illiliti: 6 Initial netbsd support ci: Add NetBSD common/evdev: Decouple os-specific functions common/terminal: Decouple os-specific functions common/drm: Decouple os-specific functions Rename evdev to input 36 files changed, 501 insertions(+), 305 deletions(-)
Implementation and CI part of this patch merged, thanks!
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~kennylevinsen/seatd-devel/patches/29975/mbox | git am -3Learn more about email & git
--- common/drm.c | 15 +++++++++++++++ common/evdev.c | 23 +++++++++++++++++++++++ common/terminal.c | 18 ++++++++++++++++-- include/drm.h | 2 +- include/evdev.h | 2 +- meson.build | 1 + seatd/client.c | 27 +++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 4 deletions(-) diff --git a/common/drm.c b/common/drm.c index 9591dc0..0d8096a 100644 --- a/common/drm.c +++ b/common/drm.c @@ -6,6 +6,11 @@ #include <sys/sysmacros.h> #endif +#if defined(__NetBSD__) +#include <stdlib.h> +#include <sys/stat.h> +#endif + #include "drm.h" // From libdrm @@ -40,6 +45,16 @@ int path_is_drm(const char *path) { static const int prefixlen = STRLEN(prefix); return strncmp(prefix, path, prefixlen) == 0; } +#elif defined(__NetBSD__) +int path_is_drm(const char *path) { + static const char prefix[] = "/dev/dri/"; + static const int prefixlen = STRLEN(prefix); + return strncmp(prefix, path, prefixlen) == 0; +} + +int dev_is_drm(dev_t device) { + return major(device) == getdevmajor("drm", S_IFCHR); +} #else #error Unsupported platform #endif diff --git a/common/evdev.c b/common/evdev.c index 4aff9bc..40acf29 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,6 +9,9 @@ #include <sys/sysmacros.h> #elif defined(__FreeBSD__) #include <dev/evdev/input.h> +#elif defined(__NetBSD__) +#include <stdlib.h> +#include <sys/stat.h> #else #error Unsupported platform #endif @@ -17,6 +20,7 @@ #define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) +#if defined(__linux__) || defined(__FreeBSD__) int path_is_evdev(const char *path) { static const char prefix[] = "/dev/input/event"; static const size_t prefixlen = STRLEN(prefix); @@ -26,9 +30,28 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } +#endif #if defined(__linux__) int dev_is_evdev(dev_t device) { return major(device) == INPUT_MAJOR; } +#elif defined(__NetBSD__) +int dev_is_evdev(dev_t device) { + return major(device) == getdevmajor("wskbd", S_IFCHR) || + major(device) == getdevmajor("wsmouse", S_IFCHR) || + major(device) == getdevmajor("wsmux", S_IFCHR); +} +int path_is_evdev(const char *path) { + const char *wskbd = "/dev/wskbd"; + const char *wsmouse = "/dev/wsmouse"; + const char *wsmux = "/dev/wsmux"; + return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || + strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || + strncmp(path, wsmux, STRLEN(wsmouse)) == 0; +} +int evdev_revoke(int fd) { + (void)fd; + return 0; +} #endif diff --git a/common/terminal.c b/common/terminal.c index 0c3466f..183c9bd 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,6 +21,11 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO +#elif defined(__NetBSD__) +#include <dev/wscons/wsdisplay_usl_io.h> +#define K_ENABLE K_XLATE +#define K_DISABLE K_RAW +#define FRSIG 0 // unimplemented #else #error Unsupported platform #endif @@ -134,6 +139,14 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { } return 0; } +#elif defined(__NetBSD__) +static int get_tty_path(int tty, char path[static TTYPATHLEN]) { + assert(tty >= 0); + if (snprintf(path, TTYPATHLEN, "/dev/ttyE%d", tty) == -1) { + return -1; + } + return 0; +} #else #error Unsupported platform #endif @@ -153,7 +166,7 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) struct vt_stat st; int res = ioctl(fd, VT_GETSTATE, &st); close(fd); @@ -231,12 +244,13 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); +#if defined(__linux__) || defined(__NetBSD__) if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } -#if defined(__FreeBSD__) +#elif defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { log_errorf("Could not set get terminal mode: %s", strerror(errno)); diff --git a/include/drm.h b/include/drm.h index 8a7fb10..c8c3eeb 100644 --- a/include/drm.h +++ b/include/drm.h @@ -5,7 +5,7 @@ int drm_set_master(int fd); int drm_drop_master(int fd); int path_is_drm(const char *path); -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) #include <sys/types.h> int dev_is_drm(dev_t device); #endif diff --git a/include/evdev.h b/include/evdev.h index 6ebd943..da57828 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -4,7 +4,7 @@ int evdev_revoke(int fd); int path_is_evdev(const char *path); -#if defined(__linux__) +#if defined(__linux__) || defined(__NetBSD__) #include <sys/types.h> int dev_is_evdev(dev_t device); #endif diff --git a/meson.build b/meson.build index e6e583d..0f267a6 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,7 @@ add_project_arguments( [ '-D_XOPEN_SOURCE=700', '-D__BSD_VISIBLE', + '-D_NETBSD_SOURCE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), diff --git a/seatd/client.c b/seatd/client.c index 6b6f3b3..0097792 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -14,6 +14,10 @@ #include <sys/un.h> #endif +#if defined(__NetBSD__) +#include <sys/un.h> +#endif + #include "client.h" #include "linked_list.h" #include "log.h" @@ -34,6 +38,23 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *uid = cred.uid; *gid = cred.gid; return 0; +#elif defined(__NetBSD__) + struct unpcbid cred; + socklen_t len = sizeof cred; + if (getsockopt(fd, 0, LOCAL_PEEREID, &cred, &len) == -1) { + // assume builtin backend + if (errno == EINVAL) { + *pid = getpid(); + *uid = getuid(); + *gid = getgid(); + return 0; + } + return -1; + } + *pid = cred.unp_pid; + *uid = cred.unp_euid; + *gid = cred.unp_egid; + return 0; #elif defined(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; @@ -468,7 +489,13 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { goto fail; } if (len == 0) { +// https://man.netbsd.org/poll.2 +// Sockets produce POLLIN rather than POLLHUP when the remote end is closed. +#if defined(__NetBSD__) + log_info("Client disconnected"); +#else log_error("Could not read client connection: zero-length read"); +#endif goto fail; } -- 2.35.1
Would you mind if I started out by merging implementation + CI, leaving the reorganization part for later?
--- .builds/netbsd.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .builds/netbsd.yml diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml new file mode 100644 index 0000000..a676138 --- /dev/null +++ b/.builds/netbsd.yml @@ -0,0 +1,24 @@ +image: netbsd/latest +packages: + - meson +sources: + - https://git.sr.ht/~kennylevinsen/seatd +tasks: + - wscons: | + echo 'wscons=YES' | sudo tee -a /etc/rc.conf + sudo /etc/rc.d/wscons start + sudo /etc/rc.d/ttys restart + - prepare: | + meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled build seatd + - build: | + ninja -C build + - unittest: | + ninja -C build test + - smoketest: | + rm -rf build + meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd + ninja -C build + sudo ninja -C build install + timeout -s SIGKILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/wskbd + - smoketest-builtin: | + timeout -s SIGKILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/wskbd -- 2.35.1
--- common/evdev.c | 55 ++++++++---------------------------------- common/evdev_freebsd.c | 18 ++++++++++++++ common/evdev_linux.c | 18 ++++++++++++++ common/evdev_netbsd.c | 15 ++++++++++++ include/evdev.h | 6 ++--- meson.build | 10 ++++++++ 6 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 common/evdev_freebsd.c create mode 100644 common/evdev_linux.c create mode 100644 common/evdev_netbsd.c diff --git a/common/evdev.c b/common/evdev.c index 40acf29..51d3a7f 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -1,57 +1,22 @@ -#include <stdlib.h> #include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> +#include <stddef.h> -#if defined(__linux__) -#include <linux/input.h> -#include <linux/major.h> -#include <sys/sysmacros.h> -#elif defined(__FreeBSD__) -#include <dev/evdev/input.h> -#elif defined(__NetBSD__) -#include <stdlib.h> -#include <sys/stat.h> +#if defined(__linux__) || defined(__FreeBSD__) +static const char *inputs[] = { "/dev/input/event", NULL }; +#elif defined(__OpenBSD__) || defined(__NetBSD__) +static const char *inputs[] = { "/dev/wskbd", "/dev/wsmux", "/dev/wsmouse", NULL }; #else #error Unsupported platform #endif #include "evdev.h" -#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) - -#if defined(__linux__) || defined(__FreeBSD__) int path_is_evdev(const char *path) { - static const char prefix[] = "/dev/input/event"; - static const size_t prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} - -int evdev_revoke(int fd) { - return ioctl(fd, EVIOCREVOKE, NULL); -} -#endif + for (size_t i = 0; inputs[i]; i++) { + if (strncmp(path, inputs[i], strlen(inputs[i])) == 0) { + return 1; + } + } -#if defined(__linux__) -int dev_is_evdev(dev_t device) { - return major(device) == INPUT_MAJOR; -} -#elif defined(__NetBSD__) -int dev_is_evdev(dev_t device) { - return major(device) == getdevmajor("wskbd", S_IFCHR) || - major(device) == getdevmajor("wsmouse", S_IFCHR) || - major(device) == getdevmajor("wsmux", S_IFCHR); -} -int path_is_evdev(const char *path) { - const char *wskbd = "/dev/wskbd"; - const char *wsmouse = "/dev/wsmouse"; - const char *wsmux = "/dev/wsmux"; - return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || - strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || - strncmp(path, wsmux, STRLEN(wsmouse)) == 0; -} -int evdev_revoke(int fd) { - (void)fd; return 0; } -#endif diff --git a/common/evdev_freebsd.c b/common/evdev_freebsd.c new file mode 100644 index 0000000..c2dcd02 --- /dev/null +++ b/common/evdev_freebsd.c @@ -0,0 +1,18 @@ +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/param.h> +#include <dev/evdev/input.h> + +#include "evdev.h" + +int evdev_revoke(int fd) { + return ioctl(fd, EVIOCREVOKE, NULL); +} + +int dev_is_evdev(dev_t device) { + char devname[SPECNAMELEN]; + // devname_r always succeds + devname_r(device, S_IFCHR, devname ,sizeof(devname)); + return strncmp(devname, "event/", 6) == 0; +} diff --git a/common/evdev_linux.c b/common/evdev_linux.c new file mode 100644 index 0000000..2c4a15b --- /dev/null +++ b/common/evdev_linux.c @@ -0,0 +1,18 @@ +#include <stddef.h> +#include <linux/input.h> +#include <linux/major.h> +#include <sys/sysmacros.h> + +#include "evdev.h" + +#ifndef INPUT_MAJOR +#define INPUT_MAJOR 13 +#endif + +int evdev_revoke(int fd) { + return ioctl(fd, EVIOCREVOKE, NULL); +} + +int dev_is_evdev(dev_t device) { + return major(device) == INPUT_MAJOR; +} diff --git a/common/evdev_netbsd.c b/common/evdev_netbsd.c new file mode 100644 index 0000000..f98298a --- /dev/null +++ b/common/evdev_netbsd.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <sys/stat.h> + +#include "evdev.h" + +int evdev_revoke(int fd) { + (void)fd; + return 0; +} + +int dev_is_evdev(dev_t device) { + return major(device) == getdevmajor("wskbd", S_IFCHR) || + major(device) == getdevmajor("wsmouse", S_IFCHR) || + major(device) == getdevmajor("wsmux", S_IFCHR); +} diff --git a/include/evdev.h b/include/evdev.h index da57828..d9eb503 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -1,12 +1,10 @@ +#include <sys/types.h> + #ifndef _SEATD_EVDEV_H #define _SEATD_EVDEV_H int evdev_revoke(int fd); int path_is_evdev(const char *path); - -#if defined(__linux__) || defined(__NetBSD__) -#include <sys/types.h> int dev_is_evdev(dev_t device); -#endif #endif diff --git a/meson.build b/meson.build index 0f267a6..21f1095 100644 --- a/meson.build +++ b/meson.build @@ -120,6 +120,16 @@ server_files = [ 'seatd/server.c', ] +if host_machine.system() == 'netbsd' + server_files += 'common/evdev_netbsd.c' +elif host_machine.system() == 'linux' + server_files += 'common/evdev_linux.c' +elif host_machine.system() == 'freebsd' + server_files += 'common/evdev_freebsd.c' +else + error('Unsupported platform') +endif + with_seatd = get_option('libseat-seatd') == 'enabled' with_builtin = get_option('libseat-builtin') == 'enabled' with_server = get_option('server') == 'enabled' -- 2.35.1
--- common/terminal.c | 180 +------------------------------------- common/terminal_freebsd.c | 129 +++++++++++++++++++++++++++ common/terminal_linux.c | 33 +++++++ common/terminal_netbsd.c | 33 +++++++ include/terminal.h | 29 ++++++ meson.build | 3 + 6 files changed, 231 insertions(+), 176 deletions(-) create mode 100644 common/terminal_freebsd.c create mode 100644 common/terminal_linux.c create mode 100644 common/terminal_netbsd.c diff --git a/common/terminal.c b/common/terminal.c index 183c9bd..c1998c0 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -1,156 +1,14 @@ -#include <assert.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 K_ENABLE K_UNICODE -#define K_DISABLE K_OFF -#define FRSIG 0 -#elif defined(__FreeBSD__) -#include <sys/consio.h> -#include <sys/kbio.h> -#include <termios.h> -#define K_ENABLE K_XLATE -#define K_DISABLE K_RAW -#define FRSIG SIGIO -#elif defined(__NetBSD__) -#include <dev/wscons/wsdisplay_usl_io.h> -#define K_ENABLE K_XLATE -#define K_DISABLE K_RAW -#define FRSIG 0 // unimplemented -#else -#error Unsupported platform -#endif +#include <limits.h> #include "log.h" #include "terminal.h" -#define TTYPATHLEN 16 - -#if defined(__FreeBSD__) -static int get_tty_path(int tty, char path[static TTYPATHLEN]) { - assert(tty >= 0); - - const char prefix[] = "/dev/ttyv"; - const size_t prefix_len = sizeof(prefix) - 1; - strcpy(path, prefix); - - // The FreeBSD VT_GETACTIVE is implemented in the kernel as follows: - // - // static int - // vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, - // struct thread *td) - // { - // struct vt_window *vw = tm->tm_softc; - // struct vt_device *vd = vw->vw_device; - // ... - // switch (cmd) { - // ... - // case VT_GETACTIVE: - // *(int *)data = vd->vd_curwindow->vw_number + 1; - // return (0); - // ... - // } - // ... - // } - // - // The side-effect here being that the returned VT number is one - // greater than the internal VT number. The internal number is what is - // used to number the TTY device, while the external number is what we - // use in e.g. VT switching. - // - // We subtract one from the requested TTY number to compensate. If the - // user asked for TTY 0 (which is special on Linux), we just give them - // the first tty. - - if (tty > 0) { - tty--; - } - - // The FreeBSD tty name is constructed in the kernel as follows: - // - // static void - // vtterm_cnprobe(struct terminal *tm, struct consdev *cp) - // { - // ... - // struct vt_window *vw = tm->tm_softc; - // ... - // sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); - // ... - // } - // - // With %r being a FreeBSD-internal radix formatter (seemingly set to - // base 32), and VT_UNIT expanding to the following to extract the - // internal VT number (which is one less than the external VT number): - // - // ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + (vw)->vw_number) - // - // As the %r formatter is kernel-internal, we implement the base 32 - // encoding ourselves below. - - size_t offset = prefix_len; - if (tty == 0) { - path[offset++] = '0'; - path[offset++] = '\0'; - return 0; - } - - const int base = 32; - for (int remaining = tty; remaining > 0; remaining /= base, offset++) { - // Return early if the buffer is too small. - if (offset + 1 >= TTYPATHLEN) { - errno = ENOMEM; - return -1; - } - - const int value = remaining % 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 0; -} -#elif defined(__linux__) -static int get_tty_path(int tty, char path[static TTYPATHLEN]) { - assert(tty >= 0); - if (snprintf(path, TTYPATHLEN, "/dev/tty%d", tty) == -1) { - return -1; - } - return 0; -} -#elif defined(__NetBSD__) -static int get_tty_path(int tty, char path[static TTYPATHLEN]) { - assert(tty >= 0); - if (snprintf(path, TTYPATHLEN, "/dev/ttyE%d", tty) == -1) { - return -1; - } - return 0; -} -#else -#error Unsupported platform -#endif - int terminal_open(int vt) { char path[TTYPATHLEN]; if (get_tty_path(vt, path) == -1) { @@ -166,18 +24,8 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) || defined(__NetBSD__) - struct vt_stat st; - int res = ioctl(fd, VT_GETSTATE, &st); - close(fd); - if (res == -1) { - log_errorf("Could not retrieve VT state: %s", strerror(errno)); - return -1; - } - return st.v_active; -#elif defined(__FreeBSD__) int vt; - int res = ioctl(fd, VT_GETACTIVE, &vt); + int res = get_current_vt(fd, &vt); close(fd); if (res == -1) { log_errorf("Could not retrieve VT state: %s", strerror(errno)); @@ -189,9 +37,6 @@ int terminal_current_vt(int fd) { return -1; } return vt; -#else -#error Unsupported platform -#endif } int terminal_set_process_switching(int fd, bool enable) { @@ -244,29 +89,12 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); -#if defined(__linux__) || defined(__NetBSD__) - if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { + + if (set_keyboard_mode(fd, enable) == -1) { log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } -#elif defined(__FreeBSD__) - struct termios tios; - if (tcgetattr(fd, &tios) == -1) { - log_errorf("Could not set get terminal mode: %s", strerror(errno)); - return -1; - } - if (enable) { - cfmakesane(&tios); - } else { - cfmakeraw(&tios); - } - if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) { - log_errorf("Could not set terminal mode to %s: %s", enable ? "sane" : "raw", - strerror(errno)); - return -1; - } -#endif return 0; } diff --git a/common/terminal_freebsd.c b/common/terminal_freebsd.c new file mode 100644 index 0000000..6137ed3 --- /dev/null +++ b/common/terminal_freebsd.c @@ -0,0 +1,129 @@ +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <limits.h> +#include <sys/consio.h> +#include <sys/kbio.h> +#include <termios.h> + +#include "terminal.h" + +int get_tty_path(int tty, char path[static TTYPATHLEN]) { + assert(tty >= 0); + + const char prefix[] = "/dev/ttyv"; + const size_t prefix_len = sizeof(prefix) - 1; + strcpy(path, prefix); + + // The FreeBSD VT_GETACTIVE is implemented in the kernel as follows: + // + // static int + // vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data, + // struct thread *td) + // { + // struct vt_window *vw = tm->tm_softc; + // struct vt_device *vd = vw->vw_device; + // ... + // switch (cmd) { + // ... + // case VT_GETACTIVE: + // *(int *)data = vd->vd_curwindow->vw_number + 1; + // return (0); + // ... + // } + // ... + // } + // + // The side-effect here being that the returned VT number is one + // greater than the internal VT number. The internal number is what is + // used to number the TTY device, while the external number is what we + // use in e.g. VT switching. + // + // We subtract one from the requested TTY number to compensate. If the + // user asked for TTY 0 (which is special on Linux), we just give them + // the first tty. + + if (tty > 0) { + tty--; + } + + // The FreeBSD tty name is constructed in the kernel as follows: + // + // static void + // vtterm_cnprobe(struct terminal *tm, struct consdev *cp) + // { + // ... + // struct vt_window *vw = tm->tm_softc; + // ... + // sprintf(cp->cn_name, "ttyv%r", VT_UNIT(vw)); + // ... + // } + // + // With %r being a FreeBSD-internal radix formatter (seemingly set to + // base 32), and VT_UNIT expanding to the following to extract the + // internal VT number (which is one less than the external VT number): + // + // ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + (vw)->vw_number) + // + // As the %r formatter is kernel-internal, we implement the base 32 + // encoding ourselves below. + + size_t offset = prefix_len; + if (tty == 0) { + path[offset++] = '0'; + path[offset++] = '\0'; + return 0; + } + + const int base = 32; + for (int remaining = tty; remaining > 0; remaining /= base, offset++) { + // Return early if the buffer is too small. + if (offset + 1 >= TTYPATHLEN) { + errno = ENOMEM; + return -1; + } + + const int value = remaining % 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 0; +} + +int get_current_vt(int fd, int *vt) { + int res = ioctl(fd, VT_GETACTIVE, vt); + int save_errno = errno; + close(fd); + errno = save_errno; + return res; +} + +int set_keyboard_mode(int fd, bool enable) { + struct termios tios; + if (tcgetattr(fd, &tios) == -1) { + return -1; + } + if (enable) { + cfmakesane(&tios); + } else { + cfmakeraw(&tios); + } + return tcsetattr(fd, TCSAFLUSH, &tios); +} diff --git a/common/terminal_linux.c b/common/terminal_linux.c new file mode 100644 index 0000000..1c679cb --- /dev/null +++ b/common/terminal_linux.c @@ -0,0 +1,33 @@ +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <limits.h> + +#include "terminal.h" + +int get_tty_path(int tty, char path[static TTYPATHLEN]) { + assert(tty >= 0); + snprintf(path, TTYPATHLEN, "/dev/tty%d", tty); + return 0; +} + +int get_current_vt(int fd, int *vt) { + struct vt_stat st; + int res = ioctl(fd, VT_GETSTATE, &st); + int save_errno = errno; + close(fd); + errno = save_errno; + if (res == -1) { + return -1; + } + *vt = st.v_active; + return 0; +} + +int set_keyboard_mode(int fd, bool enable) { + return ioctl(fd, KDSKBMODE, enable ? K_UNICODE : K_OFF); +} diff --git a/common/terminal_netbsd.c b/common/terminal_netbsd.c new file mode 100644 index 0000000..0c8cca2 --- /dev/null +++ b/common/terminal_netbsd.c @@ -0,0 +1,33 @@ +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <limits.h> +#include <dev/wscons/wsdisplay_usl_io.h> + +#include "terminal.h" + +int get_tty_path(int tty, char path[static TTYPATHLEN]) { + assert(tty >= 0); + snprintf(path, TTYPATHLEN, "/dev/ttyE%d", tty); + return 0; +} + +int get_current_vt(int fd, int *vt) { + struct vt_stat st; + int res = ioctl(fd, VT_GETSTATE, &st); + int save_errno = errno; + close(fd); + errno = save_errno; + if (res == -1) { + return -1; + } + *vt = st.v_active; + return 0; +} + +int set_keyboard_mode(int fd, bool enable) { + return ioctl(fd, KDSKBMODE, enable ? K_XLATE : K_RAW); +} diff --git a/include/terminal.h b/include/terminal.h index fb46ce3..31ff8c6 100644 --- a/include/terminal.h +++ b/include/terminal.h @@ -2,6 +2,30 @@ #define _SEATD_TERMINAL_H #include <stdbool.h> +#include <limits.h> +#include <signal.h> + +#ifndef TTY_NAME_MAX +#define TTY_NAME_MAX (16 + 1) +#endif + +#define TTYPATHLEN ((sizeof("/dev/") - 1) + TTY_NAME_MAX) + +#if defined(__linux__) +#include <linux/kd.h> +#include <linux/vt.h> +#define FRSIG 0 +#elif defined(__FreeBSD__) +#include <sys/consio.h> +#include <sys/kbio.h> +#include <termios.h> +#define FRSIG SIGIO +#elif defined(__NetBSD__) +#include <dev/wscons/wsdisplay_usl_io.h> +#define FRSIG 0 +#else +#error Unsupported platform +#endif int terminal_open(int vt); @@ -13,4 +37,9 @@ int terminal_ack_acquire(int fd); int terminal_set_keyboard(int fd, bool enable); int terminal_set_graphics(int fd, bool enable); +// internal +int get_tty_path(int tty, char path[static TTYPATHLEN]); +int get_current_vt(int fd, int *vt); +int set_keyboard_mode(int fd, bool enable); + #endif diff --git a/meson.build b/meson.build index 21f1095..49dd49b 100644 --- a/meson.build +++ b/meson.build @@ -122,10 +122,13 @@ server_files = [ if host_machine.system() == 'netbsd' server_files += 'common/evdev_netbsd.c' + server_files += 'common/terminal_netbsd.c' elif host_machine.system() == 'linux' server_files += 'common/evdev_linux.c' + server_files += 'common/terminal_linux.c' elif host_machine.system() == 'freebsd' server_files += 'common/evdev_freebsd.c' + server_files += 'common/terminal_freebsd.c' else error('Unsupported platform') endif -- 2.35.1
--- common/drm.c | 53 +++++++++++++------------------------------- common/drm_freebsd.c | 13 +++++++++++ common/drm_linux.c | 12 ++++++++++ common/drm_netbsd.c | 8 +++++++ include/drm.h | 6 ++--- meson.build | 3 +++ 6 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 common/drm_freebsd.c create mode 100644 common/drm_linux.c create mode 100644 common/drm_netbsd.c diff --git a/common/drm.c b/common/drm.c index 0d8096a..dbe24e8 100644 --- a/common/drm.c +++ b/common/drm.c @@ -1,26 +1,25 @@ +#include <stddef.h> #include <string.h> #include <sys/ioctl.h> -#include <sys/types.h> -#if defined(__linux__) -#include <sys/sysmacros.h> -#endif +#include "drm.h" -#if defined(__NetBSD__) -#include <stdlib.h> -#include <sys/stat.h> +#if defined(__linux__) || defined(__NetBSD__) +static const char *drms[] = { "/dev/dri/", NULL }; +#elif defined(__OpenBSD__) +static const char *drms[] = { "/dev/drm", NULL }; +#elif defined(__FreeBSD__) +static const char *drms[] = { "/dev/dri/", "/dev/drm/", NULL }; +#else +#error Unsupported platform #endif -#include "drm.h" - // From libdrm #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE, nr) #define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) #define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) -#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) - int drm_set_master(int fd) { return ioctl(fd, DRM_IOCTL_SET_MASTER, 0); } @@ -29,32 +28,12 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) int path_is_drm(const char *path) { - static const char prefix[] = "/dev/dri/"; - static const int prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} + for (size_t i = 0; drms[i]; i++) { + if (strncmp(path, drms[i], strlen(drms[i])) == 0) { + return 1; + } + } -int dev_is_drm(dev_t device) { - return major(device) == 226; + return 0; } -#elif defined(__FreeBSD__) -int path_is_drm(const char *path) { - static const char prefix[] = "/dev/drm/"; - static const int prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} -#elif defined(__NetBSD__) -int path_is_drm(const char *path) { - static const char prefix[] = "/dev/dri/"; - static const int prefixlen = STRLEN(prefix); - return strncmp(prefix, path, prefixlen) == 0; -} - -int dev_is_drm(dev_t device) { - return major(device) == getdevmajor("drm", S_IFCHR); -} -#else -#error Unsupported platform -#endif diff --git a/common/drm_freebsd.c b/common/drm_freebsd.c new file mode 100644 index 0000000..aa5b710 --- /dev/null +++ b/common/drm_freebsd.c @@ -0,0 +1,13 @@ +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include "drm.h" + +int dev_is_drm(dev_t device) { + char devname[SPECNAMELEN]; + // devname_r always succeds + devname_r(device, S_IFCHR, devname, sizeof(devname)); + return strncmp(devname, "dri/", 4) == 0 || strncmp(devname, "drm/", 4) == 0; +} diff --git a/common/drm_linux.c b/common/drm_linux.c new file mode 100644 index 0000000..c6f9c79 --- /dev/null +++ b/common/drm_linux.c @@ -0,0 +1,12 @@ +#include <linux/major.h> +#include <sys/sysmacros.h> + +#include "drm.h" + +#ifndef DRM_MAJOR +#define DRM_MAJOR 226 +#endif + +int dev_is_drm(dev_t device) { + return major(device) == DRM_MAJOR; +} diff --git a/common/drm_netbsd.c b/common/drm_netbsd.c new file mode 100644 index 0000000..911c381 --- /dev/null +++ b/common/drm_netbsd.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <sys/stat.h> + +#include "drm.h" + +int dev_is_drm(dev_t device) { + return major(device) == getdevmajor("drm", S_IFCHR); +} diff --git a/include/drm.h b/include/drm.h index c8c3eeb..7d72bf2 100644 --- a/include/drm.h +++ b/include/drm.h @@ -1,13 +1,11 @@ +#include <sys/types.h> + #ifndef _SEATD_DRM_H #define _SEATD_DRM_H int drm_set_master(int fd); int drm_drop_master(int fd); int path_is_drm(const char *path); - -#if defined(__linux__) || defined(__NetBSD__) -#include <sys/types.h> int dev_is_drm(dev_t device); -#endif #endif diff --git a/meson.build b/meson.build index 49dd49b..f64d20a 100644 --- a/meson.build +++ b/meson.build @@ -121,12 +121,15 @@ server_files = [ ] if host_machine.system() == 'netbsd' + server_files += 'common/drm_netbsd.c' server_files += 'common/evdev_netbsd.c' server_files += 'common/terminal_netbsd.c' elif host_machine.system() == 'linux' + server_files += 'common/drm_linux.c' server_files += 'common/evdev_linux.c' server_files += 'common/terminal_linux.c' elif host_machine.system() == 'freebsd' + server_files += 'common/drm_freebsd.c' server_files += 'common/evdev_freebsd.c' server_files += 'common/terminal_freebsd.c' else -- 2.35.1
--- common/{evdev.c => input.c} | 4 ++-- common/{evdev_freebsd.c => input_freebsd.c} | 6 +++--- common/{evdev_linux.c => input_linux.c} | 6 +++--- common/{evdev_netbsd.c => input_netbsd.c} | 6 +++--- include/evdev.h | 10 ---------- include/input.h | 10 ++++++++++ include/libseat.h | 2 +- include/seat.h | 2 +- meson.build | 8 ++++---- seatd/seat.c | 16 ++++++++-------- 10 files changed, 35 insertions(+), 35 deletions(-) rename common/{evdev.c => input.c} (88%) rename common/{evdev_freebsd.c => input_freebsd.c} (80%) rename common/{evdev_linux.c => input_linux.c} (74%) rename common/{evdev_netbsd.c => input_netbsd.c} (74%) delete mode 100644 include/evdev.h create mode 100644 include/input.h diff --git a/common/evdev.c b/common/input.c similarity index 88% rename from common/evdev.c rename to common/input.c index 51d3a7f..f102f26 100644 --- a/common/evdev.c +++ b/common/input.c @@ -9,9 +9,9 @@ static const char *inputs[] = { "/dev/wskbd", "/dev/wsmux", "/dev/wsmouse", NULL #error Unsupported platform #endif -#include "evdev.h" +#include "input.h" -int path_is_evdev(const char *path) { +int path_is_input(const char *path) { for (size_t i = 0; inputs[i]; i++) { if (strncmp(path, inputs[i], strlen(inputs[i])) == 0) { return 1; diff --git a/common/evdev_freebsd.c b/common/input_freebsd.c similarity index 80% rename from common/evdev_freebsd.c rename to common/input_freebsd.c index c2dcd02..be8309c 100644 --- a/common/evdev_freebsd.c +++ b/common/input_freebsd.c @@ -4,13 +4,13 @@ #include <sys/param.h> #include <dev/evdev/input.h> -#include "evdev.h" +#include "input.h" -int evdev_revoke(int fd) { +int input_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -int dev_is_evdev(dev_t device) { +int dev_is_input(dev_t device) { char devname[SPECNAMELEN]; // devname_r always succeds devname_r(device, S_IFCHR, devname ,sizeof(devname)); diff --git a/common/evdev_linux.c b/common/input_linux.c similarity index 74% rename from common/evdev_linux.c rename to common/input_linux.c index 2c4a15b..2264cd0 100644 --- a/common/evdev_linux.c +++ b/common/input_linux.c @@ -3,16 +3,16 @@ #include <linux/major.h> #include <sys/sysmacros.h> -#include "evdev.h" +#include "input.h" #ifndef INPUT_MAJOR #define INPUT_MAJOR 13 #endif -int evdev_revoke(int fd) { +int input_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -int dev_is_evdev(dev_t device) { +int dev_is_input(dev_t device) { return major(device) == INPUT_MAJOR; } diff --git a/common/evdev_netbsd.c b/common/input_netbsd.c similarity index 74% rename from common/evdev_netbsd.c rename to common/input_netbsd.c index f98298a..0c761ae 100644 --- a/common/evdev_netbsd.c +++ b/common/input_netbsd.c @@ -1,14 +1,14 @@ #include <stdlib.h> #include <sys/stat.h> -#include "evdev.h" +#include "input.h" -int evdev_revoke(int fd) { +int input_revoke(int fd) { (void)fd; return 0; } -int dev_is_evdev(dev_t device) { +int dev_is_input(dev_t device) { return major(device) == getdevmajor("wskbd", S_IFCHR) || major(device) == getdevmajor("wsmouse", S_IFCHR) || major(device) == getdevmajor("wsmux", S_IFCHR); diff --git a/include/evdev.h b/include/evdev.h deleted file mode 100644 index d9eb503..0000000 --- a/include/evdev.h @@ -1,10 +0,0 @@ -#include <sys/types.h> - -#ifndef _SEATD_EVDEV_H -#define _SEATD_EVDEV_H - -int evdev_revoke(int fd); -int path_is_evdev(const char *path); -int dev_is_evdev(dev_t device); - -#endif diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..146f587 --- /dev/null +++ b/include/input.h @@ -0,0 +1,10 @@ +#include <sys/types.h> + +#ifndef _SEATD_INPUT_H +#define _SEATD_INPUT_H + +int input_revoke(int fd); +int path_is_input(const char *path); +int dev_is_input(dev_t device); + +#endif diff --git a/include/libseat.h b/include/libseat.h index 385acd9..60c9f8d 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -80,7 +80,7 @@ int libseat_close_seat(struct libseat *seat); * the specified pointer. * * This will only succeed if the seat is active and the device is of a type - * permitted for opening on the backend, such as drm and evdev. + * permitted for opening on the backend, such as drm and input. * * The device may be revoked in some situations, such as in situations where a * seat session switch is being forced. diff --git a/include/seat.h b/include/seat.h index cc243b6..ca9dd3e 100644 --- a/include/seat.h +++ b/include/seat.h @@ -11,7 +11,7 @@ struct client; enum seat_device_type { SEAT_DEVICE_TYPE_NORMAL, - SEAT_DEVICE_TYPE_EVDEV, + SEAT_DEVICE_TYPE_INPUT, SEAT_DEVICE_TYPE_DRM, }; diff --git a/meson.build b/meson.build index f64d20a..83fc21a 100644 --- a/meson.build +++ b/meson.build @@ -112,7 +112,7 @@ server_files = [ 'common/linked_list.c', 'common/terminal.c', 'common/connection.c', - 'common/evdev.c', + 'common/input.c', 'common/drm.c', 'seatd/poller.c', 'seatd/seat.c', @@ -122,15 +122,15 @@ server_files = [ if host_machine.system() == 'netbsd' server_files += 'common/drm_netbsd.c' - server_files += 'common/evdev_netbsd.c' + server_files += 'common/input_netbsd.c' server_files += 'common/terminal_netbsd.c' elif host_machine.system() == 'linux' server_files += 'common/drm_linux.c' - server_files += 'common/evdev_linux.c' + server_files += 'common/input_linux.c' server_files += 'common/terminal_linux.c' elif host_machine.system() == 'freebsd' server_files += 'common/drm_freebsd.c' - server_files += 'common/evdev_freebsd.c' + server_files += 'common/input_freebsd.c' server_files += 'common/terminal_freebsd.c' else error('Unsupported platform') diff --git a/seatd/seat.c b/seatd/seat.c index 354273f..545339d 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -11,7 +11,7 @@ #include "client.h" #include "drm.h" -#include "evdev.h" +#include "input.h" #include "linked_list.h" #include "log.h" #include "protocol.h" @@ -231,8 +231,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { } enum seat_device_type type; - if (path_is_evdev(sanitized_path)) { - type = SEAT_DEVICE_TYPE_EVDEV; + if (path_is_input(sanitized_path)) { + type = SEAT_DEVICE_TYPE_INPUT; } else if (path_is_drm(sanitized_path)) { type = SEAT_DEVICE_TYPE_DRM; } else { @@ -278,7 +278,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { log_errorf("Could not make device fd drm master: %s", strerror(errno)); } break; - case SEAT_DEVICE_TYPE_EVDEV: + case SEAT_DEVICE_TYPE_INPUT: // Nothing to do here break; default: @@ -327,9 +327,9 @@ static int seat_deactivate_device(struct seat_device *seat_device) { return -1; } break; - case SEAT_DEVICE_TYPE_EVDEV: - if (evdev_revoke(seat_device->fd) == -1) { - log_errorf("Could not revoke evdev on device fd: %s", strerror(errno)); + case SEAT_DEVICE_TYPE_INPUT: + if (input_revoke(seat_device->fd) == -1) { + log_errorf("Could not revoke input on device fd: %s", strerror(errno)); return -1; } break; @@ -379,7 +379,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ } seat_device->active = true; break; - case SEAT_DEVICE_TYPE_EVDEV: + case SEAT_DEVICE_TYPE_INPUT: errno = EINVAL; return -1; default: -- 2.35.1