Browse Source

package/busybox: fix busybox lineedit signal handling

Since the Busybox version bump to 1.36.0 the TestS6 fails during the
test teardown.

Backport an upstream patch fixing signal handling (SIGWINCH), see [1].

Fixes:
https://gitlab.com/buildroot.org/buildroot/-/jobs/4322819388

[1] https://bugs.busybox.net/show_bug.cgi?id=15256

Signed-off-by: Romain Naour <romain.naour@gmail.com>
[Peter: use upstream commit as-is]
Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
Romain Naour 2 years ago
parent
commit
b6ce18b5ac

+ 103 - 0
package/busybox/0008-shell-fix-SIGWINCH-and-SIGCHLD-in-hush-interrupting-.patch

@@ -0,0 +1,103 @@
+From 93e0898c663a533082b5f3c2e7dcce93ec47076d Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.linux@googlemail.com>
+Date: Thu, 26 Jan 2023 12:56:33 +0100
+Subject: [PATCH] shell: fix SIGWINCH and SIGCHLD (in hush) interrupting line
+ input, closes 15256
+
+function                                             old     new   delta
+record_pending_signo                                  32      63     +31
+lineedit_read_key                                    231     224      -7
+------------------------------------------------------------------------------
+(add/remove: 0/0 grow/shrink: 1/1 up/down: 31/-7)              Total: 24 bytes
+
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+Upstream: https://git.busybox.net/busybox/commit/?id=93e0898c663a533082b5f3c2e7dcce93ec47076d
+Signed-off-by: Romain Naour <romain.naour@gmail.com>
+---
+ libbb/lineedit.c | 17 ++++++++++-------
+ shell/ash.c      |  3 ++-
+ shell/hush.c     | 10 ++++++++--
+ 3 files changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/libbb/lineedit.c b/libbb/lineedit.c
+index d6b2e76ff..b942f540a 100644
+--- a/libbb/lineedit.c
++++ b/libbb/lineedit.c
+@@ -2180,7 +2180,8 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
+ 		 * "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
+ 		 *
+ 		 * If LI_INTERRUPTIBLE, return -1 if got EINTR in poll()
+-		 * inside read_key, or if bb_got_signal != 0 (IOW: if signal
++		 * inside read_key and bb_got_signal became != 0,
++		 * or if bb_got_signal != 0 (IOW: if signal
+ 		 * arrived before poll() is reached).
+ 		 *
+ 		 * Note: read_key sets errno to 0 on success.
+@@ -2197,14 +2198,16 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
+ 			IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;)
+ 			if (errno != EINTR)
+ 				break;
++			/* It was EINTR. Repeat read_key() unless... */
+ 			if (state->flags & LI_INTERRUPTIBLE) {
+-				/* LI_INTERRUPTIBLE bails out on EINTR,
+-				 * but nothing really guarantees that bb_got_signal
+-				 * is nonzero. Follow the least surprise principle:
++				/* LI_INTERRUPTIBLE bails out on EINTR
++				 * if bb_got_signal became nonzero.
++				 * (It may stay zero: for example, our SIGWINCH
++				 * handler does not set it. This is used for signals
++				 * which should not interrupt line editing).
+ 				 */
+-				if (bb_got_signal == 0)
+-					bb_got_signal = 255;
+-				goto ret;
++				if (bb_got_signal != 0)
++					goto ret; /* will return -1 */
+ 			}
+ 		}
+ 
+diff --git a/shell/ash.c b/shell/ash.c
+index 18ccc1329..5f8c8ea19 100644
+--- a/shell/ash.c
++++ b/shell/ash.c
+@@ -10821,7 +10821,8 @@ preadfd(void)
+  again:
+ 		/* For shell, LI_INTERRUPTIBLE is set:
+ 		 * read_line_input will abort on either
+-		 * getting EINTR in poll(), or if it sees bb_got_signal != 0
++		 * getting EINTR in poll() and bb_got_signal became != 0,
++		 * or if it sees bb_got_signal != 0
+ 		 * (IOW: if signal arrives before poll() is reached).
+ 		 * Interactive testcases:
+ 		 * (while kill -INT $$; do sleep 1; done) &
+diff --git a/shell/hush.c b/shell/hush.c
+index d111f0cc5..f064b8fd2 100644
+--- a/shell/hush.c
++++ b/shell/hush.c
+@@ -1946,7 +1946,12 @@ static void record_pending_signo(int sig)
+ {
+ 	sigaddset(&G.pending_set, sig);
+ #if ENABLE_FEATURE_EDITING
+-	bb_got_signal = sig; /* for read_line_input: "we got a signal" */
++	if (sig != SIGCHLD
++	 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0])
++	 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */
++	) {
++		bb_got_signal = sig; /* for read_line_input: "we got a signal" */
++	}
+ #endif
+ #if ENABLE_HUSH_FAST
+ 	if (sig == SIGCHLD) {
+@@ -2669,7 +2674,8 @@ static int get_user_input(struct in_str *i)
+ 		} else {
+ 			/* For shell, LI_INTERRUPTIBLE is set:
+ 			 * read_line_input will abort on either
+-			 * getting EINTR in poll(), or if it sees bb_got_signal != 0
++			 * getting EINTR in poll() and bb_got_signal became != 0,
++			 * or if it sees bb_got_signal != 0
+ 			 * (IOW: if signal arrives before poll() is reached).
+ 			 * Interactive testcases:
+ 			 * (while kill -INT $$; do sleep 1; done) &
+-- 
+2.30.2
+