From d2f4241d2eafc90cb7e0f985133ab62b24b473f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 8 Jul 2016 12:52:24 +0200 Subject: cpio: tweak help text Signed-off-by: Denys Vlasenko --- archival/cpio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/archival/cpio.c b/archival/cpio.c index 3b1550720..540218cb2 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -23,7 +23,7 @@ //config: cpio has 110 bytes of overheads for every stored file. //config: //config: This implementation of cpio can extract cpio archives created in the -//config: "newc" or "crc" format, it cannot create or modify them. +//config: "newc" or "crc" format. //config: //config: Unless you have a specific application which requires cpio, you //config: should probably say N here. @@ -51,10 +51,10 @@ //usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") //usage: " [EXTR_FILE]..." //usage:#define cpio_full_usage "\n\n" -//usage: "Extract or list files from a cpio archive" +//usage: "Extract (-i) or list (-t) files from a cpio archive" //usage: IF_FEATURE_CPIO_O(", or" -//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") -//usage: " using file list on stdin" +//usage: "\ntake file list from stdin and create an archive (-o)" +//usage: IF_FEATURE_CPIO_P(" or copy files (-p)") //usage: ) //usage: "\n" //usage: "\nMain operation mode:" -- cgit v1.2.3-55-g6feb From f6348e50ef2a2c28c611df4df92207d7b378e78e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 10 Jul 2016 20:15:28 +0200 Subject: examples: add a useful "see abridged log" script for ntpd service example Signed-off-by: Denys Vlasenko --- examples/var_service/ntpd/p_log_important | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 examples/var_service/ntpd/p_log_important diff --git a/examples/var_service/ntpd/p_log_important b/examples/var_service/ntpd/p_log_important new file mode 100755 index 000000000..09b248fb3 --- /dev/null +++ b/examples/var_service/ntpd/p_log_important @@ -0,0 +1,4 @@ +#!/bin/sh + +cd log/logdir || exit 1 +cat @* current | grep -v -eolder -esending -esockets -e'reply from.*offset' -executing | $PAGER -- cgit v1.2.3-55-g6feb From b0056ea86d427d76bb4c08506198d0c97075fdf6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Jul 2016 19:51:08 +0200 Subject: {md5,shaN}sum: make -c EMPTY fail function old new delta md5_sha1_sum_main 466 485 +19 Signed-off-by: Denys Vlasenko --- coreutils/md5_sha1_sum.c | 23 ++++++++++++++--------- testsuite/md5sum.tests | 22 +++++++++++++++++----- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index 1a5342e87..c0e816ba6 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c @@ -66,6 +66,10 @@ //usage: "\n -w Warn about improperly formatted checksum lines" //usage: ) +//FIXME: GNU coreutils 8.25 has no -s option, it has only these two long opts: +// --quiet don't print OK for each successfully verified file +// --status don't output anything, status code shows success + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -174,6 +178,8 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) unsigned flags; if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { + /* -s and -w require -c */ + opt_complementary = "s?c:w?c"; /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ flags = getopt32(argv, "scwbt"); argv += optind; @@ -185,15 +191,6 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) if (!*argv) *--argv = (char*)"-"; - if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) { - if (flags & FLAG_SILENT) { - bb_error_msg_and_die("-%c is meaningful only with -c", 's'); - } - if (flags & FLAG_WARN) { - bb_error_msg_and_die("-%c is meaningful only with -c", 'w'); - } - } - do { if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { FILE *pre_computed_stream; @@ -244,6 +241,14 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("WARNING: %d of %d computed checksums did NOT match", count_failed, count_total); } + if (count_total == 0) { + return_value = EXIT_FAILURE; + /* + * md5sum from GNU coreutils 8.25 says: + * md5sum: : no properly formatted MD5 checksum lines found + */ + bb_error_msg("%s: no checksum lines found", *argv); + } fclose_if_not_stdin(pre_computed_stream); } else { uint8_t *hash_value = hash_file(*argv); diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests index 6c75b6d1c..cca26dc64 100755 --- a/testsuite/md5sum.tests +++ b/testsuite/md5sum.tests @@ -23,6 +23,8 @@ test -f "$bindir/.config" && . "$bindir/.config" test x"$CONFIG_FEATURE_FANCY_HEAD" != x"y" \ && { echo "SKIPPED: $sum"; exit 0; } +FAILCOUNT=0 + text="The quick brown fox jumps over the lazy dog" text=`yes "$text" | head -c 9999` @@ -33,11 +35,21 @@ while test $n -le 999; do n=$(($n+1)) done | "$sum" )` - -if test x"$result" = x"$expected -"; then +if test x"$result" != x"$expected -"; then + echo "FAIL: $sum (r:$result exp:$expected)" + : $((FAILCOUNT++)) +else echo "PASS: $sum" - exit 0 fi -echo "FAIL: $sum (r:$result exp:$expected)" -exit 1 +# GNU compat: -c EMPTY must fail (exitcode 1)! +>EMPTY +if "$sum" -c EMPTY 2>/dev/null; then + echo "FAIL: $sum -c EMPTY" + : $((FAILCOUNT++)) +else + echo "PASS: $sum -c EMPTY" +fi +rm EMPTY + +exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 2ae86ad1c64b4de9bb63464d9a783229ed8e5dd0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 12 Jul 2016 13:54:35 +0200 Subject: trylink: use "mktemp tmp.XXXXXXXXXX" to placate OS X Signed-off-by: Denys Vlasenko --- scripts/trylink | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/trylink b/scripts/trylink index 145df9959..c2a431626 100755 --- a/scripts/trylink +++ b/scripts/trylink @@ -46,7 +46,7 @@ try() { } check_cc() { - local tempname="$(mktemp)" + local tempname="$(mktemp tmp.XXXXXXXXXX)" local r echo "int main(int argc,char**argv){return argv?argc:0;}" >"$tempname".c # Can use "-o /dev/null", but older gcc tend to *unlink it* on failure! :( @@ -61,7 +61,7 @@ check_cc() { } check_libc_is_glibc() { - local tempname="$(mktemp)" + local tempname="$(mktemp tmp.XXXXXXXXXX)" local r echo "\ #include -- cgit v1.2.3-55-g6feb From 9de7509aa013a8634b13a29008cd58ca971c9c7c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 14 Jul 2016 19:14:54 +0200 Subject: sendmail: improve help text * explain which server we contact by default * explain when auth is done * -t is not implied! remove that from help text Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index fb4dbb3da..a93be707d 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -10,7 +10,8 @@ //kbuild:lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o //usage:#define sendmail_trivial_usage -//usage: "[OPTIONS] [RECIPIENT_EMAIL]..." +//usage: "[-tv] [-f SENDER] [-amLOGIN 4. Can be empty string" //usage: "\n Default: -auUSER, or username of current UID" //usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" -//usage: "\n -i -oi synonym. implied and ignored" +//usage: "\n -i -oi synonym, implied and ignored" //usage: "\n" //usage: "\nBusybox specific options:" //usage: "\n -v Verbose" //usage: "\n -w SECS Network timeout" -//usage: "\n -H 'PROG ARGS' Run connection helper" -//usage: "\n Examples:" -//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" -//usage: "\n -connect smtp.gmail.com:25' Date: Thu, 14 Jul 2016 20:06:44 +0200 Subject: sendmail: include -H and -S in short help text Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index a93be707d..cd27d676e 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -11,7 +11,7 @@ //usage:#define sendmail_trivial_usage //usage: "[-tv] [-f SENDER] [-amLOGIN 4 Date: Thu, 14 Jul 2016 20:58:39 +0200 Subject: cp: make verbose cp show symlink copies too Signed-off-by: Denys Vlasenko --- libbb/copy_file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 23bcf2e82..7801b58c7 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -375,7 +375,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) } /* _Not_ jumping to preserve_mode_ugid_time: * symlinks don't have those */ - return 0; + goto verb_and_exit; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) @@ -410,6 +410,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } + verb_and_exit: if (flags & FILEUTILS_VERBOSE) { printf("'%s' -> '%s'\n", source, dest); } -- cgit v1.2.3-55-g6feb From e5814a5a42f40274aaadc1187680ffe5c4632c0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 16 Jul 2016 18:33:55 +0200 Subject: ash: do not leave SIGQUIT ignored on "exec CMD" Signed-off-by: Denys Vlasenko --- shell/ash.c | 15 ++++++++++++++- shell/ash_test/ash-signals/sigquit_exec.right | 2 ++ shell/ash_test/ash-signals/sigquit_exec.tests | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 shell/ash_test/ash-signals/sigquit_exec.right create mode 100755 shell/ash_test/ash-signals/sigquit_exec.tests diff --git a/shell/ash.c b/shell/ash.c index faa45a8dc..4f6376f78 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -323,7 +323,7 @@ struct globals_misc { #define S_DFL 1 /* default signal handling (SIG_DFL) */ #define S_CATCH 2 /* signal is caught */ #define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permenantly */ +#define S_HARD_IGN 4 /* signal is ignored permanently */ /* indicates specified signal received */ uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ @@ -9024,7 +9024,20 @@ execcmd(int argc UNUSED_PARAM, char **argv) iflag = 0; /* exit on error */ mflag = 0; optschanged(); + /* We should set up signals for "exec CMD" + * the same way as for "CMD" without "exec". + * But optschanged->setinteractive->setsignal + * still thought we are a root shell. Therefore, for example, + * SIGQUIT is still set to IGN. Fix it: + */ + shlvl++; + setsignal(SIGQUIT); + /*setsignal(SIGTERM); - unnecessary because of iflag=0 */ + /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */ + /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */ + shellexec(argv + 1, pathval(), 0); + /* NOTREACHED */ } return 0; } diff --git a/shell/ash_test/ash-signals/sigquit_exec.right b/shell/ash_test/ash-signals/sigquit_exec.right new file mode 100644 index 000000000..a8041929a --- /dev/null +++ b/shell/ash_test/ash-signals/sigquit_exec.right @@ -0,0 +1,2 @@ +SigIgn: 0000000000000000 +SigIgn: 0000000000000000 diff --git a/shell/ash_test/ash-signals/sigquit_exec.tests b/shell/ash_test/ash-signals/sigquit_exec.tests new file mode 100755 index 000000000..24bda6921 --- /dev/null +++ b/shell/ash_test/ash-signals/sigquit_exec.tests @@ -0,0 +1,4 @@ +# Should show no masked signals in both cases. +# We had a bug where SIGQUIT was masked on exec. +grep SigIgn: /proc/self/status +exec grep SigIgn: /proc/self/status -- cgit v1.2.3-55-g6feb From e695ac97fdd48808dd0a84d4725a063481a03c30 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 19 Jul 2016 17:48:55 +0200 Subject: typo fixes Signed-off-by: Denys Vlasenko --- coreutils/sync.c | 2 +- networking/route.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreutils/sync.c b/coreutils/sync.c index 974e90452..e65d9cd8d 100644 --- a/coreutils/sync.c +++ b/coreutils/sync.c @@ -15,7 +15,7 @@ //config: help //config: sync is used to flush filesystem buffers. //config:config FEATURE_SYNC_FANCY -//config: bool "Enable -d and -f flags (requres syncfs(2) in libc)" +//config: bool "Enable -d and -f flags (requires syncfs(2) in libc)" //config: default y //config: depends on SYNC //config: help diff --git a/networking/route.c b/networking/route.c index 65c2fb7c8..102a6ec67 100644 --- a/networking/route.c +++ b/networking/route.c @@ -295,7 +295,7 @@ static NOINLINE void INET_setroute(int action, char **args) #endif /* Device is special in that it can be the last arg specified - * and doesn't requre the dev/device keyword in that case. */ + * and doesn't require the dev/device keyword in that case. */ if (!rt->rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ rt->rt_dev = args[-1]; @@ -416,7 +416,7 @@ static NOINLINE void INET6_setroute(int action, char **args) } /* Device is special in that it can be the last arg specified - * and doesn't requre the dev/device keyword in that case. */ + * and doesn't require the dev/device keyword in that case. */ if (!devname && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ devname = args[-1]; -- cgit v1.2.3-55-g6feb From 49117b48008e0fe36d6680c787045cb44a300f93 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 21 Jul 2016 14:40:08 +0200 Subject: hush: fix a possible bug Not sure this was actually a triggerable bug, but the code looked flaky. Signed-off-by: Denys Vlasenko --- shell/hush.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/hush.c b/shell/hush.c index eabe83ac6..ab192e2cd 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -9153,9 +9153,11 @@ static int FAST_FUNC builtin_break(char **argv) unsigned depth; if (G.depth_of_loop == 0) { bb_error_msg("%s: only meaningful in a loop", argv[0]); + /* if we came from builtin_continue(), need to undo "= 1" */ + G.flag_break_continue = 0; return EXIT_SUCCESS; /* bash compat */ } - G.flag_break_continue++; /* BC_BREAK = 1 */ + G.flag_break_continue++; /* BC_BREAK = 1, or BC_CONTINUE = 2 */ G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1); if (depth == UINT_MAX) -- cgit v1.2.3-55-g6feb From 0fb0045aa9261be1dda49dfdfb95cbc585402a8b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 22 Jul 2016 18:48:38 +0200 Subject: config: disentangle PREFER_APPLETS from SH_STANDALONE and SH_NOFORK On user request. I thought enabling/disabling them all together is more consistent. Evidently, some people do want them to be separately selectable. Signed-off-by: Denys Vlasenko --- applets/applet_tables.c | 4 +++- include/busybox.h | 4 +++- libbb/vfork_daemon_rexec.c | 5 +++-- shell/Config.src | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 843f2ec08..8401a1549 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -143,7 +143,9 @@ int main(int argc, char **argv) printf("};\n"); printf("#endif\n\n"); -#if ENABLE_FEATURE_PREFER_APPLETS +#if ENABLE_FEATURE_PREFER_APPLETS \ + || ENABLE_FEATURE_SH_STANDALONE \ + || ENABLE_FEATURE_SH_NOFORK printf("const uint8_t applet_flags[] ALIGN1 = {\n"); i = 0; while (i < NUM_APPLETS) { diff --git a/include/busybox.h b/include/busybox.h index 737627bd0..6a003d544 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -19,7 +19,9 @@ extern const uint8_t applet_flags[] ALIGN1; extern const uint8_t applet_suid[] ALIGN1; extern const uint8_t applet_install_loc[] ALIGN1; -#if ENABLE_FEATURE_PREFER_APPLETS +#if ENABLE_FEATURE_PREFER_APPLETS \ + || ENABLE_FEATURE_SH_STANDALONE \ + || ENABLE_FEATURE_SH_NOFORK # define APPLET_IS_NOFORK(i) (applet_flags[(i)/4] & (1 << (2 * ((i)%4)))) # define APPLET_IS_NOEXEC(i) (applet_flags[(i)/4] & (1 << ((2 * ((i)%4))+1))) #else diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 1adb5b3c4..c192829b5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -68,7 +68,8 @@ pid_t FAST_FUNC xspawn(char **argv) return pid; } -#if ENABLE_FEATURE_PREFER_APPLETS +#if ENABLE_FEATURE_PREFER_APPLETS \ + || ENABLE_FEATURE_SH_NOFORK static jmp_buf die_jmp; static void jump(void) { @@ -174,7 +175,7 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } -#endif /* FEATURE_PREFER_APPLETS */ +#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ int FAST_FUNC spawn_and_wait(char **argv) { diff --git a/shell/Config.src b/shell/Config.src index b31e62dda..e4df35973 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -88,7 +88,7 @@ config FEATURE_SH_EXTRA_QUIET config FEATURE_SH_STANDALONE bool "Standalone shell" default n - depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS + depends on (HUSH || ASH) help This option causes busybox shells to use busybox applets in preference to executables in the PATH whenever possible. For @@ -121,7 +121,7 @@ config FEATURE_SH_STANDALONE config FEATURE_SH_NOFORK bool "Run 'nofork' applets directly" default n - depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS + depends on (HUSH || ASH) help This option causes busybox shells to not execute typical fork/exec/wait sequence, but call _main directly, -- cgit v1.2.3-55-g6feb From f8ddbe1ccce9eceaaac28b4b1aa71631fcc56db6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Jul 2016 03:56:00 +0200 Subject: ash: fix handling of ${VAR: -2} Signed-off-by: Denys Vlasenko --- shell/ash.c | 12 ++++++++---- shell/ash_test/ash-vars/var_bash1a.right | 6 ++++++ shell/ash_test/ash-vars/var_bash1a.tests | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 shell/ash_test/ash-vars/var_bash1a.right create mode 100755 shell/ash_test/ash-vars/var_bash1a.tests diff --git a/shell/ash.c b/shell/ash.c index 4f6376f78..496167fbe 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6323,6 +6323,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, #if ENABLE_ASH_BASH_COMPAT case VSSUBSTR: +//TODO: support more general format ${v:EXPR:EXPR}, +// where EXPR follows $(()) rules loc = str = stackblock() + strloc; /* Read POS in ${var:POS:LEN} */ pos = atoi(loc); /* number(loc) errors out on "1:4" */ @@ -11577,15 +11579,18 @@ parsesub: { STPUTC('=', out); flags = 0; if (subtype == 0) { + static const char types[] ALIGN1 = "}-+?="; /* ${VAR...} but not $VAR or ${#VAR} */ /* c == first char after VAR */ switch (c) { case ':': c = pgetc(); #if ENABLE_ASH_BASH_COMPAT - if (c == ':' || c == '$' || isdigit(c)) { -//TODO: support more general format ${v:EXPR:EXPR}, -// where EXPR follows $(()) rules + /* This check is only needed to not misinterpret + * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} + * constructs. + */ + if (!strchr(types, c)) { subtype = VSSUBSTR; pungetc(); break; /* "goto do_pungetc" is bigger (!) */ @@ -11594,7 +11599,6 @@ parsesub: { flags = VSNUL; /*FALLTHROUGH*/ default: { - static const char types[] ALIGN1 = "}-+?="; const char *p = strchr(types, c); if (p == NULL) goto badsub; diff --git a/shell/ash_test/ash-vars/var_bash1a.right b/shell/ash_test/ash-vars/var_bash1a.right new file mode 100644 index 000000000..1965b5c6c --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1a.right @@ -0,0 +1,6 @@ +parameter 'abcdef' +varoffset2 'cdef' +varoffset-2 'ef' +literal '2' 'cdef' +literal '-2' 'abcdef' +literal ' -2' 'ef' diff --git a/shell/ash_test/ash-vars/var_bash1a.tests b/shell/ash_test/ash-vars/var_bash1a.tests new file mode 100755 index 000000000..551dd9acc --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1a.tests @@ -0,0 +1,11 @@ +parameter=abcdef +offset=2 +noffset=-2 +echo "parameter '${parameter}'" +echo "varoffset2 '${parameter:${offset}}'" +echo "varoffset-2 '${parameter:${noffset}}'" +echo "literal '2' '${parameter:2}'" +# This is not inrpreted as ${VAR:POS{:LEN}}, +# but as ${VAR:=WORD} - if VAR is unset or null, substitute WORD +echo "literal '-2' '${parameter:-2}'" +echo "literal ' -2' '${parameter: -2}'" -- cgit v1.2.3-55-g6feb From 3191ec7ccedbf7265a409a314513cef5a8143495 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Jul 2016 16:28:57 +0200 Subject: var_service/fw: optionally flush all netdevs; optionally prefer one 0/0 routing Signed-off-by: Denys Vlasenko --- examples/var_service/fw/run | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/examples/var_service/fw/run b/examples/var_service/fw/run index 81c7f2e7c..871a70545 100755 --- a/examples/var_service/fw/run +++ b/examples/var_service/fw/run @@ -1,18 +1,20 @@ #!/bin/bash # (using bashism: arrays) -service="${PWD##*/}" -rundir="/var/run/service/$service" - -user=root -extif=if -ext_open_tcp="21 22 80" # space-separated +user="root" +reset_all_netdevs=true +preferred_default_route_iface="if" +extif="if" +ext_open_tcp="22 80 88" # space-separated # Make ourself one-shot sv o . # Debug #date '+%Y-%m-%d %H:%M:%S' >>"$0.log" +service=`basename $PWD` +rundir="/var/run/service/$service" + ### filter This is the default table (if no -t option is passed). It contains ### the built-in chains INPUT (for packets coming into the box itself), ### FORWARD (for packets being routed through the box), and OUTPUT (for @@ -70,7 +72,6 @@ ln -s "$rundir" rundir # Timestamping date '+%Y-%m-%d %H:%M:%S' - echo; echo "* Reading IP config" cfg=-1 # static cfg dhcp,zeroconf etc @@ -86,11 +87,19 @@ echo; echo "* Configuring hardware" #doit ethtool -K if rx off tx off sg off tso off echo; echo "* Resetting address and routing info" -doit ip a f dev lo -i=0; while test "${if[$i]}"; do - doit ip a f dev "${if[$i]}" - doit ip r f dev "${if[$i]}" root 0/0 -let i++; done +if $reset_all_netdevs; then + devs=`sed -n 's/ //g;s/:.*$//p' Date: Mon, 25 Jul 2016 17:12:46 +0200 Subject: ssl_helper.sh: strip was invoked incorrectly Signed-off-by: Denys Vlasenko --- networking/ssl_helper-wolfssl/ssl_helper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ssl_helper-wolfssl/ssl_helper.sh b/networking/ssl_helper-wolfssl/ssl_helper.sh index 184ffe67e..c6cbf353f 100755 --- a/networking/ssl_helper-wolfssl/ssl_helper.sh +++ b/networking/ssl_helper-wolfssl/ssl_helper.sh @@ -9,4 +9,4 @@ STATIC="-static" ${PREFIX}gcc -Os -Wall -I.. -c ssl_helper.c -o ssl_helper.o ${PREFIX}gcc $STATIC --start-group ssl_helper.o -lm ../src/.libs/libwolfssl.a --end-group -o ssl_helper -${PREFIX}-strip ssl_helper +${PREFIX}strip ssl_helper -- cgit v1.2.3-55-g6feb From ed72761843945ff7efc5a8ba3095a0f82e8f3e45 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Jul 2016 21:34:57 +0200 Subject: wget: run s_client helper with -servername HOST This is necessary for multi-hosted TLSed web sites. function old new delta spawn_https_helper_openssl 334 441 +107 Based on a patch by Jeremy Chadwick Signed-off-by: Denys Vlasenko --- networking/wget.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 37950ed39..653d8076f 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -62,9 +62,10 @@ //config: a helper program to talk over HTTPS. //config: //config: OpenSSL has a simple SSL client for debug purposes. -//config: If you select "openssl" helper, wget will effectively call -//config: "openssl s_client -quiet -connect IP:443 2>/dev/null" -//config: and pipe its data through it. +//config: If you select "openssl" helper, wget will effectively run: +//config: "openssl s_client -quiet -connect hostname:443 +//config: -servername hostname 2>/dev/null" and pipe its data +//config: through it. -servername is not used if hostname is numeric. //config: Note inconvenient API: host resolution is done twice, //config: and there is no guarantee openssl's idea of IPv6 address //config: format is the same as ours. @@ -349,6 +350,30 @@ static void set_alarm(void) # define clear_alarm() ((void)0) #endif +#if ENABLE_FEATURE_WGET_OPENSSL +/* + * 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) +{ + struct sockaddr_in sa; + + int result = inet_pton(AF_INET, string, &(sa.sin_addr)); +# if ENABLE_FEATURE_IPV6 + if (result == 0) { + struct sockaddr_in6 sa6; + result = inet_pton(AF_INET6, string, &(sa6.sin6_addr)); + } +# endif + return (result == 1); +} +#endif + static FILE *open_socket(len_and_sockaddr *lsa) { int fd; @@ -629,6 +654,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ static int spawn_https_helper_openssl(const char *host, unsigned port) { char *allocated = NULL; + char *servername; int sp[2]; int pid; IF_FEATURE_WGET_SSL_HELPER(volatile int child_failed = 0;) @@ -639,12 +665,14 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) if (!strchr(host, ':')) host = allocated = xasprintf("%s:%u", host, port); + servername = xstrdup(host); + strrchr(servername, ':')[0] = '\0'; fflush_all(); pid = xvfork(); if (pid == 0) { /* Child */ - char *argv[6]; + char *argv[8]; close(sp[0]); xmove_fd(sp[1], 0); @@ -656,12 +684,22 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) */ xmove_fd(2, 3); xopen("/dev/null", O_RDWR); + memset(&argv, 0, sizeof(argv)); argv[0] = (char*)"openssl"; argv[1] = (char*)"s_client"; argv[2] = (char*)"-quiet"; argv[3] = (char*)"-connect"; argv[4] = (char*)host; - argv[5] = NULL; + /* + * Per RFC 6066 Section 3, the only permitted values in the + * TLS server_name (SNI) field are FQDNs (DNS hostnames). + * IPv4 and IPv6 addresses, port numbers are not allowed. + */ + if (!is_ip_address(servername)) { + argv[5] = (char*)"-servername"; + argv[6] = (char*)servername; + } + BB_EXECVP(argv[0], argv); xmove_fd(3, 2); # if ENABLE_FEATURE_WGET_SSL_HELPER @@ -674,6 +712,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) } /* Parent */ + free(servername); free(allocated); close(sp[1]); # if ENABLE_FEATURE_WGET_SSL_HELPER -- cgit v1.2.3-55-g6feb From 6b5abc95969caf270d269ae640bb64e6bf8a7996 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 30 Jul 2016 22:29:10 +0200 Subject: service/fw example: do not ruin $if[], use different name Signed-off-by: Denys Vlasenko --- examples/var_service/fw/run | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/var_service/fw/run b/examples/var_service/fw/run index 871a70545..1fd71cc01 100755 --- a/examples/var_service/fw/run +++ b/examples/var_service/fw/run @@ -89,9 +89,9 @@ echo; echo "* Configuring hardware" echo; echo "* Resetting address and routing info" if $reset_all_netdevs; then devs=`sed -n 's/ //g;s/:.*$//p' Date: Mon, 1 Aug 2016 20:24:24 +0200 Subject: ntpd: respond only to client and symmetric active packets The busybox NTP implementation doesn't check the NTP mode of packets received on the server port and responds to any packet with the right size. This includes responses from another NTP server. An attacker can send a packet with a spoofed source address in order to create an infinite loop of responses between two busybox NTP servers. Adding more packets to the loop increases the traffic between the servers until one of them has a fully loaded CPU and/or network. Signed-off-by: Miroslav Lichvar Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/networking/ntpd.c b/networking/ntpd.c index 130cef0af..8ca62cf1b 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -2051,6 +2051,13 @@ recv_and_process_client_pkt(void /*int fd*/) goto bail; } + /* Respond only to client and symmetric active packets */ + if ((msg.m_status & MODE_MASK) != MODE_CLIENT + && (msg.m_status & MODE_MASK) != MODE_SYM_ACT + ) { + goto bail; + } + query_status = msg.m_status; query_xmttime = msg.m_xmttime; -- cgit v1.2.3-55-g6feb From 98c50f93fe494be5547188813c367299db80dbc5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 13 Aug 2016 23:23:48 +0200 Subject: cp: fix -i for POSIX mode. Closes 9106 Signed-off-by: Denys Vlasenko --- libbb/copy_file.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 7801b58c7..23c0f8320 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -296,11 +296,16 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) if (!S_ISREG(source_stat.st_mode)) new_mode = 0666; - // POSIX way is a security problem versus (sym)link attacks - if (!ENABLE_FEATURE_NON_POSIX_CP) { - dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); - } else { /* safe way: */ + if (ENABLE_FEATURE_NON_POSIX_CP || (flags & FILEUTILS_INTERACTIVE)) { + /* + * O_CREAT|O_EXCL: require that file did not exist before creation + */ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); + } else { /* POSIX, and not "cp -i" */ + /* + * O_CREAT|O_TRUNC: create, or truncate (security problem versus (sym)link attacks) + */ + dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); } if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); -- cgit v1.2.3-55-g6feb From 34ecc3b7aefdd6c31e8691bd5485037bbabedbd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 14 Aug 2016 01:30:34 +0200 Subject: ip: fix an improper optimization: req.r.rtm_scope may be nonzero here Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index e674e9a0d..48dc6e3d9 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -362,10 +362,9 @@ IF_FEATURE_IP_RULE(ARG_table,) req.r.rtm_scope = RT_SCOPE_NOWHERE; if (cmd != RTM_DELROUTE) { + req.r.rtm_scope = RT_SCOPE_UNIVERSE; if (RTPROT_BOOT != 0) req.r.rtm_protocol = RTPROT_BOOT; - if (RT_SCOPE_UNIVERSE != 0) - req.r.rtm_scope = RT_SCOPE_UNIVERSE; if (RTN_UNICAST != 0) req.r.rtm_type = RTN_UNICAST; } -- cgit v1.2.3-55-g6feb From 454829379951cb15d03d7e51ff292addde8548df Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 14 Aug 2016 02:08:56 +0200 Subject: libiproute: eliminate some redundant zero stores function old new delta do_iprule 974 955 -19 rtnl_dump_request 173 146 -27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-46) Total: -46 bytes Signed-off-by: Denys Vlasenko --- networking/libiproute/iprule.c | 8 +++--- networking/libiproute/libnetlink.c | 50 ++++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c index dba64346f..c486834b0 100644 --- a/networking/libiproute/iprule.c +++ b/networking/libiproute/iprule.c @@ -197,9 +197,11 @@ static int iprule_modify(int cmd, char **argv) req.n.nlmsg_flags = NLM_F_REQUEST; req.r.rtm_family = preferred_family; req.r.rtm_protocol = RTPROT_BOOT; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - req.r.rtm_table = 0; - req.r.rtm_type = RTN_UNSPEC; + if (RT_SCOPE_UNIVERSE != 0) + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + /*req.r.rtm_table = 0; - already is */ + if (RTN_UNSPEC != 0) + req.r.rtm_type = RTN_UNSPEC; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index cbb5daf95..9d5c6416b 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -68,30 +68,32 @@ int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) { - struct nlmsghdr nlh; - struct sockaddr_nl nladdr; - struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; - /* Use designated initializers, struct layout is non-portable */ - struct msghdr msg = { - .msg_name = (void*)&nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = iov, - .msg_iovlen = 2, - .msg_control = NULL, - .msg_controllen = 0, - .msg_flags = 0 - }; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - - nlh.nlmsg_len = NLMSG_LENGTH(len); - nlh.nlmsg_type = type; - nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; - nlh.nlmsg_pid = 0; - nlh.nlmsg_seq = rth->dump = ++rth->seq; - - return sendmsg(rth->fd, &msg, 0); + struct { + struct nlmsghdr nlh; + struct msghdr msg; + struct sockaddr_nl nladdr; + } s; + struct iovec iov[2] = { { &s.nlh, sizeof(s.nlh) }, { req, len } }; + + memset(&s, 0, sizeof(s)); + + s.msg.msg_name = (void*)&s.nladdr; + s.msg.msg_namelen = sizeof(s.nladdr); + s.msg.msg_iov = iov; + s.msg.msg_iovlen = 2; + /*s.msg.msg_control = NULL; - already is */ + /*s.msg.msg_controllen = 0; - already is */ + /*s.msg.msg_flags = 0; - already is */ + + s.nladdr.nl_family = AF_NETLINK; + + s.nlh.nlmsg_len = NLMSG_LENGTH(len); + s.nlh.nlmsg_type = type; + s.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; + /*s.nlh.nlmsg_pid = 0; - already is */ + s.nlh.nlmsg_seq = rth->dump = ++rth->seq; + + return sendmsg(rth->fd, &s.msg, 0); } static int rtnl_dump_filter(struct rtnl_handle *rth, -- cgit v1.2.3-55-g6feb From 9e5820a86277818c2f83c11c2aa76d7f0a38283e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 14 Aug 2016 02:54:27 +0200 Subject: build system: fix include/NUM_APPLETS.h generation TBH, it's more like "work around my bad makefile-fu" than "fix"... Signed-off-by: Denys Vlasenko --- applets/Kbuild.src | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/applets/Kbuild.src b/applets/Kbuild.src index b61239948..5cc1827ea 100644 --- a/applets/Kbuild.src +++ b/applets/Kbuild.src @@ -29,7 +29,7 @@ applets/applets.o: include/usage_compressed.h include/applet_tables.h applets/applet_tables: .config include/applets.h applets/usage: .config include/applets.h -applets/usage_pod: .config include/applet_tables.h include/applets.h +applets/usage_pod: .config include/applets.h include/applet_tables.h include/NUM_APPLETS.h quiet_cmd_gen_usage_compressed = GEN include/usage_compressed.h cmd_gen_usage_compressed = $(srctree_slash)applets/usage_compressed include/usage_compressed.h applets @@ -40,8 +40,5 @@ include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compress quiet_cmd_gen_applet_tables = GEN include/applet_tables.h cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h -include/applet_tables.h: applets/applet_tables - $(call cmd,gen_applet_tables) - -include/NUM_APPLETS.h: applets/applet_tables +include/applet_tables.h include/NUM_APPLETS.h: applets/applet_tables $(call cmd,gen_applet_tables) -- cgit v1.2.3-55-g6feb From 7e6f9316a8bf3030da6c283e43aa0709d0cef259 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Sun, 14 Aug 2016 23:30:29 +0200 Subject: lineedit: trivial codeshrink for vi-mode Introduce and use BB_isalnum_or_underscore(). function old new delta BB_isalnum_or_underscore - 43 +43 vi_word_motion 162 150 -12 vi_end_motion 163 145 -18 vi_back_motion 198 179 -19 BB_isalnum 39 - -39 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 0/3 up/down: 43/-88) Total: -45 bytes Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 3e62f46b4..3bfff0084 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -81,7 +81,9 @@ # define CHAR_T wchar_t static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } # if ENABLE_FEATURE_EDITING_VI -static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); } +static bool BB_isalnum_or_underscore(CHAR_T c) { + return ((unsigned)c < 256 && isalnum(c)) || c == '_'; +} # endif static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } # undef isspace @@ -96,7 +98,11 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } # define BB_NUL '\0' # define CHAR_T char # define BB_isspace(c) isspace(c) -# define BB_isalnum(c) isalnum(c) +# if ENABLE_FEATURE_EDITING_VI +static bool BB_isalnum_or_underscore(CHAR_T c) { + return ((unsigned)c < 256 && isalnum(c)) || c == '_'; +} +# endif # define BB_ispunct(c) ispunct(c) #endif #if ENABLE_UNICODE_PRESERVE_BROKEN @@ -1586,9 +1592,9 @@ vi_word_motion(int eat) { CHAR_T *command = command_ps; - if (BB_isalnum(command[cursor]) || command[cursor] == '_') { + if (BB_isalnum_or_underscore(command[cursor])) { while (cursor < command_len - && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') + && (BB_isalnum_or_underscore(command[cursor+1])) ) { input_forward(); } @@ -1630,9 +1636,9 @@ vi_end_motion(void) input_forward(); if (cursor >= command_len-1) return; - if (BB_isalnum(command[cursor]) || command[cursor] == '_') { + if (BB_isalnum_or_underscore(command[cursor])) { while (cursor < command_len-1 - && (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') + && (BB_isalnum_or_underscore(command[cursor+1])) ) { input_forward(); } @@ -1665,9 +1671,9 @@ vi_back_motion(void) input_backward(1); if (cursor <= 0) return; - if (BB_isalnum(command[cursor]) || command[cursor] == '_') { + if (BB_isalnum_or_underscore(command[cursor])) { while (cursor > 0 - && (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_') + && (BB_isalnum_or_underscore(command[cursor-1])) ) { input_backward(1); } -- cgit v1.2.3-55-g6feb From 71cfbce655bcfa6d3e0154d441a33d3bfd1dca57 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 3 Aug 2016 16:21:52 +0200 Subject: gzip: fix compression level bug. Closes 9131 fix broken logic to get the gzip_level_config value from options -1 to -9. This fixes an off-by-one bug that caused gzip -9 output bigger files than the other compression levels. It fixes so that compression level 1 to 3 are actually mapped to level 4 as comments say. It also fixes that levels -4 to -9 is mapped to correct level and avoids out-of-bounds access. Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- archival/gzip.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index 8f1e4ff29..9e0bee815 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -2220,10 +2220,7 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) opt >>= ENABLE_GUNZIP ? 7 : 5; /* drop cfv[dt]qn bits */ if (opt == 0) opt = 1 << 6; /* default: 6 */ - /* Map 1..3 to 4 */ - if (opt & 0x7) - opt |= 1 << 4; - opt = ffs(opt >> 3); + opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ max_chain_length = 1 << gzip_level_config[opt].chain_shift; good_match = gzip_level_config[opt].good; max_lazy_match = gzip_level_config[opt].lazy2 * 2; -- cgit v1.2.3-55-g6feb From 560cf8c7ebd3feff6244a381a300cb2bac8570ec Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 3 Aug 2016 16:21:53 +0200 Subject: gzip: add test that checks that -9 compresses better than -1 Signed-off-by: Natanael Copa Signed-off-by: Denys Vlasenko --- testsuite/gzip/gzip-compression-levels | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 testsuite/gzip/gzip-compression-levels diff --git a/testsuite/gzip/gzip-compression-levels b/testsuite/gzip/gzip-compression-levels new file mode 100644 index 000000000..6d9a13d08 --- /dev/null +++ b/testsuite/gzip/gzip-compression-levels @@ -0,0 +1,5 @@ +# FEATURE: CONFIG_FEATURE_GZIP_LEVELS + +level1=$(busybox gzip -c -1 $(which busybox) | wc -c) +level9=$(busybox gzip -c -9 $(which busybox) | wc -c) +test $level1 -gt $level9 -- cgit v1.2.3-55-g6feb From 252559601f12e22ad3a687fb8188fdbf63bbdc45 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 16 Aug 2016 15:09:40 +0200 Subject: less: fix SEGV testcase: echo "" | less, then press ')' key Signed-off-by: Denys Vlasenko --- miscutils/less.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/miscutils/less.c b/miscutils/less.c index d7076dbbc..10e1d8e16 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -1591,7 +1591,9 @@ static void match_right_bracket(char bracket) { unsigned i; - if (strchr(flines[cur_fline], bracket) == NULL) { + if (cur_fline >= max_fline + || strchr(flines[cur_fline], bracket) == NULL + ) { print_statusline("No bracket in top line"); return; } @@ -1609,7 +1611,9 @@ static void match_left_bracket(char bracket) { int i; - if (strchr(flines[cur_fline + max_displayed_line], bracket) == NULL) { + if (cur_fline + max_displayed_line >= max_fline + || strchr(flines[cur_fline + max_displayed_line], bracket) == NULL + ) { print_statusline("No bracket in bottom line"); return; } -- cgit v1.2.3-55-g6feb From 110c6bb413ff7363e9b453edef8ae11cf7b64404 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 16 Aug 2016 15:27:30 +0200 Subject: less: fix bracket search to match behavior of less 481 Signed-off-by: Denys Vlasenko --- miscutils/less.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/miscutils/less.c b/miscutils/less.c index 10e1d8e16..d1d4a71be 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -1589,18 +1589,23 @@ static char opp_bracket(char bracket) static void match_right_bracket(char bracket) { - unsigned i; + unsigned i = cur_fline; - if (cur_fline >= max_fline - || strchr(flines[cur_fline], bracket) == NULL + if (i >= max_fline + || strchr(flines[i], bracket) == NULL ) { print_statusline("No bracket in top line"); return; } + bracket = opp_bracket(bracket); - for (i = cur_fline + 1; i < max_fline; i++) { + for (; i < max_fline; i++) { if (strchr(flines[i], bracket) != NULL) { - buffer_line(i); + /* + * Line with matched right bracket becomes + * last visible line + */ + buffer_line(i - max_displayed_line); return; } } @@ -1609,18 +1614,22 @@ static void match_right_bracket(char bracket) static void match_left_bracket(char bracket) { - int i; + int i = cur_fline + max_displayed_line; - if (cur_fline + max_displayed_line >= max_fline - || strchr(flines[cur_fline + max_displayed_line], bracket) == NULL + if (i >= max_fline + || strchr(flines[i], bracket) == NULL ) { print_statusline("No bracket in bottom line"); return; } bracket = opp_bracket(bracket); - for (i = cur_fline + max_displayed_line; i >= 0; i--) { + for (; i >= 0; i--) { if (strchr(flines[i], bracket) != NULL) { + /* + * Line with matched left bracket becomes + * first visible line + */ buffer_line(i); return; } -- cgit v1.2.3-55-g6feb From b11be131b73fd47e12b1a9f1c52ac0a1ed222aee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 16 Aug 2016 20:39:52 +0200 Subject: ifplugd: if SIOCSIFFLAGS fails with ENODEV, don't die Some user managed to hit a race where iface is gone between SIOCGIFFLAGS and SIOCSIFFLAGS (!). If SIOCSIFFLAGS fails, treat it the same as failed SIOCGIFFLAGS Signed-off-by: Denys Vlasenko --- networking/ifplugd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 28c49e218..029cba147 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c @@ -358,8 +358,12 @@ static void up_iface(void) ifrequest.ifr_flags |= IFF_UP; /* Let user know we mess up with interface */ bb_error_msg("upping interface"); - if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) - xfunc_die(); + if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) { + if (errno != ENODEV) + xfunc_die(); + G.iface_exists = 0; + return; + } } #if 0 /* why do we mess with IP addr? It's not our business */ -- cgit v1.2.3-55-g6feb From aedc3fe19fac368dc363050e0387d263b7e01cc6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Aug 2016 11:07:31 +0200 Subject: top: move free(prev_hist) out of signal path It was seen being called recursively on repeated signals, leading to double free Signed-off-by: Denys Vlasenko --- procps/top.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/procps/top.c b/procps/top.c index 73cd285f0..6f7f7d382 100644 --- a/procps/top.c +++ b/procps/top.c @@ -728,12 +728,6 @@ static void reset_term(void) { if (!OPT_BATCH_MODE) tcsetattr_stdin_TCSANOW(&initial_settings); - if (ENABLE_FEATURE_CLEAN_UP) { - clearmems(); -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - free(prev_hist); -# endif - } } static void sig_catcher(int sig) @@ -1258,5 +1252,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_USE_TERMIOS reset_term(); #endif + if (ENABLE_FEATURE_CLEAN_UP) { + clearmems(); +#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + free(prev_hist); +#endif + } return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 215b0ca6e4fe466c6942d21a1bba62d97f2d5e5d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Aug 2016 18:23:56 +0200 Subject: hush: fix a bug in FEATURE_SH_STANDALONE=y config. Closes 9186 Run this in a "sh SCRIPT": sha256sum /dev/null echo END sha256sum is a NOEXEC applet. It runs in a forked child. Then child exit()s. By this time, entire script is read, and buffered in a FILE object from fopen("SCRIPT"). But fgetc() did not consume entire input. exit() lseeks back by -9 bytes, from to 'e' in 'echo'. (this may be libc-specific). This change of fd position *is shared with the parent*! Now parent can read more, and it thinks there is another "echo END". End result: two "echo END"s are run. Fix this by _exit()ing instead. Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 4 +++- shell/hush.c | 23 ++++++++++++++++++++--- shell/hush_test/run-all | 3 ++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index c341817e2..f760af2cb 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -877,7 +877,9 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) } if (ENABLE_FEATURE_SUID) check_suid(applet_no); - exit(applet_main[applet_no](argc, argv)); + xfunc_error_retval = applet_main[applet_no](argc, argv); + /* Note: applet_main() may also not return (die on a xfunc or such) */ + xfunc_die(); } # endif /* NUM_APPLETS > 0 */ diff --git a/shell/hush.c b/shell/hush.c index ab192e2cd..be5c98a20 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1580,11 +1580,11 @@ static void hush_exit(int exitcode) } #endif -#if ENABLE_HUSH_JOB fflush_all(); +#if ENABLE_HUSH_JOB sigexit(- (exitcode & 0xff)); #else - exit(exitcode); + _exit(exitcode); #endif } @@ -6466,7 +6466,23 @@ static void dump_cmd_in_x_mode(char **argv) * Never returns. * Don't exit() here. If you don't exec, use _exit instead. * The at_exit handlers apparently confuse the calling process, - * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ + * in particular stdin handling. Not sure why? -- because of vfork! (vda) + * Also, it was observed that on exit(), fgetc'ed buffered data + * gets "unwound" by some libcs, via lseek(fd, -NUM, SEEK_CUR). + * With the net effect that even after fork(), not vfork(), + * exit() in NOEXECed applet in "sh SCRIPT": + * noexec_applet_here + * echo END_OF_SCRIPT + * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". + * This makes "echo END_OF_SCRIPT" executed twice. exexit() is the fix. + */ +#if ENABLE_FEATURE_SH_STANDALONE +static void exexit(void) +{ + fflush_all(); + _exit(xfunc_error_retval); +} +#endif static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; @@ -6547,6 +6563,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, # if BB_MMU /* see above why on NOMMU it is not allowed */ if (APPLET_IS_NOEXEC(a)) { debug_printf_exec("running applet '%s'\n", argv[0]); + die_func = exexit; run_applet_no_and_exit(a, argv); } # endif diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 64a7abc47..837b3f7da 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all @@ -64,11 +64,12 @@ do_test() echo -n "$1/$x:" ( "$THIS_SH" "./$x" >"$name.xx" 2>&1 + r=$? # filter C library differences sed -i \ -e "/: invalid option /s:'::g" \ "$name.xx" - test $? -eq 77 && rm -f "../$1-$x.fail" && exit 77 + test $r -eq 77 && rm -f "../$1-$x.fail" && exit 77 diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" ) case $? in -- cgit v1.2.3-55-g6feb From e9abe75fda82a986b0b40969ebdd4aa92bcb52e3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 19 Aug 2016 20:15:26 +0200 Subject: hush: `cmd` and arithmetic also need the fix for FILE rewind Discovered by running testsuite with a newest glibc Signed-off-by: Denys Vlasenko --- shell/hush.c | 71 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index be5c98a20..b41d9d04b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1477,19 +1477,50 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) return old_sa.sa_handler; } +static void hush_exit(int exitcode) NORETURN; +static void fflush_and__exit(void) NORETURN; +static void restore_ttypgrp_and__exit(void) NORETURN; + +static void restore_ttypgrp_and__exit(void) +{ + /* xfunc has failed! die die die */ + /* no EXIT traps, this is an escape hatch! */ + G.exiting = 1; + hush_exit(xfunc_error_retval); +} + +/* Needed only on some libc: + * It was observed that on exit(), fgetc'ed buffered data + * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). + * With the net effect that even after fork(), not vfork(), + * exit() in NOEXECed applet in "sh SCRIPT": + * noexec_applet_here + * echo END_OF_SCRIPT + * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". + * This makes "echo END_OF_SCRIPT" executed twice. + * Similar problems can be seen with die_if_script() -> xfunc_die() + * and in `cmd` handling. + * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): + */ +static void fflush_and__exit(void) +{ + fflush_all(); + _exit(xfunc_error_retval); +} + #if ENABLE_HUSH_JOB -static void xfunc_has_died(void); /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ -# define disable_restore_tty_pgrp_on_exit() (die_func = NULL) +# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) /* After [v]fork, in parent: restore tty pgrp on xfunc death */ -# define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) +# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit) /* Restores tty foreground process group, and exits. * May be called as signal handler for fatal signal * (will resend signal to itself, producing correct exit state) * or called directly with -EXITCODE. - * We also call it if xfunc is exiting. */ + * We also call it if xfunc is exiting. + */ static void sigexit(int sig) NORETURN; static void sigexit(int sig) { @@ -1544,7 +1575,6 @@ static sighandler_t pick_sighandler(unsigned sig) } /* Restores tty foreground process group, and exits. */ -static void hush_exit(int exitcode) NORETURN; static void hush_exit(int exitcode) { #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT @@ -1588,15 +1618,6 @@ static void hush_exit(int exitcode) #endif } -static void xfunc_has_died(void) NORETURN; -static void xfunc_has_died(void) -{ - /* xfunc has failed! die die die */ - /* no EXIT traps, this is an escape hatch! */ - G.exiting = 1; - hush_exit(xfunc_error_retval); -} - //TODO: return a mask of ALL handled sigs? static int check_and_run_traps(void) @@ -5913,7 +5934,8 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) ) { static const char *const argv[] = { NULL, NULL }; builtin_trap((char**)argv); - exit(0); /* not _exit() - we need to fflush */ + fflush_all(); /* important */ + _exit(0); } # if BB_MMU reset_traps_to_defaults(); @@ -6467,22 +6489,7 @@ static void dump_cmd_in_x_mode(char **argv) * Don't exit() here. If you don't exec, use _exit instead. * The at_exit handlers apparently confuse the calling process, * in particular stdin handling. Not sure why? -- because of vfork! (vda) - * Also, it was observed that on exit(), fgetc'ed buffered data - * gets "unwound" by some libcs, via lseek(fd, -NUM, SEEK_CUR). - * With the net effect that even after fork(), not vfork(), - * exit() in NOEXECed applet in "sh SCRIPT": - * noexec_applet_here - * echo END_OF_SCRIPT - * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". - * This makes "echo END_OF_SCRIPT" executed twice. exexit() is the fix. */ -#if ENABLE_FEATURE_SH_STANDALONE -static void exexit(void) -{ - fflush_all(); - _exit(xfunc_error_retval); -} -#endif static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; @@ -6563,7 +6570,6 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, # if BB_MMU /* see above why on NOMMU it is not allowed */ if (APPLET_IS_NOEXEC(a)) { debug_printf_exec("running applet '%s'\n", argv[0]); - die_func = exexit; run_applet_no_and_exit(a, argv); } # endif @@ -7804,6 +7810,7 @@ int hush_main(int argc, char **argv) INIT_G(); if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ G.last_exitcode = EXIT_SUCCESS; + #if ENABLE_HUSH_FAST G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ #endif @@ -7893,7 +7900,7 @@ int hush_main(int argc, char **argv) /* Initialize some more globals to non-zero values */ cmdedit_update_prompt(); - die_func = xfunc_has_died; + die_func = restore_ttypgrp_and__exit; /* Shell is non-interactive at first. We need to call * install_special_sighandlers() if we are going to execute "sh