summaryrefslogtreecommitdiff
path: root/src/shared/ptyfwd.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2017-12-05 18:28:56 +0100
committerLennart Poettering <lennart@poettering.net>2017-12-05 18:33:24 +0100
commite22e69a31edd3089514436174f97d4d8d96ed194 (patch)
tree547321289e100a09a5b46f8540c073d514b8b4c6 /src/shared/ptyfwd.c
parent3aa6a559040dda5f5db061d77ef5c5aaf3b33501 (diff)
downloadsystemd-e22e69a31edd3089514436174f97d4d8d96ed194.tar.gz
ptyfwd: before deciding that a pty is fully drained, ask the kernel again
Apparently there's no guarantee that EPOLLIN is immediately propagated from a pty slave to the master when data is written to it, hence it's not sufficient to check EPOLLIN to decide whether the pty device is drained. Let's fix this by asking the kernel directly through SIOCINQ + SIOCOUTQ, if there's anything buffered left. Fixes: #7531
Diffstat (limited to 'src/shared/ptyfwd.c')
-rw-r--r--src/shared/ptyfwd.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 487a013148..3cc2e187cc 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -171,6 +171,30 @@ static bool ignore_vhangup(PTYForward *f) {
return false;
}
+static bool drained(PTYForward *f) {
+ int q = 0;
+
+ assert(f);
+
+ if (f->out_buffer_full > 0)
+ return false;
+
+ if (f->master_readable)
+ return false;
+
+ if (ioctl(f->master, TIOCINQ, &q) < 0)
+ log_debug_errno(errno, "TIOCINQ failed on master: %m");
+ else if (q > 0)
+ return false;
+
+ if (ioctl(f->master, TIOCOUTQ, &q) < 0)
+ log_debug_errno(errno, "TIOCOUTQ failed on master: %m");
+ else if (q > 0)
+ return false;
+
+ return true;
+}
+
static int shovel(PTYForward *f) {
ssize_t k;
@@ -306,7 +330,7 @@ static int shovel(PTYForward *f) {
/* If we were asked to drain, and there's nothing more to handle from the master, then call the callback
* too. */
- if (f->drain && f->out_buffer_full == 0 && !f->master_readable)
+ if (f->drain && drained(f))
return pty_forward_done(f, 0);
return 0;
@@ -547,6 +571,5 @@ bool pty_forward_drain(PTYForward *f) {
*/
f->drain = true;
-
- return f->out_buffer_full == 0 && !f->master_readable;
+ return drained(f);
}