aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenny Levinsen <kl@kl.wtf>2020-08-02 20:21:19 +0200
committerKenny Levinsen <kl@kl.wtf>2020-08-02 21:46:10 +0200
commitb751481e5c0bed1b81b7c769923e772e9fd84e9d (patch)
treea08c88eb9b3755afb9b9ba70535ef98944de9301
parentb731b18e0a086e65aa25ed2a5e53488076f5ad37 (diff)
seat: Open/close tty on activation/deactivation
The VT and KD ioctl's are picky about the tty fd used. In order to satisfy these, and to improve state cleanup, we now only and store the current tty when opening a client, and use this fd to perform teardown later. The presence of the fd is also used to signal that teardown is needed.
-rw-r--r--common/terminal.c191
-rw-r--r--include/seat.h1
-rw-r--r--include/terminal.h13
-rw-r--r--seatd/seat.c105
4 files changed, 128 insertions, 182 deletions
diff --git a/common/terminal.c b/common/terminal.c
index bcd843d..da66143 100644
--- a/common/terminal.c
+++ b/common/terminal.c
@@ -1,27 +1,26 @@
-#include "string.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#if defined(__linux__)
#include <linux/kd.h>
#include <linux/vt.h>
-#define TTY0 "/dev/tty0"
-#define TTYF "/dev/tty%d"
-#define K_ON K_UNICODE
-#define FRSIG 0
+#define TTYF "/dev/tty%d"
+#define K_ENABLE K_UNICODE
+#define K_DISABLE K_OFF
+#define FRSIG 0
#elif defined(__FreeBSD__)
#include <sys/consio.h>
#include <sys/kbio.h>
-#define TTY0 "/dev/ttyv0"
-#define TTYF "/dev/ttyv%d"
-#define K_ON K_XLATE
-#define K_OFF K_CODE
-#define FRSIG SIGIO
+#define TTYF "/dev/ttyv%d"
+#define K_ENABLE K_XLATE
+#define K_DISABLE K_CODE
+#define FRSIG SIGIO
#else
#error Unsupported platform
#endif
@@ -31,13 +30,21 @@
#define TTYPATHLEN 64
-int terminal_current_vt(void) {
- int fd = open(TTY0, O_RDWR | O_NOCTTY);
+int terminal_open(int vt) {
+ char path[TTYPATHLEN];
+ if (snprintf(path, TTYPATHLEN, TTYF, vt) == -1) {
+ log_errorf("could not generate tty path: %s", strerror(errno));
+ return -1;
+ }
+ int fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
- log_errorf("could not open tty0: %s", strerror(errno));
+ log_errorf("could not open target tty: %s", strerror(errno));
return -1;
}
+ return fd;
+}
+int terminal_current_vt(int fd) {
#if defined(__linux__)
struct vt_stat st;
int res = ioctl(fd, VT_GETSTATE, &st);
@@ -61,173 +68,57 @@ int terminal_current_vt(void) {
#endif
}
-int terminal_setup(int vt) {
- log_debugf("setting up vt %d", vt);
- if (vt == -1) {
- vt = 0;
- }
- char path[TTYPATHLEN];
- if (snprintf(path, TTYPATHLEN, TTYF, vt) == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int fd = open(path, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not open target tty: %s", strerror(errno));
- return -1;
- }
-
- static struct vt_mode mode = {
- .mode = VT_PROCESS,
+int terminal_set_process_switching(int fd, bool enable) {
+ log_debug("setting process switching");
+ struct vt_mode mode = {
+ .mode = enable ? VT_PROCESS : VT_AUTO,
.waitv = 0,
- .relsig = SIGUSR1,
- .acqsig = SIGUSR2,
+ .relsig = enable ? SIGUSR1 : 0,
+ .acqsig = enable ? SIGUSR2 : 0,
.frsig = FRSIG,
};
- int res = ioctl(fd, VT_SETMODE, &mode);
- close(fd);
- if (res == -1) {
- log_errorf("could not set VT mode: %s", strerror(errno));
- }
-
- return res;
-}
-
-int terminal_teardown(int vt) {
- log_debugf("tearing down vt %d", vt);
- if (vt == -1) {
- vt = 0;
- }
- char path[TTYPATHLEN];
- if (snprintf(path, TTYPATHLEN, TTYF, vt) == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int fd = open(path, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not open target tty: %s", strerror(errno));
- return -1;
- }
- if (ioctl(fd, KDSETMODE, KD_TEXT) == -1) {
- log_errorf("could not set KD graphics mode: %s", strerror(errno));
- close(fd);
- return -1;
- }
- if (ioctl(fd, KDSKBMODE, K_ON) == -1) {
- log_errorf("could not set KD keyboard mode: %s", strerror(errno));
- close(fd);
- return -1;
- }
-
- static struct vt_mode mode = {
- .mode = VT_PROCESS,
- .waitv = 0,
- .relsig = SIGUSR1,
- .acqsig = SIGUSR2,
- .frsig = FRSIG,
- };
if (ioctl(fd, VT_SETMODE, &mode) == -1) {
log_errorf("could not set VT mode: %s", strerror(errno));
- close(fd);
return -1;
}
-
- close(fd);
return 0;
}
-int terminal_switch_vt(int vt) {
+int terminal_switch_vt(int fd, int vt) {
log_debugf("switching to vt %d", vt);
- int fd = open(TTY0, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not open tty0: %s", strerror(errno));
- return -1;
- }
-
- static struct vt_mode mode = {
- .mode = VT_PROCESS,
- .waitv = 0,
- .relsig = SIGUSR1,
- .acqsig = SIGUSR2,
- .frsig = FRSIG,
- };
-
- if (ioctl(fd, VT_SETMODE, &mode) == -1) {
- log_errorf("could not set VT mode: %s", strerror(errno));
- close(fd);
- return -1;
- }
-
if (ioctl(fd, VT_ACTIVATE, vt) == -1) {
log_errorf("could not activate VT: %s", strerror(errno));
- close(fd);
return -1;
}
- close(fd);
return 0;
}
-int terminal_ack_switch(void) {
+int terminal_ack_switch(int fd) {
log_debug("acking vt switch");
- int fd = open(TTY0, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not open tty0: %s", strerror(errno));
- return -1;
- }
-
- int res = ioctl(fd, VT_RELDISP, VT_ACKACQ);
- close(fd);
- if (res == -1) {
+ if (ioctl(fd, VT_RELDISP, VT_ACKACQ) == -1) {
log_errorf("could not ack VT switch: %s", strerror(errno));
+ return -1;
}
- return res;
+ return 0;
}
-int terminal_set_keyboard(int vt, bool enable) {
- log_debugf("setting KD keyboard state to %d on vt %d", enable, vt);
- if (vt == -1) {
- vt = 0;
- }
- char path[TTYPATHLEN];
- if (snprintf(path, TTYPATHLEN, TTYF, vt) == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int fd = open(path, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int res = ioctl(fd, KDSKBMODE, enable ? K_ON : K_OFF);
- close(fd);
- if (res == -1) {
+int terminal_set_keyboard(int fd, bool enable) {
+ log_debugf("setting KD keyboard state to %d", enable);
+ if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) {
log_errorf("could not set KD keyboard mode: %s", strerror(errno));
+ return -1;
}
- return res;
+ return 0;
}
-int terminal_set_graphics(int vt, bool enable) {
- log_debugf("setting KD graphics state to %d on vt %d", enable, vt);
- if (vt == -1) {
- vt = 0;
- }
- char path[TTYPATHLEN];
- if (snprintf(path, TTYPATHLEN, TTYF, vt) == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int fd = open(path, O_RDWR | O_NOCTTY);
- if (fd == -1) {
- log_errorf("could not generate tty path: %s", strerror(errno));
- return -1;
- }
- int res = ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT);
- close(fd);
- if (res == -1) {
+int terminal_set_graphics(int fd, bool enable) {
+ log_debugf("setting KD graphics state to %d", enable);
+ if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) {
log_errorf("could not set KD graphics mode: %s", strerror(errno));
+ return -1;
}
- return res;
+ return 0;
}
diff --git a/include/seat.h b/include/seat.h
index e0d3533..5a6c273 100644
--- a/include/seat.h
+++ b/include/seat.h
@@ -32,6 +32,7 @@ struct seat {
bool vt_bound;
bool vt_pending_ack;
int next_vt;
+ int curttyfd;
};
struct seat *seat_create(const char *name, bool vt_bound);
diff --git a/include/terminal.h b/include/terminal.h
index c2a49ff..208d6b2 100644
--- a/include/terminal.h
+++ b/include/terminal.h
@@ -3,12 +3,15 @@
#include <stdbool.h>
+int terminal_open(int vt);
+
+int terminal_set_process_switching(int fd, bool enable);
int terminal_setup(int vt);
int terminal_teardown(int vt);
-int terminal_current_vt(void);
-int terminal_switch_vt(int vt);
-int terminal_ack_switch(void);
-int terminal_set_keyboard(int vt, bool enable);
-int terminal_set_graphics(int vt, bool enable);
+int terminal_current_vt(int fd);
+int terminal_switch_vt(int fd, int vt);
+int terminal_ack_switch(int fd);
+int terminal_set_keyboard(int fd, bool enable);
+int terminal_set_graphics(int fd, bool enable);
#endif
diff --git a/seatd/seat.c b/seatd/seat.c
index e876ccf..f9756dc 100644
--- a/seatd/seat.c
+++ b/seatd/seat.c
@@ -25,13 +25,12 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) {
}
list_init(&seat->clients);
seat->vt_bound = vt_bound;
-
+ seat->curttyfd = -1;
seat->seat_name = strdup(seat_name);
if (seat->seat_name == NULL) {
free(seat);
return NULL;
}
-
log_debugf("created seat '%s' (vt_bound: %d)", seat_name, vt_bound);
return seat;
}
@@ -44,6 +43,7 @@ void seat_destroy(struct seat *seat) {
assert(client->seat);
client_kill(client);
}
+ assert(seat->curttyfd == -1);
free(seat->seat_name);
free(seat);
@@ -331,7 +331,18 @@ int seat_open_client(struct seat *seat, struct client *client) {
assert(client);
if (seat->vt_bound && client->seat_vt == 0) {
- client->seat_vt = terminal_current_vt();
+ int tty0fd = terminal_open(0);
+ if (tty0fd == -1) {
+ log_errorf("unable to open tty0: %s", strerror(errno));
+ return -1;
+ }
+ client->seat_vt = terminal_current_vt(tty0fd);
+ close(tty0fd);
+ if (client->seat_vt == -1) {
+ log_errorf("unable to get current VT for client: %s", strerror(errno));
+ client->seat_vt = 0;
+ return -1;
+ }
}
if (seat->active_client != NULL) {
@@ -341,8 +352,16 @@ int seat_open_client(struct seat *seat, struct client *client) {
}
if (seat->vt_bound) {
- terminal_setup(client->seat_vt);
- terminal_set_keyboard(client->seat_vt, false);
+ int ttyfd = terminal_open(client->seat_vt);
+ if (ttyfd == -1) {
+ log_errorf("unable to open tty for vt %d: %s", client->seat_vt,
+ strerror(errno));
+ return -1;
+ }
+ terminal_set_process_switching(ttyfd, true);
+ terminal_set_keyboard(ttyfd, false);
+ terminal_set_graphics(ttyfd, true);
+ seat->curttyfd = ttyfd;
}
for (size_t idx = 0; idx < client->devices.length; idx++) {
@@ -387,17 +406,19 @@ int seat_close_client(struct seat *seat, struct client *client) {
log_debugf("deactivated %zd devices", client->devices.length);
- int vt = seat->active_client->seat_vt;
seat->active_client = NULL;
- if (seat->vt_bound) {
- if (seat->vt_pending_ack) {
- log_debug("acking pending VT switch");
- seat->vt_pending_ack = false;
- terminal_teardown(vt);
- terminal_ack_switch();
- return 0;
- }
+ if (seat->vt_bound && seat->vt_pending_ack) {
+ log_debug("acking pending VT switch");
+ seat->vt_pending_ack = false;
+ assert(seat->curttyfd != -1);
+ terminal_set_process_switching(seat->curttyfd, true);
+ terminal_set_keyboard(seat->curttyfd, true);
+ terminal_set_graphics(seat->curttyfd, false);
+ terminal_ack_switch(seat->curttyfd);
+ close(seat->curttyfd);
+ seat->curttyfd = -1;
+ return 0;
}
seat_activate(seat);
@@ -457,17 +478,31 @@ int seat_activate(struct seat *seat) {
return 0;
}
- // If we're asked to do a simple VT switch, do that
- if (seat->vt_bound && seat->next_vt > 0) {
- log_info("executing VT switch");
- terminal_switch_vt(seat->next_vt);
- seat->next_vt = 0;
- return 0;
- }
-
int vt = -1;
if (seat->vt_bound) {
- vt = terminal_current_vt();
+ int ttyfd = terminal_open(0);
+ if (ttyfd == -1) {
+ log_errorf("unable to open tty0: %s", strerror(errno));
+ return -1;
+ }
+
+ // If we're asked to do a simple VT switch, do that
+ if (seat->next_vt > 0) {
+ log_info("executing VT switch");
+ terminal_switch_vt(ttyfd, seat->next_vt);
+ seat->next_vt = 0;
+ close(ttyfd);
+ return 0;
+ }
+
+ // We'll need the VT below
+ vt = terminal_current_vt(ttyfd);
+ if (vt == -1) {
+ log_errorf("unable to get vt: %s", strerror(errno));
+ close(ttyfd);
+ return -1;
+ }
+ close(ttyfd);
}
// Try to pick a client for activation
@@ -492,15 +527,25 @@ int seat_activate(struct seat *seat) {
if (next_client == NULL) {
// No suitable client found
log_info("no client suitable for activation");
- if (seat->vt_bound) {
- terminal_teardown(vt);
+ if (seat->vt_bound && seat->curttyfd != -1) {
+ terminal_set_process_switching(seat->curttyfd, false);
+ terminal_set_keyboard(seat->curttyfd, true);
+ terminal_set_graphics(seat->curttyfd, false);
+ close(seat->curttyfd);
+ seat->curttyfd = -1;
}
return -1;
}
log_info("activating next client");
if (seat->vt_bound && next_client->seat_vt != vt) {
- terminal_switch_vt(next_client->seat_vt);
+ int ttyfd = terminal_open(0);
+ if (ttyfd == -1) {
+ log_errorf("unable to open tty0: %s", strerror(errno));
+ return -1;
+ }
+ terminal_switch_vt(ttyfd, next_client->seat_vt);
+ close(ttyfd);
}
return seat_open_client(seat, next_client);
@@ -511,7 +556,13 @@ int seat_prepare_vt_switch(struct seat *seat) {
if (seat->active_client == NULL) {
log_info("no active client, performing switch immediately");
- terminal_ack_switch();
+ int tty0fd = terminal_open(0);
+ if (tty0fd == -1) {
+ log_errorf("unable to open tty0: %s", strerror(errno));
+ return -1;
+ }
+ terminal_ack_switch(tty0fd);
+ close(tty0fd);
return 0;
}