From 3109d1f9659ffad76f3cf2c547cc425ed34ae96c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Jan 2019 20:18:02 +0100 Subject: tls: code shrink function old new delta lm_add 82 78 -4 curve25519 793 786 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-11) Total: -11 bytes Signed-off-by: Denys Vlasenko --- networking/tls_fe.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/networking/tls_fe.c b/networking/tls_fe.c index f235082f5..10971bbff 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c @@ -43,17 +43,13 @@ typedef uint32_t word32; #if 0 //UNUSED static void fprime_copy(byte *x, const byte *a) { - int i; - for (i = 0; i < F25519_SIZE; i++) - x[i] = a[i]; + memcpy(x, a, F25519_SIZE); } #endif static void lm_copy(byte* x, const byte* a) { - int i; - for (i = 0; i < F25519_SIZE; i++) - x[i] = a[i]; + memcpy(x, a, F25519_SIZE); } #if 0 //UNUSED @@ -200,7 +196,7 @@ static void fe_load(byte *x, word32 c) static void fe_normalize(byte *x) { byte minusp[F25519_SIZE]; - word16 c; + unsigned c; int i; /* Reduce using 2^255 = 19 mod p */ @@ -219,13 +215,13 @@ static void fe_normalize(byte *x) */ c = 19; - for (i = 0; i + 1 < F25519_SIZE; i++) { + for (i = 0; i < F25519_SIZE - 1; i++) { c += x[i]; minusp[i] = (byte)c; c >>= 8; } - c += ((word16)x[i]) - 128; + c += ((unsigned)x[i]) - 128; minusp[31] = (byte)c; /* Load x-p if no underflow */ @@ -234,13 +230,13 @@ static void fe_normalize(byte *x) static void lm_add(byte* r, const byte* a, const byte* b) { - word16 c = 0; + unsigned c = 0; int i; /* Add */ for (i = 0; i < F25519_SIZE; i++) { c >>= 8; - c += ((word16)a[i]) + ((word16)b[i]); + c += ((unsigned)a[i]) + ((unsigned)b[i]); r[i] = (byte)c; } -- cgit v1.2.3-55-g6feb From b67d900395a847e29f2afa81198f783004c80fc5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Jan 2019 11:51:58 +0100 Subject: adduser: fix a bug of getpwnam() overwriting shell name, closes 8586 Signed-off-by: Denys Vlasenko --- loginutils/adduser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loginutils/adduser.c b/loginutils/adduser.c index b2b5be5b3..850c810c4 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c @@ -198,7 +198,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) pw.pw_gecos = (char *)"Linux User,,,"; /* We assume that newly created users "inherit" root's shell setting */ - pw.pw_shell = (char *)get_shell_name(); + pw.pw_shell = xstrdup(get_shell_name()); /* might come from getpwnam(), need to make a copy */ pw.pw_dir = NULL; opts = getopt32long(argv, "^" -- cgit v1.2.3-55-g6feb From 088fec36fedff2cd50437c95b7fb430abf8d303c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Jan 2019 14:45:18 +0100 Subject: start-stop-daemon: create pidfile before parent exits, closes 8596 This removes DAEMON_DOUBLE_FORK flag from bb_daemonize_or_rexec(), as SSD was the only user. Also includes fix for -S: now works without -a and -x, does not print pids (compat with "start-stop-daemon (OpenRC) 0.34.11 (Gentoo Linux)"). function old new delta start_stop_daemon_main 1018 1084 +66 add_interface 99 103 +4 fail_hunk 139 136 -3 bb_daemonize_or_rexec 205 183 -22 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/2 up/down: 70/-25) Total: 45 bytes Signed-off-by: Denys Vlasenko --- debianutils/start_stop_daemon.c | 66 ++++++++++++++++++++++++++------------- include/libbb.h | 10 +++--- libbb/vfork_daemon_rexec.c | 16 +++++----- testsuite/start-stop-daemon.tests | 5 +++ 4 files changed, 62 insertions(+), 35 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 43b6fca26..fa08f48cf 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -409,7 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; char *signame; - char *startas; + char *startas = NULL; char *chuid; #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY // char *retry_arg = NULL; @@ -425,10 +425,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* -K or -S is required; they are mutually exclusive */ /* -p is required if -m is given */ /* -xpun (at least one) is required if -K is given */ - /* -xa (at least one) is required if -S is given */ +// /* -xa (at least one) is required if -S is given */ +//WRONG: "start-stop-daemon -S -- sleep 5" is a valid invocation /* -q turns off -v */ "\0" - "K:S:K--S:S--K:m?p:K?xpun:S?xa" + "K:S:K--S:S--K:m?p:K?xpun" IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile @@ -442,21 +443,34 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) if (signal_nr < 0) bb_show_usage(); } - if (!(opt & OPT_a)) - startas = execname; - if (!execname) /* in case -a is given and -x is not */ + //argc -= optind; + argv += optind; +// ARGS contains zeroth arg if -x/-a is not given, else it starts with 1st arg. +// These will try to execute "[/bin/]sleep 5": +// "start-stop-daemon -S -- sleep 5" +// "start-stop-daemon -S -x /bin/sleep -- 5" +// "start-stop-daemon -S -a sleep -- 5" +// NB: -n option does _not_ behave in this way: this will try to execute "5": +// "start-stop-daemon -S -n sleep -- 5" + if (!execname) { /* -x is not given */ execname = startas; - if (execname) { - G.execname_sizeof = strlen(execname) + 1; - G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); + if (!execname) { /* neither -x nor -a is given */ + execname = argv[0]; + if (!execname) + bb_show_usage(); + argv++; + } } + if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */ + startas = execname; + *--argv = startas; + G.execname_sizeof = strlen(execname) + 1; + G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); // IF_FEATURE_START_STOP_DAEMON_FANCY( // if (retry_arg) // retries = xatoi_positive(retry_arg); // ) - //argc -= optind; - argv += optind; if (userspec) { user_id = bb_strtou(userspec, NULL, 10); @@ -473,7 +487,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) if (G.found_procs) { if (!QUIET) - printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); + printf("%s is already running\n", execname); return !(opt & OPT_OKNODO); } @@ -482,30 +496,37 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) xstat(execname, &G.execstat); #endif - *--argv = startas; if (opt & OPT_BACKGROUND) { -#if BB_MMU - bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); - /* DAEMON_DEVNULL_STDIO is superfluous - - * it's always done by bb_daemonize() */ -#else /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do * without: SSD is not itself a daemon, it _execs_ a daemon. * The usual NOMMU problem of "child can't run indefinitely, * it must exec" does not bite us: we exec anyway. + * + * bb_daemonize(DAEMON_DEVNULL_STDIO | DAEMON_CLOSE_EXTRA_FDS | DAEMON_DOUBLE_FORK) + * can be used on MMU systems, but use of vfork() + * is preferable since we want to create pidfile + * _before_ parent returns, and vfork() on Linux + * ensures that (by blocking parent until exec in the child). */ pid_t pid = xvfork(); if (pid != 0) { - /* parent */ + /* Parent */ /* why _exit? the child may have changed the stack, - * so "return 0" may do bad things */ + * so "return 0" may do bad things + */ _exit(EXIT_SUCCESS); } /* Child */ setsid(); /* detach from controlling tty */ /* Redirect stdio to /dev/null, close extra FDs */ bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); -#endif + /* On Linux, session leader can acquire ctty + * unknowingly, by opening a tty. + * Prevent this: stop being a session leader. + */ + pid = xvfork(); + if (pid != 0) + _exit(EXIT_SUCCESS); /* Parent */ } if (opt & OPT_MAKEPID) { /* User wants _us_ to make the pidfile */ @@ -534,6 +555,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) } } #endif - execvp(startas, argv); +//bb_error_msg("HERE %d '%s'%s'", __LINE__, argv[0], argv[1]); + execvp(argv[0], argv); bb_perror_msg_and_die("can't execute '%s'", startas); } diff --git a/include/libbb.h b/include/libbb.h index d2563999a..3366df30f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1201,11 +1201,11 @@ void set_task_comm(const char *comm) FAST_FUNC; * to /dev/null if they are not. */ enum { - DAEMON_CHDIR_ROOT = 1, - DAEMON_DEVNULL_STDIO = 2, - DAEMON_CLOSE_EXTRA_FDS = 4, - DAEMON_ONLY_SANITIZE = 8, /* internal use */ - DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ + DAEMON_CHDIR_ROOT = 1 << 0, + DAEMON_DEVNULL_STDIO = 1 << 1, + DAEMON_CLOSE_EXTRA_FDS = 1 << 2, + DAEMON_ONLY_SANITIZE = 1 << 3, /* internal use */ + //DAEMON_DOUBLE_FORK = 1 << 4, /* double fork to avoid controlling tty */ }; #if BB_MMU enum { re_execed = 0 }; diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index c0bea0ed2..1aac27b36 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -292,14 +292,14 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); - if (flags & DAEMON_DOUBLE_FORK) { - /* On Linux, session leader can acquire ctty - * unknowingly, by opening a tty. - * Prevent this: stop being a session leader. - */ - if (fork_or_rexec(argv)) - _exit(EXIT_SUCCESS); /* parent */ - } +// if (flags & DAEMON_DOUBLE_FORK) { +// /* On Linux, session leader can acquire ctty +// * unknowingly, by opening a tty. +// * Prevent this: stop being a session leader. +// */ +// if (fork_or_rexec(argv)) +// _exit(EXIT_SUCCESS); /* parent */ +// } } while (fd > 2) { close(fd--); diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index d07aeef0e..be1c1a856 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests @@ -16,4 +16,9 @@ testing "start-stop-daemon -a without -x" \ "1\n" \ "" "" +testing "start-stop-daemon without -x and -a" \ + 'start-stop-daemon -S false 2>&1; echo $?' \ + "1\n" \ + "" "" + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 77524a311a510c9cc1bf6449d77b40d0f41a4a40 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Jan 2019 15:00:49 +0100 Subject: start-stop-daemon: fix "both -x and -a" case: -a does override argv[0] Signed-off-by: Denys Vlasenko --- debianutils/start_stop_daemon.c | 7 +++++-- testsuite/start-stop-daemon.tests | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index fa08f48cf..3a4c1044a 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -555,7 +555,10 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) } } #endif -//bb_error_msg("HERE %d '%s'%s'", __LINE__, argv[0], argv[1]); - execvp(argv[0], argv); + /* Try: + * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000 + * should exec "/bin/usleep", but argv[0] should be "qwerty": + */ + execvp(execname, argv); bb_perror_msg_and_die("can't execute '%s'", startas); } diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index be1c1a856..2ddb7fefb 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests @@ -21,4 +21,11 @@ testing "start-stop-daemon without -x and -a" \ "1\n" \ "" "" +# Unfortunately, this does not actually check argv[0] correctness, +# but at least it checks that pathname to exec() is correct +testing "start-stop-daemon with both -x and -a" \ + 'start-stop-daemon -S -x /bin/false -a qwerty false 2>&1; echo $?' \ + "1\n" \ + "" "" + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From edb74f40191458f3ae581e3ad385832906f7a39e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Jan 2019 13:19:01 +0100 Subject: Update examples/udhcp/udhcpd.conf Signed-off-by: Denys Vlasenko --- examples/udhcp/udhcpd.conf | 78 +++++++++++++++++++++++++--------------------- networking/udhcp/common.h | 4 +-- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index 90714bcdf..bb8774e08 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf @@ -74,43 +74,49 @@ option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" option 14 "dumpfile" -# Currently supported options (for more info, see options.c): -#opt lease NUM -#opt subnet IP -#opt broadcast IP -#opt router IP_LIST -#opt ipttl NUM -#opt mtu NUM -#opt hostname STRING # client's hostname -#opt domain STRING # client's domain suffix -#opt search STRING_LIST # search domains -#opt nisdomain STRING -#opt timezone NUM # (localtime - UTC_time) in seconds. signed -#opt tftp STRING # tftp server name -#opt bootfile STRING # tftp file to download (e.g. kernel image) -#opt bootsize NUM # size of that file -#opt rootpath STRING # (NFS) path to mount as root fs -#opt wpad STRING -#opt serverid IP # default: server's IP -#opt message STRING # error message (udhcpd sends it on success too) -#opt vlanid NUM # 802.1P VLAN ID -#opt vlanpriority NUM # 802.1Q VLAN priority +# Currently supported options [hex option value] (for more info, see options.c): +#opt lease NUM # [0x33] +#opt subnet IP # [0x01] +#opt broadcast IP # [0x1c] +#opt router IP_LIST # [0x03] +#opt ipttl NUM # [0x17] +#opt mtu NUM # [0x1a] +#opt hostname STRING # [0x0c] client's hostname +#opt domain STRING # [0x0f] client's domain suffix +#opt search STRING_LIST # [0x77] search domains +#opt nisdomain STRING # [0x28] +#opt timezone NUM # [0x02] (localtime - UTC_time) in seconds. signed +#opt tftp STRING # [0x42] tftp server name +#opt bootfile STRING # [0x43] tftp file to download (e.g. kernel image) +#opt bootsize NUM # [0x0d] size of that file +#opt rootpath STRING # [0x11] (NFS) path to mount as root fs +#opt wpad STRING # [0xfc] Web Proxy Auto Discovery Protocol +#opt serverid IP # [0x36] default: server's IP +#opt message STRING # [0x38] error message (udhcpd sends it on success too) +#opt vlanid NUM # [0x84] 802.1P VLAN ID +#opt vlanpriority NUM # [0x85] 802.1Q VLAN priority +# RFC 5071: PXELINUX Options +#opt 0xd0 F100747E # [0xd0] magic +#opt pxeconffile STRING # [0xd1] +#opt pxepathprefix STRING # [0xd2] +#opt reboottime NUM # [0xd3] bootstrap timeout # Options specifying server(s) -#opt dns IP_LIST -#opt wins IP_LIST -#opt nissrv IP_LIST -#opt ntpsrv IP_LIST -#opt lprsrv IP_LIST -#opt swapsrv IP +#opt dns IP_LIST # [0x06] +#opt wins IP_LIST # [0x2c] +#opt nissrv IP_LIST # [0x29] +#opt ntpsrv IP_LIST # [0x2a] +#opt lprsrv IP_LIST # [0x09] +#opt swapsrv IP # [0x10] # Options specifying routes -#opt routes IP_PAIR_LIST -#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option -#opt msstaticroutes STATIC_ROUTES # same, using MS option number +#opt routes IP_PAIR_LIST # [0x21] +#opt staticroutes STATIC_ROUTES # [0x79] RFC 3442 classless static route option +#opt msstaticroutes STATIC_ROUTES # [0xf9] same, using MS option number # Obsolete options, no longer supported -#opt logsrv IP_LIST # 704/UDP log server (not syslog!) -#opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) -#opt cookiesrv IP_LIST # RFC 865 "quote of the day" server, rarely (never?) used -#opt timesrv IP_LIST # RFC 868 time server, rarely (never?) used +#opt logsrv IP_LIST # [0x07] 704/UDP log server (not syslog!) +#opt namesrv IP_LIST # [0x05] IEN 116 name server, obsolete (August 1979!!!) +#opt cookiesrv IP_LIST # [0x08] RFC 865 "quote of the day" server, rarely (never?) used +#opt timesrv IP_LIST # [0x04] RFC 868 time server, rarely (never?) used # TODO: in development -#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc -#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs +#opt userclass STRING # [0x4d] RFC 3004. set of LASCII strings. "I am a printer" etc +#opt sipsrv STRING LIST # [0x78] RFC 3361. flag byte, then: 0: domain names, 1: IP addrs +#opt ip6rd .... # [0xd4] IPv6 rapid deployment diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 62f9a2a4a..b68f9394e 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -154,8 +154,8 @@ enum { //#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */ //#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */ //#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */ -//#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration File */ -//#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Configuration File */ +//#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration file */ +//#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Path prefix */ //#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */ //#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */ //#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */ -- cgit v1.2.3-55-g6feb From 94e748d0276a089ca9093767d15b5d050e0218b1 Mon Sep 17 00:00:00 2001 From: Martin Lewis Date: Thu, 10 Jan 2019 13:59:30 +0100 Subject: wget: don't notify on download begin and end if quiet When printing notification on download start and end, mistakenly, it didn't respect the quiet option function old new delta retrieve_file_data 561 579 +18 wget_main 2432 2437 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 23/0) Total: 23 bytes Signed-off-by: Martin Lewis Signed-off-by: Denys Vlasenko --- networking/wget.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 3a02de6ca..735746e38 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -876,10 +876,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp) polldata.fd = fileno(dfp); polldata.events = POLLIN | POLLPRI; #endif - if (G.output_fd == 1) - fprintf(stderr, "writing to stdout\n"); - else - fprintf(stderr, "saving to '%s'\n", G.fname_out); + if (!(option_mask32 & WGET_OPT_QUIET)) { + if (G.output_fd == 1) + fprintf(stderr, "writing to stdout\n"); + else + fprintf(stderr, "saving to '%s'\n", G.fname_out); + } progress_meter(PROGRESS_START); if (G.chunked) @@ -1025,10 +1027,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp) G.chunked = 0; /* makes it show 100% even for chunked download */ G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ progress_meter(PROGRESS_END); - if (G.output_fd == 1) - fprintf(stderr, "written to stdout\n"); - else - fprintf(stderr, "'%s' saved\n", G.fname_out); + if (!(option_mask32 & WGET_OPT_QUIET)) { + if (G.output_fd == 1) + fprintf(stderr, "written to stdout\n"); + else + fprintf(stderr, "'%s' saved\n", G.fname_out); + } } static void download_one_url(const char *url) @@ -1389,7 +1393,8 @@ However, in real world it was observed that some web servers G.output_fd = -1; } } else { - fprintf(stderr, "remote file exists\n"); + if (!(option_mask32 & WGET_OPT_QUIET)) + fprintf(stderr, "remote file exists\n"); } if (dfp != sfp) { -- cgit v1.2.3-55-g6feb From fe7ae562e5d0121d1c5f4d3ba1ec4117c7bbaab8 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Thu, 17 Jan 2019 21:53:53 +0100 Subject: checkstack.pl: fix arch autodetection chomp trailing newlines Signed-off-by: Bernhard Reutner-Fischer --- scripts/checkstack.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 55cdd78c1..b5980a2e3 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -32,6 +32,7 @@ my (@stack, $re, $x, $xs); my $arch = shift; if ($arch eq "") { $arch = `uname -m`; + 1 while chomp $arch; } $x = "[0-9a-f]"; # hex character -- cgit v1.2.3-55-g6feb From f59739a66361367c29aa1c68600b91ff2212d5f7 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Thu, 17 Jan 2019 22:21:53 +0100 Subject: checkstack: pull from upstream merge upstream changes Signed-off-by: Bernhard Reutner-Fischer --- scripts/checkstack.pl | 107 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 32 deletions(-) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index b5980a2e3..7833554c8 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -1,10 +1,11 @@ -#!/usr/bin/perl +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 # Stolen from Linux kernel :) # Check the stack usage of functions # -# Copyright Joern Engel +# Copyright Joern Engel # Inspired by Linus Torvalds # Original idea maybe from Keith Owens # s390 port and big speedup by Arnd Bergmann @@ -14,41 +15,57 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab +# blackfin port by Alex Landau +# AArch64, PARISC ports by Kyle McMartin +# sparc port by Martin Habets +# ppc64le port by Breno Leitao # # Usage: -# objdump -d vmlinux | checkstack.pl [arch] +# objdump -d vmlinux | scripts/checkstack.pl [arch] # # TODO : Port to all architectures (one regex per arch) +use strict; + # check for arch # # $re is used for two matches: # $& (whole re) matches the complete objdump line with the stack growth # $1 (first bracket) matches the size of the stack growth # +# $dre is similar, but for dynamic stack reductions: +# $& (whole re) matches the complete objdump line with the stack growth +# $1 (first bracket) matches the dynamic amount of the stack growth +# # use anything else and feel the pain ;) -my (@stack, $re, $x, $xs); +my (@stack, $re, $dre, $x, $xs, $funcre); { my $arch = shift; if ($arch eq "") { $arch = `uname -m`; - 1 while chomp $arch; + chomp($arch); } $x = "[0-9a-f]"; # hex character $xs = "[0-9a-f ]"; # hex character or space - if ($arch eq 'arm') { + $funcre = qr/^$x* <(.*)>:$/; + if ($arch eq 'aarch64') { + #ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp, #-80]! + #a110: d11643ff sub sp, sp, #0x590 + $re = qr/^.*stp.*sp, \#-([0-9]{1,8})\]\!/o; + $dre = qr/^.*sub.*sp, sp, #(0x$x{1,8})/o; + } elsif ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) { + #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp + # or + # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp + $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o; + $dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o; } elsif ($arch eq 'blackfin') { # 52: 00 e8 03 00 LINK 0xc; $re = qr/.*LINK (0x$x{1,5});$/o; - } elsif ($arch =~ /^i[3456]86$/) { - #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp - $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; - } elsif ($arch eq 'x86_64') { - # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp - $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o; } elsif ($arch eq 'ia64') { #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; @@ -62,42 +79,43 @@ my (@stack, $re, $x, $xs); } elsif ($arch eq 'mips') { #88003254: 27bdffe0 addiu sp,sp,-32 $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch eq 'ppc') { - #c00029f4: 94 21 ff 30 stwu r1,-208(r1) - $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'ppc64') { - #XXX - $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'powerpc') { + } elsif ($arch eq 'nios2') { + #25a8: defffb04 addi sp,sp,-20 + $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'openrisc') { + # c000043c: 9c 21 fe f0 l.addi r1,r1,-272 + $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { + $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; + } elsif ($arch eq 'powerpc' || $arch =~ /^ppc(64)?(le)?$/ ) { + # powerpc : 94 21 ff 30 stwu r1,-208(r1) + # ppc64(le) : 81 ff 21 f8 stdu r1,-128(r1) $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; } elsif ($arch =~ /^s390x?$/) { # 11160: a7 fb ff 60 aghi %r15,-160 - $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o; + # or + # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) + $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) + (?:\(\%r15\))?$/ox; } elsif ($arch =~ /^sh64$/) { #XXX: we only check for the immediate case presently, # though we will want to check for the movi/sub # pair for larger users. -- PFM. #a00048e0: d4fc40f0 addi.l r15,-240,r15 $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; + } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { + # f0019d10: 9d e3 bf 90 save %sp, -112, %sp + $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; } else { - print("wrong or unknown architecture\n"); + print("wrong or unknown architecture \"$arch\"\n"); exit } } -sub bysize($) { - my ($asize, $bsize); - ($asize = $a) =~ s/.*: *(.*)$/$1/; - ($bsize = $b) =~ s/.*: *(.*)$/$1/; - $bsize <=> $asize -} - # # main() # -my $funcre = qr/^$x* <(.*)>:$/; -my $func; -my $file, $lastslash; +my ($func, $file, $lastslash); while (my $line = ) { if ($line =~ m/$funcre/) { @@ -137,6 +155,31 @@ while (my $line = ) { next if ($size < 100); push @stack, "$intro$size\n"; } + elsif (defined $dre && $line =~ m/$dre/) { + my $size = "Dynamic ($1)"; + + next if $line !~ m/^($xs*)/; + my $addr = $1; + $addr =~ s/ /0/g; + $addr = "0x$addr"; + + #bbox: was: my $intro = "$addr $func [$file]:"; + my $intro = "$func [$file]:"; + my $padlen = 56 - length($intro); + while ($padlen > 0) { + $intro .= ' '; + $padlen -= 8; + } + push @stack, "$intro$size\n"; + } +} + +sub bysize($) { + my ($asize, $bsize); + ($asize = $a) =~ s/.*: *(.*)$/$1/; + ($bsize = $b) =~ s/.*: *(.*)$/$1/; + $bsize <=> $asize } -print sort bysize @stack; +# Sort output by size (last field) +print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; -- cgit v1.2.3-55-g6feb From 774879c4e11bca1d4625c9ef1bc51e74cc3d24d0 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Fri, 18 Jan 2019 09:56:19 +0100 Subject: checkstack.pl: tweak bfin re Signed-off-by: Bernhard Reutner-Fischer --- scripts/checkstack.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 7833554c8..cf912e0fb 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -65,7 +65,7 @@ my (@stack, $re, $dre, $x, $xs, $funcre); $dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o; } elsif ($arch eq 'blackfin') { # 52: 00 e8 03 00 LINK 0xc; - $re = qr/.*LINK (0x$x{1,5});$/o; + $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o; } elsif ($arch eq 'ia64') { #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; -- cgit v1.2.3-55-g6feb From f7235cc89f21268162ede9e010dc2b7b20b53377 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Jan 2019 14:14:07 +0100 Subject: service examples: ifplugd -M to prevents frequent respawning Signed-off-by: Denys Vlasenko --- examples/var_service/ifplugd_if/run | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run index 5d1d4e355..5c662f298 100755 --- a/examples/var_service/ifplugd_if/run +++ b/examples/var_service/ifplugd_if/run @@ -16,7 +16,7 @@ exec \ env - PATH="$PATH" \ softlimit \ setuidgid root \ -ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" +ifplugd -aqlMns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" # We use -t3 to wake ifplugd up less often. # If after three tests (3*3=9 > 8) link state seen to be different, @@ -29,6 +29,7 @@ ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" # from pointlessly trying to get a lease. # -q means that stopping monitoring does not stop dhcp/zcip/etc: # presumably, admin decided to control them manually. +# -M prevents frequent respawning if device does not exist (yet?) #-a Don't up interface automatically #-p Don't run "up" script on startup -- cgit v1.2.3-55-g6feb From fc472ea18793d8000c6f4ec1cd06c28c05340879 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 18 Jan 2019 23:15:20 +0100 Subject: wget: remove empty if/endif preprocessor directive pair Signed-off-by: Denys Vlasenko --- networking/wget.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 735746e38..3f3d3a0c9 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -1465,8 +1465,6 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") G.proxy_flag = "on"; /* use proxies if env vars are set */ G.user_agent = "Wget"; /* "User-Agent" header field */ -#if ENABLE_FEATURE_WGET_LONG_OPTIONS -#endif GETOPT32(argv, "^" "cqSO:o:P:Y:U:T:+" /*ignored:*/ "t:" -- cgit v1.2.3-55-g6feb From 11cb9eeffec0e2575c8722e83de3116f81b61b4f Mon Sep 17 00:00:00 2001 From: Mark Marshall Date: Fri, 18 Jan 2019 09:10:34 +0100 Subject: capability: fix string comparison in cap_name_to_number The result of strcasecmp was being used incorrectly. This function returns 0 if the strings match. Signed-off-by: Mark Marshall Signed-off-by: Denys Vlasenko --- libbb/capability.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/capability.c b/libbb/capability.c index 6587dcbf7..d0ae78b91 100644 --- a/libbb/capability.c +++ b/libbb/capability.c @@ -67,7 +67,7 @@ unsigned FAST_FUNC cap_name_to_number(const char *cap) goto found; } for (i = 0; i < ARRAY_SIZE(capabilities); i++) { - if (strcasecmp(capabilities[i], cap) != 0) + if (strcasecmp(capabilities[i], cap) == 0) goto found; } bb_error_msg_and_die("unknown capability '%s'", cap); -- cgit v1.2.3-55-g6feb From dac15a10accc6921d1559d254ceed9fe9d092ddf Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Tue, 1 Jan 2019 13:40:58 -0800 Subject: awk: Guard pointer chasing when parsing ternary expressions. Avoids an uninit pointer deref for some malformed ternary exprs. Add a test that would crash in busybox before this fix. Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- editors/awk.c | 3 ++- testsuite/awk.tests | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/editors/awk.c b/editors/awk.c index b6d8cf203..f2b8b13eb 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -1265,7 +1265,7 @@ static node *parse_expr(uint32_t iexp) debug_printf_parse("%s(%x)\n", __func__, iexp); sn.info = PRIMASK; - sn.r.n = glptr = NULL; + sn.r.n = sn.a.n = glptr = NULL; xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; while (!((tc = next_token(xtc)) & iexp)) { @@ -1287,6 +1287,7 @@ static node *parse_expr(uint32_t iexp) || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) ) { vn = vn->a.n; + if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); } if ((t_info & OPCLSMASK) == OC_TERNARY) t_info += P(6); diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 3933fefc9..9f353fc10 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -338,6 +338,9 @@ testing "awk continue" \ testing "awk handles invalid for loop" \ "awk '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" +testing "awk handles colon not preceded by ternary" \ + "awk 'foo:bar:' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + # testing "description" "command" "result" "infile" "stdin" testing 'awk negative field access' \ 'awk 2>&1 -- '\''{ $(-1) }'\' \ -- cgit v1.2.3-55-g6feb From 08a514c097f1451678940a3178a9565b9d65a193 Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Tue, 1 Jan 2019 13:40:59 -0800 Subject: awk: Syntax error if delete isn't given an arg. Unlike exit and return, delete strictly requires an arg, and derefs a null pointer if executed without one. Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- editors/awk.c | 23 +++++++++++++++-------- testsuite/awk.tests | 7 +++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index f2b8b13eb..90edec82c 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -275,18 +275,21 @@ typedef struct tsplitter_s { | TC_STRING | TC_NUMBER | TC_UOPPOST) #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) -#define OF_RES1 0x010000 -#define OF_RES2 0x020000 -#define OF_STR1 0x040000 -#define OF_STR2 0x080000 -#define OF_NUM1 0x100000 -#define OF_CHECKED 0x200000 +#define OF_RES1 0x010000 +#define OF_RES2 0x020000 +#define OF_STR1 0x040000 +#define OF_STR2 0x080000 +#define OF_NUM1 0x100000 +#define OF_CHECKED 0x200000 +#define OF_REQUIRED 0x400000 + /* combined operator flags */ #define xx 0 #define xV OF_RES2 #define xS (OF_RES2 | OF_STR2) #define Vx OF_RES1 +#define Rx (OF_RES1 | OF_NUM1 | OF_REQUIRED) #define VV (OF_RES1 | OF_RES2) #define Nx (OF_RES1 | OF_NUM1) #define NV (OF_RES1 | OF_NUM1 | OF_RES2) @@ -425,7 +428,7 @@ static const uint32_t tokeninfo[] = { 0, 0, /* \n */ ST_IF, ST_DO, ST_FOR, OC_BREAK, - OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, + OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, OC_PRINTF, OC_NEXT, OC_NEXTFILE, OC_RETURN|Vx, OC_EXIT|Nx, ST_WHILE, @@ -593,7 +596,7 @@ static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; -static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; +static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments"; static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; @@ -1426,7 +1429,11 @@ static void chain_expr(uint32_t info) node *n; n = chain_node(info); + n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); + if ((info & OF_REQUIRED) && !n->l.n) + syntax_error(EMSG_TOO_FEW_ARGS); + if (t_tclass & TC_GRPTERM) rollback_token(); } diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 9f353fc10..03fedf771 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -336,10 +336,13 @@ testing "awk continue" \ 'BEGIN { if (1) continue; else a = 1 }' testing "awk handles invalid for loop" \ - "awk '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + "awk -e '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" testing "awk handles colon not preceded by ternary" \ - "awk 'foo:bar:' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + "awk -e foo:bar: 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + +testing "awk errors on missing delete arg" \ + "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" "" # testing "description" "command" "result" "infile" "stdin" testing 'awk negative field access' \ -- cgit v1.2.3-55-g6feb From 1c42c18e9601ee1416d61663f5a91874954c524d Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Sun, 6 Jan 2019 18:32:59 -0800 Subject: awk: Fix overly permissive func arg list parsing It allows things like 'func f(a b)' and 'func f(a,)' which GNU awk forbids. function old new delta parse_program 327 367 +40 chain_expr 40 67 +27 parse_expr 891 915 +24 EMSG_TOO_FEW_ARGS 30 18 -12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/1 up/down: 91/-12) Total: 79 bytes Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- editors/awk.c | 15 ++++++++++++++- testsuite/awk.tests | 12 ++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/editors/awk.c b/editors/awk.c index 90edec82c..d25508e5d 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -1613,12 +1613,25 @@ static void parse_program(char *p) f = newfunc(t_string); f->body.first = NULL; f->nargs = 0; - while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { + /* Match func arg list: a comma sep list of >= 0 args, and a close paren */ + while (next_token(TC_VARIABLE | TC_SEQTERM | TC_COMMA)) { + /* Either an empty arg list, or trailing comma from prev iter + * must be followed by an arg */ + if (f->nargs == 0 && t_tclass == TC_SEQTERM) + break; + + /* TC_SEQSTART/TC_COMMA must be followed by TC_VARIABLE */ + if (t_tclass != TC_VARIABLE) + syntax_error(EMSG_UNEXP_TOKEN); + v = findvar(ahash, t_string); v->x.aidx = f->nargs++; + /* Arg followed either by end of arg list or 1 comma */ if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) break; + if (t_tclass != TC_COMMA) + syntax_error(EMSG_UNEXP_TOKEN); } seq = &f->body; chain_group(); diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 03fedf771..0db6a26e4 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -280,6 +280,18 @@ testing "awk 'delete a[v--]' evaluates v-- once" \ " \ "" "" +testing "awk func arg parsing 1" \ + "awk 'func f(,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + +testing "awk func arg parsing 2" \ + "awk 'func f(a,,b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + +testing "awk func arg parsing 3" \ + "awk 'func f(a,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + +testing "awk func arg parsing 4" \ + "awk 'func f(a b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" + testing "awk handles empty ()" \ "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" -- cgit v1.2.3-55-g6feb From b7928e18b14a2bc2aa27f82b80803fdff68c328a Mon Sep 17 00:00:00 2001 From: Brian Foley Date: Wed, 2 Jan 2019 13:09:45 -0800 Subject: sed: Fix backslash parsing for 'w' command arg If there's any whitespace between w and the filename, parse_file_cmd writes to the wrong offset when trying to fix up backslashes. This can be seen in the asan build with busybox sed -e 'w 0\\' Signed-off-by: Brian Foley Signed-off-by: Denys Vlasenko --- editors/sed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/sed.c b/editors/sed.c index 1054c1302..cddb0c732 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -387,7 +387,7 @@ static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char * bb_error_msg_and_die("empty filename"); *retval = xstrndup(filecmdstr+start, idx-start+hack+1); if (hack) - (*retval)[idx] = '\\'; + (*retval)[idx-start] = '\\'; return idx; } -- cgit v1.2.3-55-g6feb From 4906faafab9760bd2d3ed1c6eb11def9efdc438c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jan 2019 13:49:28 +0100 Subject: sed: code shrink function old new delta parse_file_cmd 115 94 -21 Signed-off-by: Denys Vlasenko --- editors/sed.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index cddb0c732..bb39de149 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -371,25 +371,25 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval) { - int start = 0, idx, hack = 0; + const char *start; + const char *eol; /* Skip whitespace, then grab filename to end of line */ - while (isspace(filecmdstr[start])) - start++; - idx = start; - while (filecmdstr[idx] && filecmdstr[idx] != '\n') - idx++; - - /* If lines glued together, put backslash back. */ - if (filecmdstr[idx] == '\n') - hack = 1; - if (idx == start) + start = skip_whitespace(filecmdstr); + eol = strchrnul(start, '\n'); + if (eol == start) bb_error_msg_and_die("empty filename"); - *retval = xstrndup(filecmdstr+start, idx-start+hack+1); - if (hack) - (*retval)[idx-start] = '\\'; - return idx; + if (*eol) { + /* If lines glued together, put backslash back. */ + *retval = xstrndup(start, eol-start + 1); + (*retval)[eol-start] = '\\'; + } else { + /* eol is NUL */ + *retval = xstrdup(start); + } + + return eol - filecmdstr; } static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) -- cgit v1.2.3-55-g6feb From 9b313ddcd8c24361b2e8fb4f0f11459436be112f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jan 2019 13:53:26 +0100 Subject: wget: detect when the length of received file is less than advertised function old new delta retrieve_file_data 579 596 +17 Signed-off-by: Denys Vlasenko --- networking/wget.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 3f3d3a0c9..fa4d21afd 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -248,7 +248,7 @@ struct globals { * With 512 byte buffer, it was measured to be * an order of magnitude slower than with big one. */ - char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(sizeof(long)); + char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(16); } FIX_ALIASING; #define G (*ptr_to_globals) #define INIT_G() do { \ @@ -388,9 +388,6 @@ static void set_alarm(void) * is_ip_address() attempts to verify whether or not a string * contains an IPv4 or IPv6 address (vs. an FQDN). The result * of inet_pton() can be used to determine this. - * - * TODO add proper error checking when inet_pton() returns -1 - * (some form of system error has occurred, and errno is set) */ static int is_ip_address(const char *string) { @@ -1012,6 +1009,15 @@ static void NOINLINE retrieve_file_data(FILE *dfp) */ } + /* Draw full bar and free its resources */ + G.chunked = 0; /* makes it show 100% even for chunked download */ + G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ + progress_meter(PROGRESS_END); + if (G.content_len != 0) { + bb_perror_msg_and_die("connection closed prematurely"); + /* GNU wget says "DATE TIME (NN MB/s) - Connection closed at byte NNN. Retrying." */ + } + /* If -c failed, we restart from the beginning, * but we do not truncate file then, we do it only now, at the end. * This lets user to ^C if his 99% complete 10 GB file download @@ -1023,10 +1029,6 @@ static void NOINLINE retrieve_file_data(FILE *dfp) ftruncate(G.output_fd, pos); } - /* Draw full bar and free its resources */ - G.chunked = 0; /* makes it show 100% even for chunked download */ - G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ - progress_meter(PROGRESS_END); if (!(option_mask32 & WGET_OPT_QUIET)) { if (G.output_fd == 1) fprintf(stderr, "written to stdout\n"); -- cgit v1.2.3-55-g6feb From f50faf84081caa3ce325d2ec69f9dda2520174d9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Jan 2019 10:07:50 +0100 Subject: ip link: fix mismatched enums in vlan_parse_opt(), closes 11631 Signed-off-by: Denys Vlasenko --- networking/libiproute/iplink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 9c164a71d..883a1f14a 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -490,11 +490,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) ; enum { ARG_id = 0, + ARG_protocol, ARG_reorder_hdr, ARG_gvrp, ARG_mvrp, ARG_loose_binding, - ARG_protocol, }; enum { PROTO_8021Q = 0, -- cgit v1.2.3-55-g6feb From 414be6c1112f8fa5d444f902ca0061f631a46522 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 22 Jan 2019 11:11:15 +0100 Subject: ip link: Fix vlan proto, closes 8261 and 11638 The proto has to be passed in network byte-order. While at it allow for ip link add link eth0 name eth0.2.24 type vlan proto 802.1ad id 24 ip link del link eth0 name eth0.2.24 type vlan proto 802.1ad id 24 The del was lacking a dev_str and thus errored out. Fix by using name/dev counterpart as fallback. The proto identifier 802.1Q was not recognized, just it's lowercase variant, fix that too. function old new delta do_add_or_delete 1275 1376 +101 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 101/0) Total: 101 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iplink.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 883a1f14a..1a1064bdc 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -518,11 +518,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) id = get_u16(*argv, "id"); addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); } else if (arg == ARG_protocol) { - arg = index_in_substrings(protocols, *argv); + arg = index_in_substrings(protocols, str_tolower(*argv)); if (arg == PROTO_8021Q) - proto = ETH_P_8021Q; + proto = htons(ETH_P_8021Q); else if (arg == PROTO_8021AD) - proto = ETH_P_8021AD; + proto = htons(ETH_P_8021AD); else bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", *argv); @@ -673,13 +673,19 @@ static int do_add_or_delete(char **argv, const unsigned rtm) linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; } + /* Allow "ip link add dev" and "ip link add name" */ + if (!name_str) + name_str = dev_str; + else if (!dev_str) + dev_str = name_str; + /* else if (!strcmp(name_str, dev_str)) + name_str = dev_str; */ + if (rtm != RTM_NEWLINK) { if (!dev_str) return 1; /* Need a device to delete */ req.i.ifi_index = xll_name_to_index(dev_str); } else { - if (!name_str) - name_str = dev_str; if (link_str) { int idx = xll_name_to_index(link_str); addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); -- cgit v1.2.3-55-g6feb From db5a6daa7f6fe92cdb70e53aec2f3717b6892b2a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Jan 2019 17:00:14 +0100 Subject: login: close PAM session on errors as well, not only on success Signed-off-by: Denys Vlasenko --- loginutils/login.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/loginutils/login.c b/loginutils/login.c index 25bb5203b..4df651cc6 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -245,7 +245,9 @@ static void login_pam_end(pam_handle_t *pamh) pam_strerror(pamh, pamret), pamret); } } -#endif /* ENABLE_PAM */ +#else +# define login_pam_end(pamh) ((void)0) +#endif static void get_username_or_die(char *buf, int size_buf) { @@ -471,6 +473,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) * to know _why_ login failed */ syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret); + login_pam_end(pamh); safe_strncpy(username, "UNKNOWN", sizeof(username)); #else /* not PAM */ pw = getpwnam(username); @@ -528,8 +531,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (child_pid < 0) bb_perror_msg("vfork"); else { - if (safe_waitpid(child_pid, NULL, 0) == -1) - bb_perror_msg("waitpid"); + wait_for_exitstatus(child_pid); update_utmp_DEAD_PROCESS(child_pid); } IF_PAM(login_pam_end(pamh);) -- cgit v1.2.3-55-g6feb From 53799506acf69e7f7137d91fa5a4451211621469 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jan 2019 14:24:03 +0100 Subject: bc: implement pass-by-reference code from upstream function old new delta zxc_program_popResultAndCopyToVar 298 493 +195 bc_vec_pushIndex - 75 +75 zxc_vm_process 859 928 +69 xc_program_dereference - 66 +66 bc_vec_npush - 65 +65 zbc_num_s 239 249 +10 zxc_program_num 1024 1032 +8 zbc_num_divmod 150 156 +6 xc_program_search 143 146 +3 zxc_program_assign 392 389 -3 zdc_program_execStr 520 517 -3 xc_program_pushVar 198 195 -3 zxc_program_exec 4101 4092 -9 zbc_program_call 318 308 -10 zbc_func_insert 120 104 -16 zbc_parse_stmt_possibly_auto 1460 1439 -21 bc_vec_push 53 12 -41 xc_parse_pushIndex 61 18 -43 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 6/9 up/down: 497/-149) Total: 348 bytes Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 271 ++++++++++++++++++++++++------------ testsuite/bc_references.bc | 106 ++++++++++++++ testsuite/bc_references_results.txt | 212 ++++++++++++++++++++++++++++ 3 files changed, 503 insertions(+), 86 deletions(-) create mode 100644 testsuite/bc_references.bc create mode 100644 testsuite/bc_references_results.txt diff --git a/miscutils/bc.c b/miscutils/bc.c index 7fecb264d..36e978ed8 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -4,8 +4,8 @@ * Adapted from https://github.com/gavinhoward/bc * Original code copyright (c) 2018 Gavin D. Howard and contributors. */ -//TODO: GNU extensions: -// support "define f(*param[])" - "pass array by reference" syntax +//TODO: +// maybe implement a^b for non-integer b? #define DEBUG_LEXER 0 #define DEBUG_COMPILE 0 @@ -380,6 +380,12 @@ typedef struct BcInstPtr { size_t inst_idx; } BcInstPtr; +typedef enum BcType { + BC_TYPE_VAR, + BC_TYPE_ARRAY, + BC_TYPE_REF, +} BcType; + typedef enum BcLexType { XC_LEX_EOF, XC_LEX_INVALID, @@ -1092,15 +1098,25 @@ static void bc_vec_pop_all(BcVec *v) bc_vec_npop(v, v->len); } -static size_t bc_vec_push(BcVec *v, const void *data) +static size_t bc_vec_npush(BcVec *v, size_t n, const void *data) { size_t len = v->len; - if (len >= v->cap) bc_vec_grow(v, 1); - memmove(v->v + (v->size * len), data, v->size); - v->len++; + if (len + n > v->cap) bc_vec_grow(v, n); + memmove(v->v + (v->size * len), data, v->size * n); + v->len = len + n; return len; } +static size_t bc_vec_push(BcVec *v, const void *data) +{ + return bc_vec_npush(v, 1, data); + //size_t len = v->len; + //if (len >= v->cap) bc_vec_grow(v, 1); + //memmove(v->v + (v->size * len), data, v->size); + //v->len = len + 1; + //return len; +} + // G.prog.results often needs "pop old operand, push result" idiom. // Can do this without a few extra ops static size_t bc_result_pop_and_push(const void *data) @@ -3528,14 +3544,14 @@ static void xc_parse_pushName(char *name) // (The above describes 32-bit case). #define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) -static void xc_parse_pushIndex(size_t idx) +static void bc_vec_pushIndex(BcVec *v, size_t idx) { size_t mask; unsigned amt; dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); if (idx < SMALL_INDEX_LIMIT) { - xc_parse_push(idx); + bc_vec_pushByte(v, idx); return; } @@ -3548,14 +3564,19 @@ static void xc_parse_pushIndex(size_t idx) } // amt is at least 1 here - "one byte of length data follows" - xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt); + bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt); do { - xc_parse_push((unsigned char)idx); + bc_vec_pushByte(v, (unsigned char)idx); idx >>= 8; } while (idx != 0); } +static void xc_parse_pushIndex(size_t idx) +{ + bc_vec_pushIndex(&G.prs.func->code, idx); +} + static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) { xc_parse_push(inst); @@ -4340,7 +4361,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcLexType type) } #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) -static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) +static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type) { BcId *autoid; BcId a; @@ -4349,13 +4370,13 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) autoid = (void*)f->autos.v; for (i = 0; i < f->autos.len; i++, autoid++) { if (strcmp(name, autoid->name) == 0 - && var == autoid->idx + && type == (BcType) autoid->idx ) { RETURN_STATUS(bc_error("duplicate function parameter or auto name")); } } - a.idx = var; + a.idx = type; a.name = name; bc_vec_push(&f->autos, &a); @@ -4368,7 +4389,7 @@ static BC_STATUS zbc_parse_funcdef(void) { BcParse *p = &G.prs; BcStatus s; - bool var, comma, voidfunc; + bool comma, voidfunc; char *name; dbg_lex_enter("%s:%d entered", __func__, __LINE__); @@ -4406,6 +4427,16 @@ static BC_STATUS zbc_parse_funcdef(void) comma = false; while (p->lex != BC_LEX_RPAREN) { + BcType t = BC_TYPE_VAR; + + if (p->lex == XC_LEX_OP_MULTIPLY) { + t = BC_TYPE_REF; + s = zxc_lex_next(); + if (s) RETURN_STATUS(s); + s = zbc_POSIX_does_not_allow("references"); + if (s) RETURN_STATUS(s); + } + if (p->lex != XC_LEX_NAME) RETURN_STATUS(bc_error_bad_function_definition()); @@ -4415,9 +4446,8 @@ static BC_STATUS zbc_parse_funcdef(void) s = zxc_lex_next(); if (s) goto err; - var = p->lex != BC_LEX_LBRACKET; - - if (!var) { + if (p->lex == BC_LEX_LBRACKET) { + if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY; s = zxc_lex_next(); if (s) goto err; @@ -4429,6 +4459,10 @@ static BC_STATUS zbc_parse_funcdef(void) s = zxc_lex_next(); if (s) goto err; } + else if (t == BC_TYPE_REF) { + s = bc_error_at("vars can't be references"); + goto err; + } comma = p->lex == BC_LEX_COMMA; if (comma) { @@ -4436,7 +4470,7 @@ static BC_STATUS zbc_parse_funcdef(void) if (s) goto err; } - s = zbc_func_insert(p->func, name, var); + s = zbc_func_insert(p->func, name, t); if (s) goto err; } @@ -4488,7 +4522,7 @@ static BC_STATUS zbc_parse_auto(void) if (s) RETURN_STATUS(s); for (;;) { - bool var; + BcType t; if (p->lex != XC_LEX_NAME) RETURN_STATUS(bc_error_at("bad 'auto' syntax")); @@ -4497,8 +4531,9 @@ static BC_STATUS zbc_parse_auto(void) s = zxc_lex_next(); if (s) goto err; - var = (p->lex != BC_LEX_LBRACKET); - if (!var) { + t = BC_TYPE_VAR; + if (p->lex == BC_LEX_LBRACKET) { + t = BC_TYPE_ARRAY; s = zxc_lex_next(); if (s) goto err; @@ -4510,7 +4545,7 @@ static BC_STATUS zbc_parse_auto(void) if (s) goto err; } - s = zbc_func_insert(p->func, name, var); + s = zbc_func_insert(p->func, name, t); if (s) goto err; if (p->lex == XC_LEX_NLINE @@ -5119,12 +5154,64 @@ static BC_STATUS zdc_parse_exprs_until_eof(void) #define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) -static BcVec* xc_program_search(char *id, bool var) +static size_t xc_program_index(char *code, size_t *bgn) +{ + unsigned char *bytes = (void*)(code + *bgn); + unsigned amt; + unsigned i; + size_t res; + + amt = *bytes++; + if (amt < SMALL_INDEX_LIMIT) { + *bgn += 1; + return amt; + } + amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here + *bgn += amt + 1; + + res = 0; + i = 0; + do { + res |= (size_t)(*bytes++) << i; + i += 8; + } while (--amt != 0); + + return res; +} + +static char *xc_program_name(char *code, size_t *bgn) +{ + code += *bgn; + *bgn += strlen(code) + 1; + + return xstrdup(code); +} + +static BcVec* xc_program_dereference(BcVec *vec) +{ + BcVec *v; + size_t vidx, nidx, i = 0; + + //assert(vec->size == sizeof(uint8_t)); + + vidx = xc_program_index(vec->v, &i); + nidx = xc_program_index(vec->v, &i); + + v = bc_vec_item(&G.prog.arrs, vidx); + v = bc_vec_item(v, nidx); + + //assert(v->size != sizeof(uint8_t)); + + return v; +} + +static BcVec* xc_program_search(char *id, BcType type) { BcId e, *ptr; BcVec *v, *map; size_t i; int new; + bool var = (type == BC_TYPE_VAR); v = var ? &G.prog.vars : &G.prog.arrs; map = var ? &G.prog.var_map : &G.prog.arr_map; @@ -5178,17 +5265,20 @@ static BC_STATUS zxc_program_num(BcResult *r, BcNum **num) case XC_RESULT_VAR: case XC_RESULT_ARRAY: case XC_RESULT_ARRAY_ELEM: { - BcVec *v; - void *p; - v = xc_program_search(r->d.id.name, r->t == XC_RESULT_VAR); -// dc variables are all stacks, so here we have this: - p = bc_vec_top(v); -// TODO: eliminate these stacks for bc-only config? + BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; + BcVec *v = xc_program_search(r->d.id.name, type); + void *p = bc_vec_top(v); + if (r->t == XC_RESULT_ARRAY_ELEM) { + size_t idx = r->d.id.idx; + v = p; - if (v->len <= r->d.id.idx) - bc_array_expand(v, r->d.id.idx + 1); - *num = bc_vec_item(v, r->d.id.idx); + if (v->size == sizeof(uint8_t)) + v = xc_program_dereference(v); + //assert(v->size == sizeof(BcNum)); + if (v->len <= idx) + bc_array_expand(v, idx + 1); + *num = bc_vec_item(v, idx); } else { *num = p; } @@ -5347,39 +5437,6 @@ static BC_STATUS zxc_program_read(void) } #define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) -static size_t xc_program_index(char *code, size_t *bgn) -{ - unsigned char *bytes = (void*)(code + *bgn); - unsigned amt; - unsigned i; - size_t res; - - amt = *bytes++; - if (amt < SMALL_INDEX_LIMIT) { - *bgn += 1; - return amt; - } - amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here - *bgn += amt + 1; - - res = 0; - i = 0; - do { - res |= (size_t)(*bytes++) << i; - i += 8; - } while (--amt != 0); - - return res; -} - -static char *xc_program_name(char *code, size_t *bgn) -{ - code += *bgn; - *bgn += strlen(code) + 1; - - return xstrdup(code); -} - static void xc_program_printString(const char *str) { #if ENABLE_DC @@ -5755,43 +5812,81 @@ static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push) #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) #endif // ENABLE_DC -static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, bool var) +static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t) { BcStatus s; BcResult *ptr, r; - BcVec *v; + BcVec *vec; BcNum *n; + bool var = (t == BC_TYPE_VAR); if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) RETURN_STATUS(bc_error_stack_has_too_few_elements()); ptr = bc_vec_top(&G.prog.results); - if ((ptr->t == XC_RESULT_ARRAY) != !var) + if ((ptr->t == XC_RESULT_ARRAY) == var) RETURN_STATUS(bc_error_variable_is_wrong_type()); - v = xc_program_search(name, var); + vec = xc_program_search(name, t); #if ENABLE_DC - if (ptr->t == XC_RESULT_STR && !var) - RETURN_STATUS(bc_error_variable_is_wrong_type()); - if (ptr->t == XC_RESULT_STR) - RETURN_STATUS(zdc_program_assignStr(ptr, v, true)); + if (ptr->t == XC_RESULT_STR) { + if (!var) + RETURN_STATUS(bc_error_variable_is_wrong_type()); + RETURN_STATUS(zdc_program_assignStr(ptr, vec, true)); + } #endif s = zxc_program_num(ptr, &n); if (s) RETURN_STATUS(s); // Do this once more to make sure that pointers were not invalidated. - v = xc_program_search(name, var); + vec = xc_program_search(name, t); if (var) { bc_num_init_DEF_SIZE(&r.d.n); bc_num_copy(&r.d.n, n); } else { + BcVec *v = (BcVec*) n; + bool ref, ref_size; + + ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY); + ref_size = (v->size == sizeof(uint8_t)); + + if (ref || (ref_size && t == BC_TYPE_REF)) { + bc_vec_init(&r.d.v, sizeof(uint8_t), NULL); + if (ref) { + size_t vidx, idx; + BcId id; + + id.name = ptr->d.id.name; + v = xc_program_search(ptr->d.id.name, BC_TYPE_REF); + + // Make sure the pointer was not invalidated. + vec = xc_program_search(name, t); + + vidx = bc_map_find_exact(&G.prog.arr_map, &id); + //assert(vidx != BC_VEC_INVALID_IDX); + vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx; + idx = v->len - 1; + + bc_vec_pushIndex(&r.d.v, vidx); + bc_vec_pushIndex(&r.d.v, idx); + } + // If we get here, we are copying a ref to a ref. + else bc_vec_npush(&r.d.v, v->len, v->v); + + // We need to return early. + goto ret; + } + + if (ref_size && t != BC_TYPE_REF) + v = xc_program_dereference(v); + bc_array_init(&r.d.v, true); - bc_array_copy(&r.d.v, (BcVec *) n); + bc_array_copy(&r.d.v, v); } - - bc_vec_push(v, &r.d); + ret: + bc_vec_push(vec, &r.d); bc_vec_pop(&G.prog.results); RETURN_STATUS(s); @@ -5818,7 +5913,7 @@ static BC_STATUS zxc_program_assign(char inst) if (left->t != XC_RESULT_VAR) RETURN_STATUS(bc_error_variable_is_wrong_type()); - v = xc_program_search(left->d.id.name, true); + v = xc_program_search(left->d.id.name, BC_TYPE_VAR); RETURN_STATUS(zdc_program_assignStr(right, v, false)); } @@ -5897,7 +5992,7 @@ static BC_STATUS xc_program_pushVar(char *code, size_t *bgn, #if ENABLE_DC if (pop || copy) { - BcVec *v = xc_program_search(name, true); + BcVec *v = xc_program_search(name, BC_TYPE_VAR); BcNum *num = bc_vec_top(v); free(name); @@ -6014,16 +6109,19 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) for (i = 0; i < nparams; ++i) { BcResult *arg; BcStatus s; + bool arr; a = bc_vec_item(&func->autos, nparams - 1 - i); arg = bc_vec_top(&G.prog.results); - if ((!a->idx) != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch + arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF); + + if (arr != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) ) { RETURN_STATUS(bc_error_variable_is_wrong_type()); } - s = zxc_program_popResultAndCopyToVar(a->name, a->idx); + s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx); if (s) RETURN_STATUS(s); } @@ -6031,12 +6129,13 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) for (; i < func->autos.len; i++, a++) { BcVec *v; - v = xc_program_search(a->name, a->idx); - if (a->idx) { + v = xc_program_search(a->name, (BcType) a->idx); + if (a->idx == BC_TYPE_VAR) { BcNum n2; bc_num_init_DEF_SIZE(&n2); bc_vec_push(v, &n2); } else { + //assert(a->idx == BC_TYPE_ARRAY); BcVec v2; bc_array_init(&v2, true); bc_vec_push(v, &v2); @@ -6087,7 +6186,7 @@ static BC_STATUS zbc_program_return(char inst) a = (void*)f->autos.v; for (i = 0; i < f->autos.len; i++, a++) { BcVec *v; - v = xc_program_search(a->name, a->idx); + v = xc_program_search(a->name, (BcType) a->idx); bc_vec_pop(v); } @@ -6399,7 +6498,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) if (exec) { BcVec *v; - v = xc_program_search(name, true); + v = xc_program_search(name, BC_TYPE_VAR); n = bc_vec_top(v); } @@ -6724,7 +6823,7 @@ static BC_STATUS zxc_program_exec(void) } case DC_INST_PUSH_TO_VAR: { char *name = xc_program_name(code, &ip->inst_idx); - s = zxc_program_popResultAndCopyToVar(name, true); + s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR); free(name); break; } diff --git a/testsuite/bc_references.bc b/testsuite/bc_references.bc new file mode 100644 index 000000000..fc48c1a56 --- /dev/null +++ b/testsuite/bc_references.bc @@ -0,0 +1,106 @@ +define printarray(a[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a[i] + } +} + +define a2(a[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a[i] = a[i] * a[i] + } + + printarray(a[], len) +} + +define a4(a__[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a__[i] = a__[i] * a__[i] + } + + printarray(a__[], len) +} + +define a6(*a__[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a__[i] = a__[i] * a__[i] + } + + printarray(a__[], len) +} + +define a1(*a[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a[i] = i + } + + a2(a[], len) + + printarray(a[], len) +} + +define a3(*a__[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a__[i] = i + } + + a4(a__[], len) + + printarray(a__[], len) +} + +define a5(*a__[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a__[i] = i + } + + a2(a__[], len) + + printarray(a__[], len) +} + +define a7(*a__[], len) { + + auto i + + for (i = 0; i < len; ++i) { + a__[i] = i + } + + a6(a__[], len) + + printarray(a__[], len) +} + +len = 16 + +a1(a[], len) +printarray(a[], len) +a3(a[], len) +printarray(a[], len) +a5(a[], len) +printarray(a[], len) +a7(a[], len) +printarray(a[], len) + +halt diff --git a/testsuite/bc_references_results.txt b/testsuite/bc_references_results.txt new file mode 100644 index 000000000..564b54a3a --- /dev/null +++ b/testsuite/bc_references_results.txt @@ -0,0 +1,212 @@ +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +0 +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 +0 +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 +0 +0 +1 +4 +9 +16 +25 +36 +49 +64 +81 +100 +121 +144 +169 +196 +225 +0 -- cgit v1.2.3-55-g6feb From 9a9c6e39ba4c8f4f2cecb147c7e6464bec2d8b55 Mon Sep 17 00:00:00 2001 From: Ari Sundholm Date: Tue, 29 Jan 2019 14:42:57 +0100 Subject: grep: fix -x -v with certain pattern orders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We found out that busybox -x -v is a bit broken: ari@ari-thinkpad:~/busybox$ echo ' aa bb cc' | ./busybox grep -x -e 'aa.*' -e '.*bb.*' aa bb cc ari@ari-thinkpad:~/busybox$ echo ' aa bb cc' | ./busybox grep -x -v -e 'aa.*' -e '.*bb.*' ari@ari-thinkpad:~/busybox$ echo ' aa bb cc' | ./busybox grep -x -e '.*aa.*' -e 'bb.*' aa bb cc ari@ari-thinkpad:~/busybox$ echo ' aa bb cc' | ./busybox grep -x -v -e '.*aa.*' -e 'bb.*' aa bb cc Last one is wrong. This patch fixes the issue by making sure that the variable 'found' never makes a transition from 1 to 0, as this would mean that grep previously found a match on this input line. Signed-off-by: Ari Sundholm Signed-off-by: Niko Vähäsarja Signed-off-by: Denys Vlasenko --- findutils/grep.c | 2 +- testsuite/grep.tests | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/findutils/grep.c b/findutils/grep.c index a4033a40b..9d9da422c 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -404,7 +404,7 @@ static int grep_file(FILE *file) #endif ) { if (option_mask32 & OPT_x) { - found = (gl->matched_range.rm_so == 0 + found |= (gl->matched_range.rm_so == 0 && match_at[gl->matched_range.rm_eo] == '\0'); } else if (!(option_mask32 & OPT_w)) { diff --git a/testsuite/grep.tests b/testsuite/grep.tests index e57889790..26f8e69cf 100755 --- a/testsuite/grep.tests +++ b/testsuite/grep.tests @@ -177,6 +177,13 @@ testing "grep -w word match second word" \ "bword,word\n""wordb,word\n""bwordb,word\n" \ "" + +testing "grep -x -v -e EXP1 -e EXP2 finds nothing if either EXP matches" \ + "grep -x -v -e '.*aa.*' -e 'bb.*'; echo \$?" \ + "1\n" \ + "" \ + " aa bb cc\n" + # -r on symlink to dir should recurse into dir mkdir -p grep.testdir/foo echo bar > grep.testdir/foo/file -- cgit v1.2.3-55-g6feb From d4b568c108b89fb726181b0fabb19f2d62bc1930 Mon Sep 17 00:00:00 2001 From: Ari Sundholm Date: Mon, 28 Jan 2019 19:41:12 +0200 Subject: grep: short-circuit -v to bail out on first match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A small optimization. There is no need to try matching the current input line against any further patterns if a match was already found and -v is specified. function old new delta grep_file 1463 1440 -23 Signed-off-by: Ari Sundholm Signed-off-by: Niko Vähäsarja Signed-off-by: Denys Vlasenko --- findutils/grep.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/findutils/grep.c b/findutils/grep.c index 9d9da422c..2cbe7ea91 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -443,15 +443,23 @@ static int grep_file(FILE *file) } } } - /* If it's non-inverted search, we can stop - * at first match */ - if (found && !invert_search) - goto do_found; + /* If it's a non-inverted search, we can stop + * at first match and report it. + * If it's an inverted search, we can move on + * to the next line of input, ignoring the + * rest of the patterns. + */ + if (found) { + //if (invert_search) + // goto do_not_found; + //goto do_found; + break; // this accomplishes both + } pattern_ptr = pattern_ptr->link; } /* while (pattern_ptr) */ if (found ^ invert_search) { - do_found: + //do_found: /* keep track of matches */ nmatches++; @@ -552,6 +560,7 @@ static int grep_file(FILE *file) } #if ENABLE_FEATURE_GREP_CONTEXT else { /* no match */ + //do_not_found: /* if we need to print some context lines after the last match, do so */ if (print_n_lines_after) { print_line(line, strlen(line), linenum, '-'); -- cgit v1.2.3-55-g6feb From e17e8d4b7da27f28956253104218d53328f31995 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 2 Feb 2019 19:06:19 +0100 Subject: service examples: do not respawn supplicant too often Signed-off-by: Denys Vlasenko --- examples/var_service/supplicant_if/run | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/var_service/supplicant_if/run b/examples/var_service/supplicant_if/run index 45211e001..279d18af5 100755 --- a/examples/var_service/supplicant_if/run +++ b/examples/var_service/supplicant_if/run @@ -8,7 +8,8 @@ pwd="$PWD" if="${PWD##*/dhcp_}" echo "* Upping iface $if" -ip link set dev "$if" up +# "or sleep" idiom prevents rapid respawning if iface does not exist +ip link set dev "$if" up || { sleep 5; exit; } ##echo "* Powersave disable on $if" ##iw dev "$if" set power_save off -- cgit v1.2.3-55-g6feb From 779f96a24c43209be841f9cc0e7715a2c57db487 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 4 Feb 2019 16:16:30 +0100 Subject: lineedit: fix SEGV in isk, hexedit, ed, closes 11661 fdisk, hexedit and ed calls read_line_edit in libbb/lineedit.c with NULL as first argument. On line 2373 of lineedit.c of busybox version 1.29.3, state->hist_file is referenced without checking the state->flag. This causes segmentation fault on fdisk, hexedit and ed on ARM Cortex-A9. It somehow works on x86_64. Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 0a888fa70..1d5fef5ee 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -2383,13 +2383,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman timeout = st->timeout; } #if MAX_HISTORY > 0 + if (state->flags & DO_HISTORY) { # if ENABLE_FEATURE_EDITING_SAVEHISTORY - if (state->hist_file) - if (state->cnt_history == 0) - load_history(state); + if (state->hist_file) + if (state->cnt_history == 0) + load_history(state); # endif - if (state->flags & DO_HISTORY) state->cur_history = state->cnt_history; + } #endif /* prepare before init handlers */ -- cgit v1.2.3-55-g6feb From 2feaba1d8dc2893d9f1064673e500312eaa70777 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 5 Feb 2019 17:48:24 +0100 Subject: dhcp service example: cater for servers hot giving subnet and/or router Signed-off-by: Denys Vlasenko --- examples/var_service/dhcp_if/convert2ipconf | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/examples/var_service/dhcp_if/convert2ipconf b/examples/var_service/dhcp_if/convert2ipconf index 62a288ebf..038b1f7f1 100755 --- a/examples/var_service/dhcp_if/convert2ipconf +++ b/examples/var_service/dhcp_if/convert2ipconf @@ -26,6 +26,25 @@ exec 2>&1 test "$interface" || exit 1 test "$ip" || exit 1 +# some servers do not return subnet option. +# guess it for standard private networks. +if ! test "$mask"; then + if test "$ip" != "${ip#192.168.}"; then + mask=16 + elif test "$ip" != "${ip#172.16.}"; then + mask=12 + # repeat for each in 172.17. - 172.31. range? + elif test "$ip" != "${ip#10.}"; then + mask=8 + fi +fi + +# some servers do not return router option. +# assume DHCP server is the router. +if ! test "$router"; then + test "$serverid" && router="$serverid" +fi + { echo "let cfg=cfg+1" test "$interface" && echo "if[\$cfg]='$interface'" -- cgit v1.2.3-55-g6feb From 5a387e26c2460428d4d5d9a2b2f074a31a994da1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Feb 2019 10:37:05 +0100 Subject: dhcp service example: rewrite "private network to mask" as case statement Signed-off-by: Denys Vlasenko --- examples/var_service/dhcp_if/convert2ipconf | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/var_service/dhcp_if/convert2ipconf b/examples/var_service/dhcp_if/convert2ipconf index 038b1f7f1..31e3c7fde 100755 --- a/examples/var_service/dhcp_if/convert2ipconf +++ b/examples/var_service/dhcp_if/convert2ipconf @@ -29,14 +29,19 @@ test "$ip" || exit 1 # some servers do not return subnet option. # guess it for standard private networks. if ! test "$mask"; then - if test "$ip" != "${ip#192.168.}"; then - mask=16 - elif test "$ip" != "${ip#172.16.}"; then - mask=12 - # repeat for each in 172.17. - 172.31. range? - elif test "$ip" != "${ip#10.}"; then - mask=8 - fi + case "$ip" in + 10.*) + mask=8;; + 192.168.*) + mask=16;; + #172.16-31.x.x + 172.1[6789].*) + mask=12;; + 172.2[0123456789].*) + mask=12;; + 172.3[01].*) + mask=12;; + esac fi # some servers do not return router option. -- cgit v1.2.3-55-g6feb From e6503f2f0982378cd753be152fa19f8336c357bc Mon Sep 17 00:00:00 2001 From: Rostislav Skudnov Date: Wed, 6 Feb 2019 11:57:29 +0000 Subject: chcon: Fix typo in ACTION_RECURSE Signed-off-by: Rostislav Skudnov Signed-off-by: Denys Vlasenko --- selinux/chcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selinux/chcon.c b/selinux/chcon.c index 92eb76737..5bf91710c 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c @@ -204,7 +204,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) fname[fname_len] = '\0'; if (recursive_action(fname, - ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSIVE : 0), + ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0), change_filedir_context, change_filedir_context, NULL, 0) != TRUE) -- cgit v1.2.3-55-g6feb From bb983f30e7ea69604212793f228270f21e8a5b06 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 3 Feb 2019 10:13:17 +0000 Subject: vi: fix faulty undo after autoinsert Enable autoinsert and enter the following with an indent of three spaces: line 1 line 2 Using 'u' to undo the last insert results in: line1e 2 The insertion of the indent hasn't been properly recorded. Since recording insertions is a common operation add a convenience function, undo_push_insert(), to handle this and use it to record the autoindent correctly. function old new delta undo_push_insert - 36 +36 string_insert 133 129 -4 char_insert 518 473 -45 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 36/-49) Total: -13 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 57 ++++++++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 32144abaa..c6adeb311 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -598,6 +598,7 @@ static void check_context(char); // remember context for '' command #if ENABLE_FEATURE_VI_UNDO static void flush_undo_data(void); static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack +static void undo_push_insert(char *, int, int); // convenience function static void undo_pop(void); // Undo the last operation # if ENABLE_FEATURE_VI_UNDO_QUEUE static void undo_queue_commit(void); // Flush any queued objects to the undo stack @@ -2011,19 +2012,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' c = get_one_char(); *p = c; #if ENABLE_FEATURE_VI_UNDO - switch (undo) { - case ALLOW_UNDO: - undo_push(p, 1, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, 1, UNDO_INS_CHAIN); - break; -# if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, 1, UNDO_INS_QUEUED); - break; -# endif - } + undo_push_insert(p, 1, undo); #else modified_count++; #endif /* ENABLE_FEATURE_VI_UNDO */ @@ -2051,19 +2040,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' if (c == '\n') undo_queue_commit(); # endif - switch (undo) { - case ALLOW_UNDO: - undo_push(p, 1, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, 1, UNDO_INS_CHAIN); - break; -# if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, 1, UNDO_INS_QUEUED); - break; -# endif - } + undo_push_insert(p, 1, undo); #else modified_count++; #endif /* ENABLE_FEATURE_VI_UNDO */ @@ -2083,7 +2060,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' p += bias; q += bias; #if ENABLE_FEATURE_VI_UNDO - undo_push(p, len, UNDO_INS); + undo_push_insert(p, len, undo); #endif memcpy(p, q, len); p += len; @@ -2392,6 +2369,23 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to modified_count++; } +static void undo_push_insert(char *p, int len, int undo) +{ + switch (undo) { + case ALLOW_UNDO: + undo_push(p, len, UNDO_INS); + break; + case ALLOW_UNDO_CHAIN: + undo_push(p, len, UNDO_INS_CHAIN); + break; +# if ENABLE_FEATURE_VI_UNDO_QUEUE + case ALLOW_UNDO_QUEUED: + undo_push(p, len, UNDO_INS_QUEUED); + break; +# endif + } +} + static void undo_pop(void) // Undo the last operation { int repeat; @@ -2665,14 +2659,7 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s i = strlen(s); #if ENABLE_FEATURE_VI_UNDO - switch (undo) { - case ALLOW_UNDO: - undo_push(p, i, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, i, UNDO_INS_CHAIN); - break; - } + undo_push_insert(p, i, undo); #endif bias = text_hole_make(p, i); p += bias; -- cgit v1.2.3-55-g6feb From df4e3af9f716e0483bd02fd4ab3ad973ffe5b998 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 3 Feb 2019 14:01:58 +0000 Subject: vi: fix replacement of single character with CR Currently if the 'r' command is followed by a carriage return a literal CR replaces the current character. Fix this so that: - a new line is inserted - the autoindent setting is respected - the cursor is placed at the start of the new line function old new delta do_cmd 5052 5060 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0) Total: 8 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index c6adeb311..899fcf57e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -4189,14 +4189,9 @@ static void do_cmd(int c) case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char if (*dot != '\n') { -#if ENABLE_FEATURE_VI_UNDO - undo_push(dot, 1, UNDO_DEL); - *dot = c1; - undo_push(dot, 1, UNDO_INS_CHAIN); -#else - *dot = c1; - modified_count++; -#endif + dot = text_hole_delete(dot, dot, ALLOW_UNDO); + dot = char_insert(dot, c1, ALLOW_UNDO_CHAIN); + dot_left(); } end_cmd_q(); // stop adding to q break; -- cgit v1.2.3-55-g6feb From 317498f3b3335ee9b9944929ffae16f07e1ebd2d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Feb 2019 14:02:59 +0100 Subject: sysctl: allow setting empty values function old new delta sysctl_act_on_setting 451 445 -6 Signed-off-by: Denys Vlasenko --- procps/sysctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/procps/sysctl.c b/procps/sysctl.c index 5fa7646d1..42de374d2 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -119,14 +119,16 @@ static int sysctl_act_on_setting(char *setting) if (cptr) writing = 1; if (writing) { - if (cptr == NULL) { + if (!cptr) { bb_error_msg("error: '%s' must be of the form name=value", outname); retval = EXIT_FAILURE; goto end; } value = cptr + 1; /* point to the value in name=value */ - if (setting == cptr || !*value) { + if (setting == cptr /* "name" can't be empty */ + /* || !*value - WRONG: "sysctl net.ipv4.ip_local_reserved_ports=" is a valid syntax (clears the value) */ + ) { bb_error_msg("error: malformed setting '%s'", outname); retval = EXIT_FAILURE; goto end; -- cgit v1.2.3-55-g6feb From 679c30e73eda275085676f51fc77ee18c84edf21 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Feb 2019 14:27:21 +0100 Subject: sysctl: avoid stat() on every item if in -w mode function old new delta sysctl_act_recursive 163 167 +4 Signed-off-by: Denys Vlasenko --- procps/sysctl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/procps/sysctl.c b/procps/sysctl.c index 42de374d2..2ef19c1be 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -205,19 +205,21 @@ static int sysctl_act_on_setting(char *setting) static int sysctl_act_recursive(const char *path) { - DIR *dirp; struct stat buf; - struct dirent *entry; - char *next; int retval = 0; - stat(path, &buf); - if (S_ISDIR(buf.st_mode) && !(option_mask32 & FLAG_WRITE)) { + if (!(option_mask32 & FLAG_WRITE) + && stat(path, &buf) == 0 + && S_ISDIR(buf.st_mode) + ) { + struct dirent *entry; + DIR *dirp; + dirp = opendir(path); if (dirp == NULL) return -1; while ((entry = readdir(dirp)) != NULL) { - next = concat_subpath_file(path, entry->d_name); + char *next = concat_subpath_file(path, entry->d_name); if (next == NULL) continue; /* d_name is "." or ".." */ /* if path was ".", drop "./" prefix: */ @@ -305,6 +307,8 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) return sysctl_act_recursive("."); } +//TODO: if(!argv[0]) bb_show_usage() ? + retval = 0; while (*argv) { sysctl_dots_to_slashes(*argv); -- cgit v1.2.3-55-g6feb From 1422ba6dea9160a4b8ad7be9c2cc925c810f1414 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Feb 2019 14:59:06 +0100 Subject: sysctl: on EIO ("sysctl net.ipv6.conf.all.stable_secret") set nonzero exitcode Signed-off-by: Denys Vlasenko --- procps/sysctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/procps/sysctl.c b/procps/sysctl.c index 2ef19c1be..94a307901 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -177,6 +177,7 @@ static int sysctl_act_on_setting(char *setting) close(fd); if (value == NULL) { bb_perror_msg("error reading key '%s'", outname); + retval = EXIT_FAILURE; goto end; } -- cgit v1.2.3-55-g6feb From 78301861ef9e8d0edc72898712dbce7d793150a8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Feb 2019 16:02:39 +0100 Subject: sysctl: do slash/dot conversions only on name, not value part function old new delta sysctl_dots_to_slashes 71 86 +15 Signed-off-by: Denys Vlasenko --- procps/sysctl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/procps/sysctl.c b/procps/sysctl.c index 94a307901..5303460f9 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -57,6 +57,7 @@ enum { static void sysctl_dots_to_slashes(char *name) { char *cptr, *last_good, *end; + char end_ch; /* Convert minimum number of '.' to '/' so that * we end up with existing file's name. @@ -76,10 +77,11 @@ static void sysctl_dots_to_slashes(char *name) * * To set up testing: modprobe 8021q; vconfig add eth0 100 */ - end = name + strlen(name); - last_good = name - 1; + end = strchrnul(name, '='); + end_ch = *end; *end = '.'; /* trick the loop into trying full name too */ + last_good = name - 1; again: cptr = end; while (cptr > last_good) { @@ -96,7 +98,7 @@ static void sysctl_dots_to_slashes(char *name) } cptr--; } - *end = '\0'; + *end = end_ch; } static int sysctl_act_on_setting(char *setting) -- cgit v1.2.3-55-g6feb From c89764c0633670ef28166c70d03bc593f4a1179f Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 8 Feb 2019 16:30:24 +0100 Subject: sysctl: fix compatibility with procps sysctl Busybox sysctl is incompatible with procps when '.' appears in directory name, mostly happens with VLANs. busybox syntax (since 2008): net.ipv4.conf.eth0.100.mc_forwarding procps syntax (since 2002): net.ipv4.conf.eth0/100.mc_forwarding (supported by both: net/ipv4/conf/eth0.100/mc_forwarding) Use procps syntax for output; for input, allow both. function old new delta sysctl_dots_to_slashes 86 143 +57 sysctl_act_on_setting 443 453 +10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 67/0) Total: 67 bytes Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- procps/sysctl.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/procps/sysctl.c b/procps/sysctl.c index 5303460f9..6d77185ca 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -56,9 +56,32 @@ enum { static void sysctl_dots_to_slashes(char *name) { - char *cptr, *last_good, *end; + char *cptr, *last_good, *end, *slash; char end_ch; + end = strchrnul(name, '='); + + slash = strchrnul(name, '/'); + if (slash < end + && strchrnul(name, '.') < slash + ) { + /* There are both dots and slashes, and 1st dot is + * before 1st slash. + * (IOW: not raw, unmangled a/b/c.d format) + * + * procps supports this syntax for names with dots: + * net.ipv4.conf.eth0/100.mc_forwarding + * (dots and slashes are simply swapped) + */ + while (end != name) { + end--; + if (*end == '.') *end = '/'; + else if (*end == '/') *end = '.'; + } + return; + } + /* else: use our old behavior: */ + /* Convert minimum number of '.' to '/' so that * we end up with existing file's name. * @@ -77,7 +100,6 @@ static void sysctl_dots_to_slashes(char *name) * * To set up testing: modprobe 8021q; vconfig add eth0 100 */ - end = strchrnul(name, '='); end_ch = *end; *end = '.'; /* trick the loop into trying full name too */ @@ -114,6 +136,8 @@ static int sysctl_act_on_setting(char *setting) while (*cptr) { if (*cptr == '/') *cptr = '.'; + else if (*cptr == '.') + *cptr = '/'; cptr++; } -- cgit v1.2.3-55-g6feb From dac8f5ea38b0f293bc9d3b10693ebb94648a992d Mon Sep 17 00:00:00 2001 From: Nikolaus Voss Date: Sun, 10 Feb 2019 19:56:41 +0100 Subject: i2ctransfer: new applet i2ctransfer sends and receives user defined i2c messages v2: apply Xabier's comments: add -a option, don't decrement argc, use bb_show_usage() and xzalloc() v3: fix possible out of bound access to msgs[nmsgs] Reviewed-by: Xabier Oneca -- xOneca Signed-off-by: Nikolaus Voss Signed-off-by: Denys Vlasenko --- miscutils/i2c_tools.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 1 deletion(-) diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 610fed5d6..455ff028d 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -36,17 +36,26 @@ //config: help //config: Detect I2C chips. //config: +//config:config I2CTRANSFER +//config: bool "i2ctransfer (4.0 kb)" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Send user-defined I2C messages in one transfer. +//config: //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP)) /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o +//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o /* * Unsupported stuff: @@ -80,12 +89,19 @@ #define I2C_FUNCS 0x0705 #define I2C_PEC 0x0708 #define I2C_SMBUS 0x0720 +#define I2C_RDWR 0x0707 +#define I2C_RDWR_IOCTL_MAX_MSGS 42 +#define I2C_RDWR_IOCTL_MAX_MSGS_STR "42" struct i2c_smbus_ioctl_data { __u8 read_write; __u8 command; __u32 size; union i2c_smbus_data *data; }; +struct i2c_rdwr_ioctl_data { + struct i2c_msg *msgs; /* pointers to i2c_msgs */ + __u32 nmsgs; /* number of i2c_msgs */ +}; /* end linux/i2c-dev.h */ /* @@ -262,7 +278,7 @@ static int i2c_bus_lookup(const char *bus_str) return xstrtou_range(bus_str, 10, 0, 0xfffff); } -#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP +#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER static int i2c_parse_bus_addr(const char *addr_str) { /* Slave address must be in range 0x03 - 0x77. */ @@ -1373,3 +1389,163 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) return 0; } #endif /* ENABLE_I2CDETECT */ + +#if ENABLE_I2CTRANSFER +static void check_i2c_func(int fd) +{ + unsigned long funcs; + + get_funcs_matrix(fd, &funcs); + + if (!(funcs & I2C_FUNC_I2C)) + bb_error_msg_and_die("adapter does not support I2C transfers"); +} + +//usage:#define i2ctransfer_trivial_usage +//usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..." +//usage:#define i2ctransfer_full_usage "\n\n" +//usage: "Read/write I2C data in one transfer" +//usage: "\n" +//usage: "\n -f Force access" +//usage: "\n -a Force scanning of non-regular addresses" +//usage: "\n -y Disable interactive mode" +int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int i2ctransfer_main(int argc UNUSED_PARAM, char **argv) +{ + enum { + opt_f = (1 << 0), + opt_y = (1 << 1), + opt_a = (1 << 2), + }; + int bus_num, bus_addr; + int fd; + unsigned opts, first, last; + int nmsgs, nmsgs_sent, i; + struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS]; + struct i2c_rdwr_ioctl_data rdwr; + + memset(msgs, 0, sizeof(msgs)); + + opts = getopt32(argv, "^" + "fya" + "\0" "-2" /* minimum 2 args */ + ); + first = 0x03; + last = 0x77; + if (opts & opt_a) { + first = 0x00; + last = 0x7f; + } + + argv += optind; + bus_num = i2c_bus_lookup(argv[0]); + fd = i2c_dev_open(bus_num); + check_i2c_func(fd); + + bus_addr = -1; + nmsgs = 0; + while (*++argv) { + char *arg_ptr; + unsigned len; + uint16_t flags; + char *end; + + if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS) + bb_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR); + + flags = 0; + arg_ptr = *argv; + switch (*arg_ptr++) { + case 'r': flags |= I2C_M_RD; break; + case 'w': break; + default: + bb_show_usage(); + } + + end = strchr(arg_ptr, '@'); + if (end) *end = '\0'; + len = xstrtou_range(arg_ptr, 0, 0, 0xffff); + if (end) { + bus_addr = xstrtou_range(end + 1, 0, first, last); +//TODO: will this work correctly if -f is specified? + if (!(opts & opt_f)) + i2c_set_slave_addr(fd, bus_addr, (opts & opt_f)); + } else { + /* Reuse last address if possible */ + if (bus_addr < 0) + bb_error_msg_and_die("no address given in '%s'", *argv); + } + + msgs[nmsgs].addr = bus_addr; + msgs[nmsgs].flags = flags; + msgs[nmsgs].len = len; + if (len) + msgs[nmsgs].buf = xzalloc(len); + + if (!(flags & I2C_M_RD)) { + /* Consume DATA arg(s) */ + unsigned buf_idx = 0; + + while (buf_idx < len) { + uint8_t data8; + unsigned long data; + + arg_ptr = *++argv; + if (!arg_ptr) + bb_show_usage(); + data = strtoul(arg_ptr, &end, 0); + if (data > 0xff || arg_ptr == end) + bb_error_msg_and_die("invalid data byte '%s'", *argv); + + data8 = data; + while (buf_idx < len) { + msgs[nmsgs].buf[buf_idx++] = data8; + if (!*end) + break; + switch (*end) { + /* Pseudo randomness (8 bit AXR with a=13 and b=27) */ + case 'p': + data8 = (data8 ^ 27) + 13; + data8 = (data8 << 1) | (data8 >> 7); + break; + case '+': data8++; break; + case '-': data8--; break; + case '=': break; + default: + bb_error_msg_and_die("invalid data byte suffix: '%s'", + *argv); + } + } + } + } + nmsgs++; + } + + if (!(opts & opt_y)) + confirm_action(bus_addr, 0, 0, 0); + + rdwr.msgs = msgs; + rdwr.nmsgs = nmsgs; + nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR"); + if (nmsgs_sent < nmsgs) + bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs); + + for (i = 0; i < nmsgs_sent; i++) { + if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) { + int j; + for (j = 0; j < msgs[i].len - 1; j++) + printf("0x%02x ", msgs[i].buf[j]); + /* Print final byte with newline */ + printf("0x%02x\n", msgs[i].buf[j]); + } + } + +# if ENABLE_FEATURE_CLEAN_UP + close(fd); + for (i = 0; i < nmsgs; i++) + free(msgs[i].buf); +# endif + + return 0; +} +#endif /* ENABLE_I2CTRANSFER */ -- cgit v1.2.3-55-g6feb From 61052d1bb8fe5da745c4333a8bf7d031d636b76e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 11 Feb 2019 08:29:15 +0000 Subject: vi: further fixes to undo after autoindent Commit bb983f30e (vi: fix faulty undo after autoinsert) has a number of problems: - The commit message refers to 'autoinsert' when it really means 'autoindent'. - The indentation of undo_push_insert() was incorrect. - Most seriously the commit only fixed the problem for cases where the indentation was exactly one character. This is because undo_push() only allows single characters to be queued for UNDO_INS_QUEUED. Lifting this restriction allows the example given in the previous commit message (with a three character indent) to work. function old new delta undo_push 406 435 +29 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 29/0) Total: 29 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 899fcf57e..065a1068e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2314,16 +2314,18 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to } break; case UNDO_INS_QUEUED: - if (length != 1) + if (length < 1) return; switch (undo_queue_state) { case UNDO_EMPTY: undo_queue_state = UNDO_INS; undo_queue_spos = src; case UNDO_INS: - undo_q++; // Don't need to save any data for insertions - if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) - undo_queue_commit(); + while (length--) { + undo_q++; // Don't need to save any data for insertions + if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) + undo_queue_commit(); + } return; case UNDO_DEL: // Switch from storing deleted text to inserted text @@ -2372,16 +2374,16 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to static void undo_push_insert(char *p, int len, int undo) { switch (undo) { - case ALLOW_UNDO: - undo_push(p, len, UNDO_INS); - break; - case ALLOW_UNDO_CHAIN: - undo_push(p, len, UNDO_INS_CHAIN); - break; + case ALLOW_UNDO: + undo_push(p, len, UNDO_INS); + break; + case ALLOW_UNDO_CHAIN: + undo_push(p, len, UNDO_INS_CHAIN); + break; # if ENABLE_FEATURE_VI_UNDO_QUEUE - case ALLOW_UNDO_QUEUED: - undo_push(p, len, UNDO_INS_QUEUED); - break; + case ALLOW_UNDO_QUEUED: + undo_push(p, len, UNDO_INS_QUEUED); + break; # endif } } -- cgit v1.2.3-55-g6feb From f81e0120f4478c58e126bcadb19b9954ed184e8f Mon Sep 17 00:00:00 2001 From: Nikolaus Voss Date: Mon, 11 Feb 2019 11:30:52 +0100 Subject: i2c_tools.c: i2ctransfer Call i2c_set_slave_addr() unconditionally as busy checking is skipped depending on force argument. Clarify usage texts for -f and -a flags. Signed-off-by: Nikolaus Voss Signed-off-by: Denys Vlasenko --- miscutils/i2c_tools.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 455ff028d..7a2e8534a 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -1406,8 +1406,8 @@ static void check_i2c_func(int fd) //usage:#define i2ctransfer_full_usage "\n\n" //usage: "Read/write I2C data in one transfer" //usage: "\n" -//usage: "\n -f Force access" -//usage: "\n -a Force scanning of non-regular addresses" +//usage: "\n -f Force access to busy addresses" +//usage: "\n -a Force access to non-regular addresses" //usage: "\n -y Disable interactive mode" int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int i2ctransfer_main(int argc UNUSED_PARAM, char **argv) @@ -1467,9 +1467,7 @@ int i2ctransfer_main(int argc UNUSED_PARAM, char **argv) len = xstrtou_range(arg_ptr, 0, 0, 0xffff); if (end) { bus_addr = xstrtou_range(end + 1, 0, first, last); -//TODO: will this work correctly if -f is specified? - if (!(opts & opt_f)) - i2c_set_slave_addr(fd, bus_addr, (opts & opt_f)); + i2c_set_slave_addr(fd, bus_addr, (opts & opt_f)); } else { /* Reuse last address if possible */ if (bus_addr < 0) -- cgit v1.2.3-55-g6feb