From ac959bb9c6ce549047a954109ae825158855e386 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Fri, 12 Oct 2018 19:16:53 -0700 Subject: handle EINTR while polling scripts/hooks 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 Signed-off-by: Allan McRae --- 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 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") -- cgit v1.2.3-54-g00ecf