From a7d21c5c7f02241732818d747d4ee27f54a65c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 31 Jul 2020 17:15:51 +0200 Subject: [PATCH] slave: user-notifications: don't block in write(3) The main process is blocking and waiting for us to close the error pipe (in exec(3), via O_CLOEXEC). Thus, pts data will *not* be processed until we've exec:d the shell. Because of this we must not write too much and block in write(3). Do this by setting O_NONBLOCK on the pts fd (*after* dup:ing it to stdin/stderr/sdout) and watch for EAGAIN EWOULDBLOCK. --- slave.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/slave.c b/slave.c index 8019f20c..e8f9ccc7 100644 --- a/slave.c +++ b/slave.c @@ -93,6 +93,16 @@ emit_one_notification(int fd, const struct user_notification *notif) write(fd, notif->text, strlen(notif->text)) < 0 || write(fd, postfix, strlen(postfix)) < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + /* + * The main process is blocking and waiting for us to + * close the error pipe. Thus, pts data will *not* be + * processed until we've exec:d. This means we cannot + * write anymore once the kernel buffer is full. Don't + * treat this as a fatal error. + */ + return true; + } return false; } @@ -186,6 +196,14 @@ slave_exec(int ptmx, char *argv[], int err_fd, bool login_shell, goto err; } + { + int flags = fcntl(pts, F_GETFL); + if (flags < 0) + goto err; + if (fcntl(pts, F_SETFL, flags | O_NONBLOCK) < 0) + goto err; + } + if (!emit_notifications(pts, notifications)) goto err;