aboutsummaryrefslogtreecommitdiffstats
path: root/package/utils/busybox/501-ash-hush-fix-SIGCHLD-interrupting-read-builtin.patch
blob: 1386dad282697503ead5adcb832ec75a47fac820 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
From f5470419404d643070db99d058405b714695b817 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Mon, 22 May 2017 19:34:45 +0200
Subject: [PATCH] ash,hush: fix SIGCHLD interrupting read builtin

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@googlemail.com>
Signed-off-by: Bastian Bittorf <bb@npl.de>
---
 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(-)
 create mode 100644 shell/ash_test/ash-read/read_SIGCHLD.right
 create mode 100755 shell/ash_test/ash-read/read_SIGCHLD.tests
 create mode 100644 shell/hush_test/hush-read/read_SIGCHLD.right
 create mode 100755 shell/hush_test/hush-read/read_SIGCHLD.tests

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;
-- 
1.9.1