From: Mike Yuan Date: Mon, 28 Aug 2023 14:33:33 +0000 (+0800) Subject: logind-session: generalize EIO handling for {restore,leave}_vt X-Git-Tag: v255-rc1~624^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=93041c6010ad7699a8aa7e6c8a1ee5bea3a2fd7c;p=thirdparty%2Fsystemd.git logind-session: generalize EIO handling for {restore,leave}_vt Replaces #28949 --- diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 939a728a828..4e885ce03bd 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1290,7 +1290,8 @@ int session_kill(Session *s, KillWho who, int signo) { return manager_kill_unit(s->manager, s->scope, who, signo, NULL); } -static int session_open_vt(Session *s) { +static int session_open_vt(Session *s, bool reopen) { + _cleanup_close_ int fd = -EBADF; char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)]; assert(s); @@ -1298,14 +1299,16 @@ static int session_open_vt(Session *s) { if (s->vtnr < 1) return -ENODEV; - if (s->vtfd >= 0) + if (!reopen && s->vtfd >= 0) return s->vtfd; sprintf(path, "/dev/tty%u", s->vtnr); - s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); - if (s->vtfd < 0) - return log_error_errno(s->vtfd, "Cannot open VT %s of session %s: %m", path, s->id); + fd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); + if (fd < 0) + return log_error_errno(fd, "Cannot open VT %s of session %s: %m", path, s->id); + + close_and_replace(s->vtfd, fd); return s->vtfd; } @@ -1318,7 +1321,7 @@ static int session_prepare_vt(Session *s) { if (s->vtnr < 1) return 0; - vt = session_open_vt(s); + vt = session_open_vt(s, /* reopen = */ false); if (vt < 0) return vt; @@ -1377,23 +1380,17 @@ static void session_restore_vt(Session *s) { r = vt_restore(s->vtfd); if (r == -EIO) { - int vt, old_fd; - /* It might happen if the controlling process exited before or while we were * restoring the VT as it would leave the old file-descriptor in a hung-up * state. In this case let's retry with a fresh handle to the virtual terminal. */ /* We do a little dance to avoid having the terminal be available * for reuse before we've cleaned it up. */ - old_fd = TAKE_FD(s->vtfd); - - vt = session_open_vt(s); - safe_close(old_fd); - if (vt >= 0) - r = vt_restore(vt); + int fd = session_open_vt(s, /* reopen = */ true); + if (fd >= 0) + r = vt_restore(fd); } - if (r < 0) log_warning_errno(r, "Failed to restore VT, ignoring: %m"); @@ -1420,23 +1417,13 @@ void session_leave_vt(Session *s) { return; session_device_pause_all(s); - r = vt_release(s->vtfd, false); + r = vt_release(s->vtfd, /* restore = */ false); if (r == -EIO) { - int vt, old_fd; - - /* It might happen if the controlling process exited before or while we were - * restoring the VT as it would leave the old file-descriptor in a hung-up - * state. In this case let's retry with a fresh handle to the virtual terminal. */ - - /* We do a little dance to avoid having the terminal be available - * for reuse before we've cleaned it up. */ - old_fd = TAKE_FD(s->vtfd); - - vt = session_open_vt(s); - safe_close(old_fd); + /* Handle the same VT hung-up case as in session_restore_vt */ - if (vt >= 0) - r = vt_release(vt, false); + int fd = session_open_vt(s, /* reopen = */ true); + if (fd >= 0) + r = vt_release(fd, /* restore = */ false); } if (r < 0) log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);