From 2235695335c56cf91df8dbae0ea49889b209da17 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Tue, 18 Aug 2015 14:41:24 -0400 Subject: [PATCH 1/2] logind: use open_terminal() instead of open() The open_terminal() function adds retries in case a terminal is in the process of being closed when we open it, and should generally be used to open a terminal. We especially need it for code that a subsequent commit adds that reopens the terminal at session shut-down time; such races would be more likely in that case. Found by Ray Strode. --- src/login/logind-session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/logind-session.c b/src/login/logind-session.c index e75c7c042e..902abe0e42 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -986,7 +986,7 @@ static int session_open_vt(Session *s) { return s->vtfd; sprintf(path, "/dev/tty%u", s->vtnr); - s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); + s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); if (s->vtfd < 0) return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id); From 128df4cfe93e6de6afb38a2160167339d88f4e1a Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Tue, 18 Aug 2015 15:19:05 -0400 Subject: [PATCH 2/2] logind: get a fresh file descriptor to clean up a VT When the controlling process exits, any existing file descriptors for that FD will be marked as hung-up and ioctls on them will file with EIO. To work around this, open a new file descriptor for the VT we want to clean up. Thanks to Ray Strode for help in sorting out the problem and coming up with a fix! https://github.com/systemd/systemd/issues/989 --- src/login/logind-session.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 902abe0e42..92a6027a7e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1050,7 +1050,18 @@ void session_restore_vt(Session *s) { int vt, kb = K_XLATE; struct vt_mode mode = { 0 }; + /* We need to get a fresh handle to the virtual terminal, + * since the old file-descriptor is potentially in a hung-up + * state after the controlling process exited; we do a + * little dance to avoid having the terminal be available + * for reuse before we've cleaned it up. + */ + int old_fd = s->vtfd; + s->vtfd = -1; + vt = session_open_vt(s); + safe_close(old_fd); + if (vt < 0) return;