diff mbox

[pacman-dev] handle EINTR while polling scripts/hooks

Message ID 20181013021653.6090-1-andrew.gregory.8@gmail.com
State Accepted, archived
Headers show

Commit Message

Andrew Gregory Oct. 13, 2018, 2:16 a.m. UTC
If poll() is interrupted by a signal, alpm was closing the socket it
uses for listening to script/hook output.  This would drop script output
at the least and kill the script at the worst.

Fixes FS#60396

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
---
 lib/libalpm/util.c                             | 10 +++++++++-
 test/pacman/tests/TESTS                        |  1 +
 test/pacman/tests/scriptlet-signal-handling.py | 15 +++++++++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 test/pacman/tests/scriptlet-signal-handling.py

Comments

Allan McRae Oct. 21, 2018, 9:20 a.m. UTC | #1
On 13/10/18 12:16 pm, Andrew Gregory wrote:
> If poll() is interrupted by a signal, alpm was closing the socket it
> uses for listening to script/hook output.  This would drop script output
> at the least and kill the script at the worst.
> 
> Fixes FS#60396
> 
> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>

Patch is good.

A
diff mbox

Patch

diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index eaf85e93..d33eef2a 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -665,6 +665,7 @@  int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
 		ssize_t olen = 0, ilen = 0;
 		nfds_t nfds = 2;
 		struct pollfd fds[2], *child2parent = &(fds[0]), *parent2child = &(fds[1]);
+		int poll_ret;
 
 		child2parent->fd = child2parent_pipefd[TAIL];
 		child2parent->events = POLLIN;
@@ -685,7 +686,14 @@  int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
 #define STOP_POLLING(p) do { close(p->fd); p->fd = -1; } while(0)
 
 		while((child2parent->fd != -1 || parent2child->fd != -1)
-				&& poll(fds, nfds, -1) > 0) {
+				&& (poll_ret = poll(fds, nfds, -1)) != 0) {
+			if(poll_ret == -1) {
+				if(errno == EINTR) {
+					continue;
+				} else {
+					break;
+				}
+			}
 			if(child2parent->revents & POLLIN) {
 				if(_alpm_chroot_read_from_child(handle, child2parent->fd,
 							ibuf, &ilen, sizeof(ibuf)) != 0) {
diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
index 5deb93c4..dc0b4ec3 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -150,6 +150,7 @@  TESTS += test/pacman/tests/replace102.py
 TESTS += test/pacman/tests/replace103.py
 TESTS += test/pacman/tests/replace104.py
 TESTS += test/pacman/tests/replace110.py
+TESTS += test/pacman/tests/scriptlet-signal-handling.py
 TESTS += test/pacman/tests/scriptlet-signal-reset.py
 TESTS += test/pacman/tests/scriptlet001.py
 TESTS += test/pacman/tests/scriptlet002.py
diff --git a/test/pacman/tests/scriptlet-signal-handling.py b/test/pacman/tests/scriptlet-signal-handling.py
new file mode 100644
index 00000000..e65df55b
--- /dev/null
+++ b/test/pacman/tests/scriptlet-signal-handling.py
@@ -0,0 +1,15 @@ 
+self.description = "Handle signal interrupts while running scriptlets/hooks"
+
+p1 = pmpkg("dummy")
+p1.install['post_install'] = """
+	kill -INT $PPID  # send an arbitrary signal that pacman catches
+	sleep 1          # give alpm time to close the socket if EINTR was not handled
+	echo to-parent   # if the interrupt is not handled this will die with SIGPIPE
+	echo success > interrupt_was_handled
+	"""
+self.addpkg(p1)
+
+self.args = "-U %s" % p1.filename()
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("FILE_EXIST=interrupt_was_handled")