From fc6c0ca12e941d5d7d567834bff3ab7df9447001 Mon Sep 17 00:00:00 2001 From: Ting-Wei Lan Date: Sat, 7 Dec 2019 22:29:20 +0800 Subject: [PATCH] backend/session/freebsd: Fix the way to get TTY path Previously, the path of TTY is generated using snprintf with %d format. It works with TTY 1 to 10, but fails with TTY with greater number because the number used in the name is in base 32 instead of base 10. Since there is no standard function to convert a number to a string with a custom base, this commit adds a function to do it. Fixes: https://github.com/swaywm/wlroots/issues/1854 --- backend/session/direct-freebsd.c | 50 +++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 238664ac..c6e1f720 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -139,6 +139,51 @@ static int vt_handler(int signo, void *data) { return 1; } +static bool get_tty_path(int tty, char path[static 11], size_t len) { + assert(tty > 0); + + const char prefix[] = "/dev/ttyv"; + static_assert(sizeof(prefix) + 1 <= 11, "TTY path prefix is too long"); + + const size_t prefix_len = sizeof(prefix) - 1; + strcpy(path, prefix); + + size_t offset = prefix_len; + const int num = tty - 1; + if (num == 0) { + path[offset++] = '0'; + path[offset++] = '\0'; + return true; + } + + const int base = 32; + for (int remaning = num; remaning > 0; remaning /= base, offset++) { + // Return early if the buffer is too small. + if (offset + 1 >= len) { + return false; + } + + const int value = remaning % base; + if (value >= 10) { + path[offset] = 'a' + value - 10; + } else { + path[offset] = '0' + value; + } + } + + const size_t num_len = offset - prefix_len; + for (size_t i = 0; i < num_len / 2; i++) { + const size_t p1 = prefix_len + i; + const size_t p2 = offset - 1 - i; + const char tmp = path[p1]; + path[p1] = path[p2]; + path[p2] = tmp; + } + + path[offset++] = '\0'; + return true; +} + static bool setup_tty(struct direct_session *session, struct wl_display *display) { int fd = -1, tty = -1, tty0_fd = -1, old_tty = 1; if ((tty0_fd = open("/dev/ttyv0", O_RDWR | O_CLOEXEC)) < 0) { @@ -155,7 +200,10 @@ static bool setup_tty(struct direct_session *session, struct wl_display *display } close(tty0_fd); char tty_path[64]; - snprintf(tty_path, sizeof(tty_path), "/dev/ttyv%d", tty - 1); + if (!get_tty_path(tty, tty_path, sizeof(tty_path))) { + wlr_log(WLR_ERROR, "Could not get tty %d path", tty); + goto error; + } wlr_log(WLR_INFO, "Using tty %s", tty_path); fd = open(tty_path, O_RDWR | O_NOCTTY | O_CLOEXEC);