[git commit] ash,hush: fix SIGCHLD interrupting read builtin

Denys Vlasenko vda.linux at googlemail.com
Mon May 22 17:34:45 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=f5470419404d643070db99d058405b714695b817
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
readcmd                                              169     217     +48
shell_builtin_read                                  1087    1097     +10
localcmd                                             366     364      -2
builtin_read                                         197     193      -4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 58/-6)              Total: 52 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                                  |  7 +++++++
 shell/ash_test/ash-read/read_SIGCHLD.right   |  2 ++
 shell/ash_test/ash-read/read_SIGCHLD.tests   |  4 ++++
 shell/hush.c                                 |  5 ++++-
 shell/hush_test/hush-read/read_SIGCHLD.right |  2 ++
 shell/hush_test/hush-read/read_SIGCHLD.tests |  4 ++++
 shell/shell_common.c                         | 20 +++++++++++---------
 7 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 70ee15e..60c8ffe 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -13268,6 +13268,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 	/* "read -s" needs to save/restore termios, can't allow ^C
 	 * to jump out of it.
 	 */
+ again:
 	INT_OFF;
 	r = shell_builtin_read(setvar0,
 		argptr,
@@ -13280,6 +13281,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 	);
 	INT_ON;
 
+	if ((uintptr_t)r == 1 && errno == EINTR) {
+		/* to get SIGCHLD: sleep 1 & read x; echo $x */
+		if (pending_sig == 0)
+			goto again;
+	}
+
 	if ((uintptr_t)r > 1)
 		ash_msg_and_raise_error(r);
 
diff --git a/shell/ash_test/ash-read/read_SIGCHLD.right b/shell/ash_test/ash-read/read_SIGCHLD.right
new file mode 100644
index 0000000..b3dc7ab
--- /dev/null
+++ b/shell/ash_test/ash-read/read_SIGCHLD.right
@@ -0,0 +1,2 @@
+x='Ok'
+exitcode:0
diff --git a/shell/ash_test/ash-read/read_SIGCHLD.tests b/shell/ash_test/ash-read/read_SIGCHLD.tests
new file mode 100755
index 0000000..c5f673a
--- /dev/null
+++ b/shell/ash_test/ash-read/read_SIGCHLD.tests
@@ -0,0 +1,4 @@
+x=BAD
+{ sleep 0.4; echo Ok; } | { sleep 0.2 & read x; echo "x='$x'"; }
+echo "exitcode:$?"
+
diff --git a/shell/hush.c b/shell/hush.c
index e18920f..125463a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -9038,6 +9038,9 @@ static int FAST_FUNC builtin_type(char **argv)
  * - terminates shell (regardless of interactivity);
  * if it has non-empty trap:
  * - executes trap and returns to read;
+ * SIGCHLD from children:
+ * - does not interrupt read regardless of interactivity:
+ *   try: sleep 1 & read x; echo $x
  */
 static int FAST_FUNC builtin_read(char **argv)
 {
@@ -9071,7 +9074,7 @@ static int FAST_FUNC builtin_read(char **argv)
 
 	if ((uintptr_t)r == 1 && errno == EINTR) {
 		unsigned sig = check_and_run_traps();
-		if (sig && sig != SIGINT)
+		if (sig != SIGINT)
 			goto again;
 	}
 
diff --git a/shell/hush_test/hush-read/read_SIGCHLD.right b/shell/hush_test/hush-read/read_SIGCHLD.right
new file mode 100644
index 0000000..b3dc7ab
--- /dev/null
+++ b/shell/hush_test/hush-read/read_SIGCHLD.right
@@ -0,0 +1,2 @@
+x='Ok'
+exitcode:0
diff --git a/shell/hush_test/hush-read/read_SIGCHLD.tests b/shell/hush_test/hush-read/read_SIGCHLD.tests
new file mode 100755
index 0000000..c5f673a
--- /dev/null
+++ b/shell/hush_test/hush-read/read_SIGCHLD.tests
@@ -0,0 +1,4 @@
+x=BAD
+{ sleep 0.4; echo Ok; } | { sleep 0.2 & read x; echo "x='$x'"; }
+echo "exitcode:$?"
+
diff --git a/shell/shell_common.c b/shell/shell_common.c
index fb86e68..03b7d0b 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -204,15 +204,17 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
 		c = buffer[bufpos];
 		if (c == '\0')
 			continue;
-		if (backslash) {
-			backslash = 0;
-			if (c != '\n')
-				goto put;
-			continue;
-		}
-		if (!(read_flags & BUILTIN_READ_RAW) && c == '\\') {
-			backslash = 1;
-			continue;
+		if (!(read_flags & BUILTIN_READ_RAW)) {
+			if (backslash) {
+				backslash = 0;
+				if (c != '\n')
+					goto put;
+				continue;
+			}
+			if (c == '\\') {
+				backslash = 1;
+				continue;
+			}
 		}
 		if (c == '\n')
 			break;


More information about the busybox-cvs mailing list