From 4091ba2c07efde82a109fa8a07db77c814e90e5c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 15 Sep 2021 23:30:53 +0200 Subject: [PATCH 01/66] ci: Install seatd instead of manipulating PATH --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + .builds/smoketest-seatd.sh | 3 +-- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index adea8ed..20f5fef 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -13,6 +13,7 @@ tasks: meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled -Dexamples=enabled build seatd - build: | ninja -C build + sudo ninja -C build install - unittest: | ninja -C build test - scan-build: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 3e1574b..3f7463c 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -12,6 +12,7 @@ tasks: meson -Db_sanitize=address -Dlibseat-logind=auto -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled build seatd - build: | ninja -C build + sudo ninja -C build install - unittest: | ninja -C build test - scan-build: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 1b4ceba..79bee15 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -14,6 +14,7 @@ tasks: 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 KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index 96f554b..f471928 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -13,7 +13,6 @@ else fi export SEATD_LOGLEVEL=debug -export PATH=$(pwd)/build:$PATH # # Run simpletest a few times # @@ -21,7 +20,7 @@ cnt=0 while [ "$cnt" -lt 2 ] do echo "Simpletest run $((cnt+1))" - if ! sudo -E seatd-launch ./build/simpletest $file + if ! sudo -E ./build/seatd-launch ./build/simpletest $file then echo "Simpletest failed" exit 1 From 907b75de1ae5ec415a99889faecaf05b36bea31e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 15 Sep 2021 23:34:02 +0200 Subject: [PATCH 02/66] seatd-launch: Use absolute path for seatd We previously used execlp to execute seatd, which had the effect of searching PATH for the executable. This allowed the caller to control what executable was run, which is bad if SUID has been set. Instead, expose the absolute install path for seatd from meason as a define, and use that in a call to execv. --- meson.build | 5 ++++- seatd-launch/seatd-launch.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 999380d..b6892c7 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,8 @@ if defaultpath == '' endif endif +seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) + cc = meson.get_compiler('c') add_project_arguments(cc.get_supported_arguments( [ @@ -41,7 +43,8 @@ add_project_arguments(cc.get_supported_arguments( '-D_XOPEN_SOURCE=700', '-D__BSD_VISIBLE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), - '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath) + '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), + '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), ]), language: 'c', ) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index b9d33d7..7b41bb6 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -68,10 +68,11 @@ int main(int argc, char *argv[]) { } else if (seatd_child == 0) { close(fds[0]); - char pipebuf[8]; - sprintf(pipebuf, "%d", fds[1]); + char pipebuf[16] = {0}; + snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]); - execlp("seatd", "seatd", "-n", pipebuf, "-s", sockpath, NULL); + char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, NULL}; + execv(SEATD_INSTALLPATH, command); perror("Could not start seatd"); _exit(1); } From ebf512c2bf74b1286d2f243c2f78daa64114d81d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 16 Sep 2021 00:10:56 +0200 Subject: [PATCH 03/66] seatd-launch: Specify exact environment to seatd The parent environment might contain nasty things. Create a new environment for the seatd process containing only the environment variables we care about. For now, that's only SEATD_LOGLEVEL. --- seatd-launch/seatd-launch.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 7b41bb6..69ca86a 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -71,8 +71,16 @@ int main(int argc, char *argv[]) { char pipebuf[16] = {0}; snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]); + char *env[2] = {NULL, NULL}; + char loglevelbuf[32] = {0}; + char *cur_loglevel = getenv("SEATD_LOGLEVEL"); + if (cur_loglevel != NULL) { + snprintf(loglevelbuf, sizeof loglevelbuf, "SEATD_LOGLEVEL=%s", cur_loglevel); + env[0] = loglevelbuf; + } + char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, NULL}; - execv(SEATD_INSTALLPATH, command); + execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); } From 0f20175752b7b11a5c66070b2dedc4cf8716d107 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 16 Sep 2021 01:07:42 +0200 Subject: [PATCH 04/66] Bump version to 0.6.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b6892c7..e6c80a4 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.1', + version: '0.6.2', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From 2eee9aa445e3f9dc6a7ca115489f87b10f60b9ba Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 20 Sep 2021 23:43:10 +0200 Subject: [PATCH 05/66] seatd: Implement ping request to wake up later When device open or close messages are sent to seatd, libseat must read messages from the socket until it sees the associated response message. This means that it may drain enable/disable seat events from the socket, queueing them internally for deferred processing. As the socket is drained, the caller will not wake from a poll and have no reason to dispatch libseat. To ensure that these messages would not be left in the queue, 6fa82930d0c5660eea3102989c765dc864514e36 made it so that open/close calls would execute all queued events just before returning. Unfortunately, this had the side-effect of having events fire from the stack of libseat_open_device or libseat_close_device, which we now see cause problems in compositors. Specifically, an issue has been observed where libinput end up calling libseat_close_device, which in turn dispatch a disable seat event that calls libinput_suspend. libinput does not like this. Instead, remove the execution from libseat_open_device and libseat_close_device, and instead make a "ping" request to seatd if events have been queued. The response to this will wake us up and ensure that dispatch is called. --- include/protocol.h | 2 ++ libseat/backend/seatd.c | 45 +++++++++++++++++++++++++++++++++++++---- seatd/client.c | 22 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/include/protocol.h b/include/protocol.h index b3361ba..cb994fc 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -15,6 +15,7 @@ #define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4) #define CLIENT_DISABLE_SEAT CLIENT_EVENT(5) #define CLIENT_SWITCH_SESSION CLIENT_EVENT(6) +#define CLIENT_PING CLIENT_EVENT(7) #define SERVER_SEAT_OPENED SERVER_EVENT(1) #define SERVER_SEAT_CLOSED SERVER_EVENT(2) @@ -22,6 +23,7 @@ #define SERVER_DEVICE_CLOSED SERVER_EVENT(4) #define SERVER_DISABLE_SEAT SERVER_EVENT(5) #define SERVER_ENABLE_SEAT SERVER_EVENT(6) +#define SERVER_PONG SERVER_EVENT(7) #define SERVER_ERROR SERVER_EVENT(0x7FFF) #include diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 85df9f5..26308d1 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -36,6 +36,7 @@ struct backend_seatd { const struct libseat_seat_listener *seat_listener; void *seat_listener_data; struct linked_list pending_events; + bool awaiting_pong; bool error; char seat_name[MAX_SEAT_LEN]; @@ -243,6 +244,12 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) { while (connection_get(&backend->connection, &header, sizeof header) != -1) { packets++; switch (header.opcode) { + case SERVER_PONG: + // We care about whether or not the answer has been + // read from the connection, so handle it here instead + // of pushing it to the pending event list. + backend->awaiting_pong = false; + break; case SERVER_DISABLE_SEAT: case SERVER_ENABLE_SEAT: if (queue_event(backend, header.opcode) == -1) { @@ -450,6 +457,36 @@ static const char *seat_name(struct libseat *base) { return backend->seat_name; } +static int send_ping(struct backend_seatd *backend) { + struct proto_header header = { + .opcode = CLIENT_PING, + .size = 0, + }; + if (conn_put(backend, &header, sizeof header) == -1 || conn_flush(backend) == -1) { + return -1; + } + return 0; +} + +static void check_pending_events(struct backend_seatd *backend) { + if (linked_list_empty(&backend->pending_events)) { + return; + } + if (backend->awaiting_pong) { + return; + } + + // We have events pending execution, so a dispatch is required. + // However, we likely already drained our socket, so there will not be + // anything to read. Instead, send a ping request to seatd, so that the + // user will be woken up by its response. + if (send_ping(backend) == -1) { + log_errorf("Could not send ping request: %s", strerror(errno)); + return; + } + backend->awaiting_pong = true; +} + static int open_device(struct libseat *base, const char *path, int *fd) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); if (backend->error) { @@ -481,11 +518,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) { goto error; } - execute_events(backend); + check_pending_events(backend); return rmsg.device_id; error: - execute_events(backend); + check_pending_events(backend); return -1; } @@ -516,11 +553,11 @@ static int close_device(struct libseat *base, int device_id) { goto error; } - execute_events(backend); + check_pending_events(backend); return 0; error: - execute_events(backend); + check_pending_events(backend); return -1; } diff --git a/seatd/client.c b/seatd/client.c index 1bfe94a..220c5d3 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -309,6 +309,20 @@ error: return client_send_error(client, errno); } +static int handle_ping(struct client *client) { + struct proto_header header = { + .opcode = SERVER_PONG, + .size = 0, + }; + + if (connection_put(&client->connection, &header, sizeof header) == -1) { + log_errorf("Could not write response: %s", strerror(errno)); + return -1; + } + + return 0; +} + static int client_handle_opcode(struct client *client, uint16_t opcode, size_t size) { int res = 0; switch (opcode) { @@ -372,6 +386,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s res = handle_disable_seat(client); break; } + case CLIENT_PING: { + if (size != 0) { + log_error("Protocol error: invalid ping message"); + return -1; + } + res = handle_ping(client); + break; + } default: log_errorf("Protocol error: unknown opcode: %d", opcode); res = -1; From db08fb921f8ea13202a487dcea2fdd3914b87dfd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 20 Sep 2021 23:43:11 +0200 Subject: [PATCH 06/66] logind: Send ping to wake us up later sd_bus_call drains received messages into the receive queue, and peeks for its own return value. It does not dispatch the receive queue. As the socket is drained, the caller will not wake from a poll and have no reason to dispatch libseat. This has gone unnoticed largely due to logind sending an event for every device, making it unlikely that no unread message will be left on the socket. Like we have done for seatd, we fix this by sending a "ping" request to logind if anything is left in our receive queue as reported by sd_bus_get_events. The response to this will wake us up and ensure that dispatch is called. --- libseat/backend/logind.c | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index cb809e7..dd050ce 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -41,6 +41,7 @@ struct backend_logind { bool active; bool initial_setup; + bool awaiting_pong; int has_drm; }; @@ -67,6 +68,48 @@ static int close_seat(struct libseat *base) { return 0; } +static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + (void)ret_error; + struct backend_logind *session = userdata; + if (sd_bus_message_is_method_error(m, NULL)) { + const sd_bus_error *error = sd_bus_message_get_error(m); + log_errorf("Ping failed: %s: %s", error->name, error->message); + return -1; + } + session->awaiting_pong = false; + return 0; +} + +static int send_ping(struct backend_logind *backend) { + int ret = sd_bus_call_method_async(backend->bus, NULL, "org.freedesktop.login1", + "/org/freedesktop/login1", "org.freedesktop.DBus.Peer", + "Ping", ping_handler, NULL, ""); + if (ret < 0) { + return ret; + } + return 0; +} + +static void check_pending_events(struct backend_logind *backend) { + if (sd_bus_get_events(backend->bus) <= 0) { + return; + } + if (backend->awaiting_pong) { + return; + } + + // We have events pending execution, so a dispatch is required. + // However, we likely already drained our socket, so there will not be + // anything to read. Instead, send a ping request to logind so that the + // user will be woken up by its response. + int ret = send_ping(backend); + if (ret < 0) { + log_errorf("Could not send ping message: %s", strerror(-ret)); + return; + } + backend->awaiting_pong = true; +} + static int open_device(struct libseat *base, const char *path, int *fd) { struct backend_logind *session = backend_logind_from_libseat_backend(base); @@ -113,9 +156,11 @@ static int open_device(struct libseat *base, const char *path, int *fd) { } *fd = tmpfd; + out: sd_bus_error_free(&error); sd_bus_message_unref(msg); + check_pending_events(session); return tmpfd; } @@ -150,7 +195,7 @@ static int close_device(struct libseat *base, int device_id) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - + check_pending_events(session); return ret < 0 ? -1 : 0; } @@ -173,6 +218,7 @@ static int switch_session(struct libseat *base, int s) { sd_bus_error_free(&error); sd_bus_message_unref(msg); + check_pending_events(session); return ret < 0 ? -1 : 0; } From e2baadc23047edaccc4a7d3d95e6ba8c30f75851 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Sep 2021 12:46:52 +0200 Subject: [PATCH 07/66] clang-format: Fix alignment --- .clang-format | 2 +- common/drm.c | 4 ++-- common/terminal.c | 4 ++-- include/protocol.h | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.clang-format b/.clang-format index c182735..28723ad 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ IndentWidth: 8 TabWidth: 8 ContinuationIndentWidth: 8 -UseTab: Always +UseTab: ForContinuationAndIndentation ColumnLimit: 100 AlignConsecutiveMacros: true diff --git a/common/drm.c b/common/drm.c index 897028c..9591dc0 100644 --- a/common/drm.c +++ b/common/drm.c @@ -9,8 +9,8 @@ #include "drm.h" // From libdrm -#define DRM_IOCTL_BASE 'd' -#define DRM_IO(nr) _IO(DRM_IOCTL_BASE, nr) +#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) diff --git a/common/terminal.c b/common/terminal.c index 6274957..0c3466f 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -13,14 +13,14 @@ #include #define K_ENABLE K_UNICODE #define K_DISABLE K_OFF -#define FRSIG 0 +#define FRSIG 0 #elif defined(__FreeBSD__) #include #include #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW -#define FRSIG SIGIO +#define FRSIG SIGIO #else #error Unsupported platform #endif diff --git a/include/protocol.h b/include/protocol.h index cb994fc..25133e5 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -1,10 +1,10 @@ #ifndef _SEATD_CONSTANTS_H #define _SEATD_CONSTANTS_H -#define MAX_PATH_LEN 256 -#define MAX_SEAT_LEN 64 +#define MAX_PATH_LEN 256 +#define MAX_SEAT_LEN 64 #define MAX_SEAT_DEVICES 128 -#define MAX_SESSION_LEN 64 +#define MAX_SESSION_LEN 64 #define CLIENT_EVENT(opcode) (opcode) #define SERVER_EVENT(opcode) ((opcode) + (1 << 15)) @@ -15,7 +15,7 @@ #define CLIENT_CLOSE_DEVICE CLIENT_EVENT(4) #define CLIENT_DISABLE_SEAT CLIENT_EVENT(5) #define CLIENT_SWITCH_SESSION CLIENT_EVENT(6) -#define CLIENT_PING CLIENT_EVENT(7) +#define CLIENT_PING CLIENT_EVENT(7) #define SERVER_SEAT_OPENED SERVER_EVENT(1) #define SERVER_SEAT_CLOSED SERVER_EVENT(2) @@ -23,8 +23,8 @@ #define SERVER_DEVICE_CLOSED SERVER_EVENT(4) #define SERVER_DISABLE_SEAT SERVER_EVENT(5) #define SERVER_ENABLE_SEAT SERVER_EVENT(6) -#define SERVER_PONG SERVER_EVENT(7) -#define SERVER_ERROR SERVER_EVENT(0x7FFF) +#define SERVER_PONG SERVER_EVENT(7) +#define SERVER_ERROR SERVER_EVENT(0x7FFF) #include From 1c376ca9b13458b1e4ad0da20c8d35729fa09d4b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 21 Sep 2021 13:11:55 +0200 Subject: [PATCH 08/66] ci: Inline smoketest into build scripts The smoketest script has gotten significantly simpler, and can simply be inlined into the build scripts if we don't care about running the tests twice. This should fix CI for mailing list patches. --- .builds/alpine.yml | 4 ++-- .builds/archlinux.yml | 4 ++-- .builds/freebsd.yml | 4 ++-- .builds/smoketest-builtin.sh | 30 ------------------------------ .builds/smoketest-seatd.sh | 31 ------------------------------- 5 files changed, 6 insertions(+), 67 deletions(-) delete mode 100755 .builds/smoketest-builtin.sh delete mode 100755 .builds/smoketest-seatd.sh diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 20f5fef..bb8904a 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,9 +20,9 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/dri/card0 - smoketest-builtin: | - timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh + timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/dri/card0 - check-format: | ninja -C build clang-format git -C seatd diff --exit-code diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 3f7463c..bc3229a 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -19,6 +19,6 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | - timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh + timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 79bee15..b4bc7da 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,6 +15,6 @@ tasks: 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 KILL 30s ./seatd/.builds/smoketest-seatd.sh + timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | - timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh + timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh deleted file mode 100755 index 332c3f9..0000000 --- a/.builds/smoketest-builtin.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# Devices that exist on sr.ht -if [ -e "/dev/input/event0" ] -then - file="/dev/input/event0" -elif [ -e "/dev/dri/card0" ] -then - file="/dev/dri/card0" -else - echo "No useful device file found" - exit 1 -fi - -# -# Run simpletest a few times -# -cnt=0 -while [ "$cnt" -lt 2 ] -do - echo "Simpletest run $((cnt+1))" - if ! sudo LIBSEAT_BACKEND=builtin ./build/simpletest $file - then - echo "Simpletest failed" - exit $res - fi - cnt=$((cnt+1)) -done - -echo "smoketest-builtin completed" diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh deleted file mode 100755 index f471928..0000000 --- a/.builds/smoketest-seatd.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -# Devices that exist on sr.ht -if [ -e "/dev/input/event0" ] -then - file="/dev/input/event0" -elif [ -e "/dev/dri/card0" ] -then - file="/dev/dri/card0" -else - echo "No useful device file found" - exit 1 -fi - -export SEATD_LOGLEVEL=debug -# -# Run simpletest a few times -# -cnt=0 -while [ "$cnt" -lt 2 ] -do - echo "Simpletest run $((cnt+1))" - if ! sudo -E ./build/seatd-launch ./build/simpletest $file - then - echo "Simpletest failed" - exit 1 - fi - cnt=$((cnt+1)) -done - -echo "smoketest-seatd completed" From 262ccef84eddf3714183b80729a157504615468e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 09:40:02 +0000 Subject: [PATCH 09/66] logind: check if session is active on startup Up until now we assumed the session was always active on startup. This might not be the case. Instead, read the current value of the Active property. --- libseat/backend/logind.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index dd050ce..ceafc6c 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -303,6 +303,7 @@ static bool session_activate(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; + // Note: the Activate call might not make the session active immediately int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", session->path, "org.freedesktop.login1.Session", "Activate", &error, &msg, ""); if (ret < 0) { @@ -314,6 +315,22 @@ static bool session_activate(struct backend_logind *session) { return ret >= 0; } +static bool session_check_active(struct backend_logind *session) { + sd_bus_error error = SD_BUS_ERROR_NULL; + int active = 0; + int ret = sd_bus_get_property_trivial(session->bus, "org.freedesktop.login1", session->path, + "org.freedesktop.login1.Session", "Active", &error, + 'b', &active); + if (ret < 0) { + log_errorf("Could not check if session is active: %s", error.message); + } else { + session->active = (bool)active; + } + + sd_bus_error_free(&error); + return ret >= 0; +} + static bool take_control(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -699,6 +716,10 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list goto error; } + if (!session_check_active(backend)) { + goto error; + } + if (!take_control(backend)) { goto error; } @@ -709,7 +730,6 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list } backend->initial_setup = true; - backend->active = true; backend->seat_listener = listener; backend->seat_listener_data = data; backend->base.impl = &logind_impl; From d2193b45ff3098515115b317878814dc32098294 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 22 Sep 2021 09:44:44 +0000 Subject: [PATCH 10/66] examples/simpletest: check for libseat_dispatch failures --- examples/simpletest/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/simpletest/main.c b/examples/simpletest/main.c index aeeace2..6f94cf5 100644 --- a/examples/simpletest/main.c +++ b/examples/simpletest/main.c @@ -43,7 +43,11 @@ int main(int argc, char *argv[]) { while (active == 0) { fprintf(stderr, "waiting for activation...\n"); - libseat_dispatch(backend, -1); + if (libseat_dispatch(backend, -1) == -1) { + libseat_close_seat(backend); + fprintf(stderr, "libseat_dispatch() failed: %s\n", strerror(errno)); + return -1; + } } fprintf(stderr, "active!\n"); From 8e5c00e7c8d9113b69a880dc6d7feecb0b3eed41 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Sep 2021 23:04:40 +0200 Subject: [PATCH 11/66] logind: Improve error handling in open_seat errno was not being set by open_seat in most cases, leading to simpletest possibly failing with "libseat_open_seat() failed: Success". --- libseat/backend/logind.c | 63 +++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index ceafc6c..e96af6a 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -299,7 +299,7 @@ static struct backend_logind *backend_logind_from_libseat_backend(struct libseat return (struct backend_logind *)base; } -static bool session_activate(struct backend_logind *session) { +static int session_activate(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -312,10 +312,10 @@ static bool session_activate(struct backend_logind *session) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret; } -static bool session_check_active(struct backend_logind *session) { +static int session_check_active(struct backend_logind *session) { sd_bus_error error = SD_BUS_ERROR_NULL; int active = 0; int ret = sd_bus_get_property_trivial(session->bus, "org.freedesktop.login1", session->path, @@ -328,10 +328,10 @@ static bool session_check_active(struct backend_logind *session) { } sd_bus_error_free(&error); - return ret >= 0; + return ret; } -static bool take_control(struct backend_logind *session) { +static int take_control(struct backend_logind *session) { sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -344,7 +344,7 @@ static bool take_control(struct backend_logind *session) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret; } static void release_control(struct backend_logind *session) { @@ -530,7 +530,7 @@ error: return 0; } -static bool add_signal_matches(struct backend_logind *backend) { +static int add_signal_matches(struct backend_logind *backend) { static const char *logind = "org.freedesktop.login1"; static const char *session_interface = "org.freedesktop.login1.Session"; static const char *property_interface = "org.freedesktop.DBus.Properties"; @@ -540,34 +540,34 @@ static bool add_signal_matches(struct backend_logind *backend) { "PauseDevice", pause_device, backend); if (ret < 0) { log_errorf("Could not add D-Bus match: %s", strerror(-ret)); - return false; + return ret; } ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->path, session_interface, "ResumeDevice", resume_device, backend); if (ret < 0) { log_errorf("Could not add D-Bus match: %s", strerror(-ret)); - return false; + return ret; } ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->path, property_interface, "PropertiesChanged", properties_changed, backend); if (ret < 0) { log_errorf("Could not add D-Bus match: %s", strerror(-ret)); - return false; + return ret; } ret = sd_bus_match_signal(backend->bus, NULL, logind, backend->seat_path, property_interface, "PropertiesChanged", properties_changed, backend); if (ret < 0) { log_errorf("Could not add D-Bus match: %s", strerror(-ret)); - return false; + return ret; } - return true; + return 0; } -static bool find_session_path(struct backend_logind *session) { +static int find_session_path(struct backend_logind *session) { int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -592,10 +592,10 @@ out: sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret; } -static bool find_seat_path(struct backend_logind *session) { +static int find_seat_path(struct backend_logind *session) { int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -620,10 +620,10 @@ out: sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret; } -static bool get_display_session(char **session_id) { +static int get_display_session(char **session_id) { assert(session_id != NULL); char *xdg_session_id = getenv("XDG_SESSION_ID"); int ret; @@ -656,12 +656,12 @@ static bool get_display_session(char **session_id) { success: assert(*session_id != NULL); - return true; + return 0; error: free(*session_id); *session_id = NULL; - return false; + return ret; } static int set_type(struct backend_logind *backend, const char *type) { @@ -686,11 +686,13 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list return NULL; } - if (!get_display_session(&backend->id)) { + int ret; + ret = get_display_session(&backend->id); + if (ret < 0) { goto error; } - int ret = sd_session_get_seat(backend->id, &backend->seat); + ret = sd_session_get_seat(backend->id, &backend->seat); if (ret < 0) { goto error; } @@ -700,27 +702,33 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list goto error; } - if (!find_session_path(backend)) { + ret = find_session_path(backend); + if (ret < 0) { goto error; } - if (!find_seat_path(backend)) { + ret = find_seat_path(backend); + if (ret < 0) { goto error; } - if (!add_signal_matches(backend)) { + ret = add_signal_matches(backend); + if (ret < 0) { goto error; } - if (!session_activate(backend)) { + ret = session_activate(backend); + if (ret < 0) { goto error; } - if (!session_check_active(backend)) { + ret = session_check_active(backend); + if (ret < 0) { goto error; } - if (!take_control(backend)) { + ret = take_control(backend); + if (ret < 0) { goto error; } @@ -738,6 +746,7 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list error: destroy(backend); + errno = -ret; return NULL; } From ec0d6565bbe81f1e371da0ddff39ee4c4124ffcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 22 Sep 2021 23:06:59 +0200 Subject: [PATCH 12/66] ci: Add logind smoketest to arch --- .builds/archlinux.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index bc3229a..da300c8 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -22,3 +22,9 @@ tasks: timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 + - smoketest-logind: | + # Turn off systemd-logind and patch our session to be tied to seat0 on VT 6 + sudo systemctl stop systemd-logind + echo -e "ACTIVE=$XDG_SESSION_ID\nACTIVE_UID=$UID\nSESSIONS=$XDG_SESSION_ID\nUIDS=$UID\n" | sudo tee -a /run/systemd/seats/seat0 > /dev/null + echo -e "SEAT=seat0\nVTNR=6\n" | sudo tee -a /run/systemd/sessions/$XDG_SESSION_ID > /dev/null + timeout -s KILL 30s sudo LIBSEAT_BACKEND=logind ./build/simpletest /dev/input/event0 From e35c9cd02e95ec8a76bb4bb82f801a795e135bc9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 5 Oct 2021 10:05:25 +0200 Subject: [PATCH 13/66] logind: Set userdata for ping_handler --- libseat/backend/logind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index e96af6a..5a10c75 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -83,7 +83,7 @@ static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_err static int send_ping(struct backend_logind *backend) { int ret = sd_bus_call_method_async(backend->bus, NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.DBus.Peer", - "Ping", ping_handler, NULL, ""); + "Ping", ping_handler, backend, ""); if (ret < 0) { return ret; } From 88db55f6068c1c01d85b61aa6adff0a6b2a8dce8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 19 Oct 2021 21:39:17 +0200 Subject: [PATCH 14/66] Bump version to 0.6.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e6c80a4..d8fd25d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.2', + version: '0.6.3', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From cb7a94378b96b9c7e0da8ea8e3a2e756b4976d35 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:30:28 +0000 Subject: [PATCH 15/66] seatd: avoid overwriting errno in set_nonblock error handling If close fails, it'll mess up errno, and log_errorf will print a non-sensical value. --- seatd/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/server.c b/seatd/server.c index 0a08f50..8e59c5d 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -123,8 +123,8 @@ static int set_nonblock(int fd) { int server_add_client(struct server *server, int fd) { if (set_nonblock(fd) != 0) { - close(fd); log_errorf("Could not prepare new client socket: %s", strerror(errno)); + close(fd); return -1; } From 88529f08567fabf28432d17dd94b863ea61d554d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:33:07 +0000 Subject: [PATCH 16/66] seatd: don't log errno on EVENT_ERROR errno won't be set when poll returns EVENT_ERROR. --- seatd/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/server.c b/seatd/server.c index 8e59c5d..8ead54d 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -146,7 +146,7 @@ int server_handle_connection(int fd, uint32_t mask, void *data) { if (mask & (EVENT_ERROR | EVENT_HANGUP)) { shutdown(fd, SHUT_RDWR); server->running = false; - log_errorf("Server socket received an error: %s", strerror(errno)); + log_error("Server socket received an error"); return -1; } From 69cf5c36e05c64597063dd8c4d83d3e036547451 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 26 Oct 2021 12:56:26 +0000 Subject: [PATCH 17/66] build: don't use cc.get_supported_arguments for defines If the compiler errors out on some -DXXX flag, then we're in trouble. Avoid using cc.get_supported_arguments for defines we require. Only use it for detecting support for warning flags. --- meson.build | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index d8fd25d..206cde1 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,18 @@ endif seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) cc = meson.get_compiler('c') + +add_project_arguments( + [ + '-D_XOPEN_SOURCE=700', + '-D__BSD_VISIBLE', + '-DSEATD_VERSION="@0@"'.format(meson.project_version()), + '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), + '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), + ], + language: 'c', +) + add_project_arguments(cc.get_supported_arguments( [ '-Wundef', @@ -40,11 +52,6 @@ add_project_arguments(cc.get_supported_arguments( '-Wno-unused-command-line-argument', '-Wvla', '-Wl,--exclude-libs=ALL', - '-D_XOPEN_SOURCE=700', - '-D__BSD_VISIBLE', - '-DSEATD_VERSION="@0@"'.format(meson.project_version()), - '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), - '-DSEATD_INSTALLPATH="@0@"'.format(seatdpath), ]), language: 'c', ) From d92fa01f884e94262e4c7184be62efaf8a00a634 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 21:17:51 +0000 Subject: [PATCH 18/66] build: use list for logind dep This reduces the boilerplate a bit. Use logind.name() instead of having a separate source of truth. Requires adapting the checks a bit because the dep name has a "lib" prefix. --- libseat/backend/logind.c | 4 ++-- meson.build | 19 ++++++------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 5a10c75..bfb02cf 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -13,10 +13,10 @@ #include #include -#if defined(HAVE_ELOGIND) +#if defined(HAVE_LIBELOGIND) #include #include -#elif defined(HAVE_SYSTEMD) +#elif defined(HAVE_LIBSYSTEMD) #include #include #else diff --git a/meson.build b/meson.build index 206cde1..b5d00c6 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.6.3', license: 'MIT', - meson_version: '>=0.56.0', + meson_version: '>=0.60.0', default_options: [ 'c_std=c11', 'warning_level=3', @@ -126,26 +126,19 @@ if with_seatd endif logind = disabler() -logind_provider = '' if get_option('libseat-logind') != 'disabled' if get_option('libseat-logind') == 'auto' and get_option('auto_features').disabled() # Disable logind elif get_option('libseat-logind') == 'auto' assert(get_option('auto_features').auto(), '-Dlibseat-logind must be set to systemd or elogind since auto_features != auto') - foreach logind_provider : ['elogind', 'systemd'] - logind = dependency('lib@0@'.format(logind_provider), required: false) - if logind.found() - break - endif - endforeach + logind = dependency(['libelogind', 'libsystemd'], required: false) else - logind_provider = get_option('libseat-logind') - logind = dependency('lib@0@'.format(logind_provider)) + logind = dependency('lib@0@'.format(get_option('libseat-logind'))) endif if logind.found() add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') - add_project_arguments('-DHAVE_@0@=1'.format(logind_provider.to_upper()), language: 'c') + add_project_arguments('-DHAVE_@0@=1'.format(logind.name().to_upper()), language: 'c') private_files += [ 'libseat/backend/logind.c', 'common/drm.c', @@ -278,7 +271,7 @@ endif summary({ 'libseat-seatd': with_seatd, 'libseat-builtin': with_builtin, - 'libseat-systemd': logind.found() and logind_provider == 'systemd', - 'libseat-elogind': logind.found() and logind_provider == 'elogind', + 'libseat-systemd': logind.found() and logind.name() == 'libsystemd', + 'libseat-elogind': logind.found() and logind.name() == 'libelogind', 'server': with_server, }, bool_yn: true) From f381e22955d9bcffd1c47c70626f22972e5af1db Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 21:20:05 +0000 Subject: [PATCH 19/66] build: don't use sh for scdoc Just use the built-in feed/capture Meson options instead. --- meson.build | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index b5d00c6..c313294 100644 --- a/meson.build +++ b/meson.build @@ -247,7 +247,6 @@ else endif if scdoc.found() - scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') foreach src : ['seatd.1.scd', 'seatd-launch.1.scd'] @@ -259,9 +258,9 @@ if scdoc.found() output, input: 'man/' + src, output: output, - command: [ - 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output) - ], + command: scdoc.get_variable(pkgconfig: 'scdoc'), + feed: true, + capture: true, install: true, install_dir: '@0@/man@1@'.format(mandir, section) ) From 936ff9dbea9148f0b5e4892c392337060bee5860 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 14 Dec 2021 11:14:39 +0000 Subject: [PATCH 20/66] build: use meson.override_dependency This allows downstream users to write: dependency('libseat', fallback: 'seatd') instead of having to rely on the seatd/meson.build's variable name: dependency('libseat', fallback: ['seatd', 'libseat']) --- meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meson.build b/meson.build index c313294..960c3b6 100644 --- a/meson.build +++ b/meson.build @@ -200,6 +200,8 @@ libseat = declare_dependency( variables: libseat_vars, ) +meson.override_dependency('libseat', libseat) + if with_server executable( 'seatd', From 96a5de88595cb8ddc41a4beb72d213d1f8bfdc61 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Dec 2021 07:46:48 +0000 Subject: [PATCH 21/66] readme: add irc:// link This allows users to just click the link to join the IRC channel. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aa9e99..2ed6e8b 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,4 @@ Instead of giving user shell developers more work, libseat aims to make supporti ## How to discuss -Go to #kennylevinsen @ irc.libera.chat to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). +Go to [#kennylevinsen @ irc.libera.chat](ircs://irc.libera.chat/#kennylevinsen) to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). From b47c79d73123052b20bc853b544c10274ab29fa6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 9 Feb 2022 23:21:18 +0100 Subject: [PATCH 22/66] libseat: Use SOCK_CLOEXEC and SOCK_NONBLOCK This both simplifies our code and fixes an exec fd leak when using builtin or noop backends. --- libseat/backend/noop.c | 2 +- libseat/backend/seatd.c | 20 ++------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 7436c48..f69aac6 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -109,7 +109,7 @@ static struct libseat *noop_open_seat(const struct libseat_seat_listener *listen return NULL; } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, backend->sockets) != 0) { + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, backend->sockets) != 0) { log_errorf("socketpair() failed: %s", strerror(errno)); free(backend); return NULL; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 26308d1..6e90713 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -42,32 +42,16 @@ struct backend_seatd { char seat_name[MAX_SEAT_LEN]; }; -static int set_nonblock(int fd) { - int flags; - if ((flags = fcntl(fd, F_GETFD)) == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - return -1; - } - if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - return -1; - } - return 0; -} - static int seatd_connect(void) { union { struct sockaddr_un unix; struct sockaddr generic; } addr = {{0}}; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); if (fd == -1) { log_errorf("Could not create socket: %s", strerror(errno)); return -1; } - if (set_nonblock(fd) == -1) { - log_errorf("Could not make socket non-blocking: %s", strerror(errno)); - close(fd); - return -1; - } const char *path = getenv("SEATD_SOCK"); if (path == NULL) { path = SEATD_DEFAULTPATH; @@ -638,7 +622,7 @@ static int set_deathsig(int signal) { static struct libseat *builtin_open_seat(const struct libseat_seat_listener *listener, void *data) { int fds[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) { + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) == -1) { log_errorf("Could not create socket pair: %s", strerror(errno)); return NULL; } From f128359332ac33d5ef0c2e91830059fb1c1ef923 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 15 Feb 2022 13:24:41 +0100 Subject: [PATCH 23/66] logind: Always send ping if data is queued sd_bus_call_method may have read and queued our ping response, so we cannot assume that a previous ping will make the socket readable. Instead, always send a ping if read or write queues are not empty, even if a ping has already been sent. --- libseat/backend/logind.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index bfb02cf..53523c8 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -41,7 +41,6 @@ struct backend_logind { bool active; bool initial_setup; - bool awaiting_pong; int has_drm; }; @@ -70,13 +69,12 @@ static int close_seat(struct libseat *base) { static int ping_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { (void)ret_error; - struct backend_logind *session = userdata; + (void)userdata; if (sd_bus_message_is_method_error(m, NULL)) { const sd_bus_error *error = sd_bus_message_get_error(m); log_errorf("Ping failed: %s: %s", error->name, error->message); return -1; } - session->awaiting_pong = false; return 0; } @@ -91,14 +89,15 @@ static int send_ping(struct backend_logind *backend) { } static void check_pending_events(struct backend_logind *backend) { - if (sd_bus_get_events(backend->bus) <= 0) { - return; - } - if (backend->awaiting_pong) { + uint64_t queued_read, queued_write; + sd_bus_get_n_queued_read(backend->bus, &queued_read); + sd_bus_get_n_queued_write(backend->bus, &queued_write); + + if (queued_read == 0 && queued_write == 0) { return; } - // We have events pending execution, so a dispatch is required. + // The sd_bus instance has queued data, so a dispatch is required. // However, we likely already drained our socket, so there will not be // anything to read. Instead, send a ping request to logind so that the // user will be woken up by its response. @@ -107,7 +106,6 @@ static void check_pending_events(struct backend_logind *backend) { log_errorf("Could not send ping message: %s", strerror(-ret)); return; } - backend->awaiting_pong = true; } static int open_device(struct libseat *base, const char *path, int *fd) { @@ -286,6 +284,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { total_dispatched += dispatched; } } + check_pending_events(backend); return total_dispatched; } @@ -742,6 +741,7 @@ static struct libseat *logind_open_seat(const struct libseat_seat_listener *list backend->seat_listener_data = data; backend->base.impl = &logind_impl; + check_pending_events(backend); return &backend->base; error: From 157ce685658c19b51caa091601240940267c0940 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:27:56 +0100 Subject: [PATCH 24/66] seatd: Remove SOCK_PATH and improve cleanup SOCK_PATH is made redundant by the -s command-line argument added in a98e0c4ce90347d37370f2debcbed8ae9678a990. Support was originally left behind for short-term compatibility, but it should be fine to remove. Previous socket cleanup is changed to run unconditionally. The cleanup now fails if the existing file is not a socket. --- seatd/seatd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 053d44b..8480350 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) { int c; int uid = -1, gid = -1; int readiness = -1; - const char *socket_path = getenv("SEATD_SOCK"); + const char *socket_path = SEATD_DEFAULTPATH; while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { switch (c) { case 'n': @@ -131,11 +131,14 @@ int main(int argc, char *argv[]) { } } - if (socket_path == NULL) { - socket_path = SEATD_DEFAULTPATH; - struct stat st; - if (stat(socket_path, &st) == 0) { - log_info("Removing leftover seatd socket"); + struct stat st; + if (stat(socket_path, &st) == 0) { + if (!S_ISSOCK(st.st_mode)) { + log_errorf("Non-socket file found at socket path %s, refusing to start", + socket_path); + return 1; + } else { + log_infof("Removing leftover socket at %s", socket_path); unlink(socket_path); } } From 0864f6a3ac8ca8263490269ecc7fdf4c1cd59850 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:37:26 +0100 Subject: [PATCH 25/66] seatd: Ensure socket gets unlinked on error --- seatd/seatd.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 8480350..c2ce411 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -145,22 +145,21 @@ int main(int argc, char *argv[]) { struct server server = {0}; if (server_init(&server) == -1) { - log_errorf("server_create failed: %s", strerror(errno)); + log_errorf("server_init failed: %s", strerror(errno)); return 1; } + int ret = 1; int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); - server_finish(&server); - return 1; + goto error_server; } if (poller_add_fd(&server.poller, socket_fd, EVENT_READABLE, server_handle_connection, &server) == NULL) { log_errorf("Could not add socket to poller: %s", strerror(errno)); close(socket_fd); - server_finish(&server); - return 1; + goto error_socket; } log_info("seatd started"); @@ -175,12 +174,16 @@ int main(int argc, char *argv[]) { while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Poller failed: %s", strerror(errno)); - return 1; + goto error_socket; } } - server_finish(&server); + ret = 0; + +error_socket: unlink(socket_path); +error_server: + server_finish(&server); log_info("seatd stopped"); - return 0; + return ret; } From 32d06482d3aeaac166d76912fcba53fa8dfb2fcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:44:27 +0100 Subject: [PATCH 26/66] seatd-launch: Do not unlink socket path seatd cleans up after itself and takes care of stale sockets when applicable, so seatd-launch should not replicate this functionality. --- seatd-launch/seatd-launch.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 69ca86a..0075efb 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -53,8 +53,6 @@ int main(int argc, char *argv[]) { sockpath = sockbuf; } - unlink(sockpath); - int fds[2]; if (pipe(fds) == -1) { perror("Could not create pipe"); @@ -170,9 +168,6 @@ int main(int argc, char *argv[]) { } } - if (unlink(sockpath) != 0) { - perror("Could not unlink socket"); - } if (kill(seatd_child, SIGTERM) != 0) { perror("Could not kill seatd"); } @@ -186,7 +181,6 @@ int main(int argc, char *argv[]) { } error_seatd: - unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; From 10658dc5439db429af0088295a051c53925a4416 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 11:46:48 +0100 Subject: [PATCH 27/66] seatd-launch: Remove socket path command line arg This should not need to be configured, so remove the argument. If downstream prefers a different folder, the location can be made compile-time configurable like for seatd itself. --- seatd-launch/seatd-launch.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 0075efb..4f15616 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -15,18 +15,13 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" - " -h Show this help message\n" - " -s Where to create the seatd socket\n" - " -v Show the version number\n" + " -h Show this help message\n" + " -v Show the version number\n" "\n"; int c; - char *sockpath = NULL; - while ((c = getopt(argc, argv, "vhs:")) != -1) { + while ((c = getopt(argc, argv, "vh")) != -1) { switch (c) { - case 's': - sockpath = optarg; - break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); return 0; @@ -47,11 +42,8 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - char sockbuf[256]; - if (sockpath == NULL) { - sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); - sockpath = sockbuf; - } + char sockpath[256]; + sprintf(sockpath, "/tmp/seatd.%d.sock", getpid()); int fds[2]; if (pipe(fds) == -1) { From a44476ce65af5c192860130cb25b0ce17cec2651 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 12:04:09 +0100 Subject: [PATCH 28/66] seatd: Fix usage rendering --- seatd/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index c2ce411..0d9274b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" - " -n FD to notify readiness on\n" + " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" From ed90ed62cdf1c4e7d59e4d279a5bf946b93057dd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 21:27:14 +0100 Subject: [PATCH 29/66] seatd-launch: Use snprintf for socket path We also reduce the size of the buffer from 256 bytes to a much more reasonable 32 bytes. --- seatd-launch/seatd-launch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 4f15616..8057ba7 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -42,8 +42,8 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - char sockpath[256]; - sprintf(sockpath, "/tmp/seatd.%d.sock", getpid()); + char sockpath[32]; + snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); int fds[2]; if (pipe(fds) == -1) { From 3eb0db57bb1c23b5157279223f248d58d9662aae Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 21 Feb 2022 21:33:06 +0100 Subject: [PATCH 30/66] seatd-launch: Minor readability improvements --- seatd-launch/seatd-launch.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 8057ba7..d03a50f 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -11,8 +11,6 @@ #include int main(int argc, char *argv[]) { - (void)argc; - const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" " -h Show this help message\n" @@ -45,21 +43,22 @@ int main(int argc, char *argv[]) { char sockpath[32]; snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); - int fds[2]; - if (pipe(fds) == -1) { + int readiness_pipe[2]; + if (pipe(readiness_pipe) == -1) { perror("Could not create pipe"); goto error; } + // Start seatd pid_t seatd_child = fork(); if (seatd_child == -1) { perror("Could not fork seatd process"); goto error; } else if (seatd_child == 0) { - close(fds[0]); + close(readiness_pipe[0]); char pipebuf[16] = {0}; - snprintf(pipebuf, sizeof pipebuf, "%d", fds[1]); + snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]); char *env[2] = {NULL, NULL}; char loglevelbuf[32] = {0}; @@ -74,7 +73,7 @@ int main(int argc, char *argv[]) { perror("Could not start seatd"); _exit(1); } - close(fds[1]); + close(readiness_pipe[1]); // Wait for seatd to be ready char buf[1] = {0}; @@ -89,7 +88,7 @@ int main(int argc, char *argv[]) { } struct pollfd fd = { - .fd = fds[0], + .fd = readiness_pipe[0], .events = POLLIN, }; @@ -104,7 +103,7 @@ int main(int argc, char *argv[]) { } if (fd.revents & POLLIN) { - ssize_t n = read(fds[0], buf, 1); + ssize_t n = read(readiness_pipe[0], buf, 1); if (n == -1 && errno != EINTR) { perror("Could not read from pipe"); goto error_seatd; @@ -113,7 +112,7 @@ int main(int argc, char *argv[]) { } } } - close(fds[0]); + close(readiness_pipe[0]); uid_t uid = getuid(); gid_t gid = getgid(); From 9bbdf0f0b8d383edd1d621507c04db0a5382a5af Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 19:05:49 +0100 Subject: [PATCH 31/66] seatd: Command-line argument for loglevel SEATD_LOGLEVEL was used to set the loglevel despite already having getopt in place. Remove the environment variable and make a command-line argument for it instead. --- man/seatd-launch.1.scd | 4 ++++ man/seatd.1.scd | 16 ++++------------ seatd-launch/seatd-launch.c | 23 +++++++++++------------ seatd/seatd.c | 35 ++++++++++++++++++++--------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index 9234203..d66ad3e 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -10,6 +10,10 @@ seatd-launch - Start a process with its own seatd instance # OPTIONS +*-l * + Log-level to pass to seatd. See *seatd*(1) for information about + available log-levels. + *-h* Show help message and quit. diff --git a/man/seatd.1.scd b/man/seatd.1.scd index de95843..2de4326 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -27,6 +27,10 @@ seatd - A seat management daemon *-s * Where to create the seatd socket. Defaults to `/run/seatd.sock`. +*-l * + Log-level to use. Must be one of debug, info, error or silent. Defaults + to error. + *-v* Show the version number and quit. @@ -38,18 +42,6 @@ such as displays and input devices in a multi-session, multi-seat environment. seatd operates over a UNIX domain socket, with *libseat* providing the client-side of the protocol. -# ENVIRONMENT - -[[ *VARIABLE* -:[ *VALUES* -:< *DESCRIPTION* -| SEATD_SOCK -: File path -: Informs libseat of the socket location, needed if it differs from `/run/seatd.sock` -| SEATD_LOGLEVEL -: silent, error, info, debug -: Sets the seatd log level. Defaults to "error" - # SEE ALSO The libseat library, **, *seatd-launch*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index d03a50f..f8ab8d4 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -13,13 +13,19 @@ int main(int argc, char *argv[]) { const char *usage = "Usage: seatd-launch [options] [--] command\n" "\n" - " -h Show this help message\n" - " -v Show the version number\n" + " -l Log-level to pass to seatd\n" + " -h Show this help message\n" + " -v Show the version number\n" "\n"; int c; - while ((c = getopt(argc, argv, "vh")) != -1) { + char loglevel[16] = "info"; + while ((c = getopt(argc, argv, "vhl:")) != -1) { switch (c) { + case 'l': + strncpy(loglevel, optarg, sizeof loglevel); + loglevel[sizeof loglevel - 1] = '\0'; + break; case 'v': printf("seatd-launch version %s\n", SEATD_VERSION); return 0; @@ -60,15 +66,8 @@ int main(int argc, char *argv[]) { char pipebuf[16] = {0}; snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]); - char *env[2] = {NULL, NULL}; - char loglevelbuf[32] = {0}; - char *cur_loglevel = getenv("SEATD_LOGLEVEL"); - if (cur_loglevel != NULL) { - snprintf(loglevelbuf, sizeof loglevelbuf, "SEATD_LOGLEVEL=%s", cur_loglevel); - env[0] = loglevelbuf; - } - - char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, NULL}; + char *env[1] = {NULL}; + char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, "-l", loglevel, NULL}; execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); diff --git a/seatd/seatd.c b/seatd/seatd.c index 0d9274b..2a41146 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -57,20 +57,6 @@ error: } int main(int argc, char *argv[]) { - char *loglevel = getenv("SEATD_LOGLEVEL"); - enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; - if (loglevel != NULL) { - if (strcmp(loglevel, "silent") == 0) { - level = LIBSEAT_LOG_LEVEL_SILENT; - } else if (strcmp(loglevel, "info") == 0) { - level = LIBSEAT_LOG_LEVEL_INFO; - } else if (strcmp(loglevel, "debug") == 0) { - level = LIBSEAT_LOG_LEVEL_DEBUG; - } - } - log_init(); - libseat_set_log_level(level); - const char *usage = "Usage: seatd [options]\n" "\n" " -h Show this help message\n" @@ -78,14 +64,16 @@ int main(int argc, char *argv[]) { " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" + " -l Log-level, one of debug, info, error or silent\n" " -v Show the version number\n" "\n"; int c; int uid = -1, gid = -1; int readiness = -1; + enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; const char *socket_path = SEATD_DEFAULTPATH; - while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { + while ((c = getopt(argc, argv, "vhn:s:g:u:l:")) != -1) { switch (c) { case 'n': readiness = atoi(optarg); @@ -117,6 +105,20 @@ int main(int argc, char *argv[]) { } break; } + case 'l': + if (strcmp(optarg, "debug") == 0) { + level = LIBSEAT_LOG_LEVEL_DEBUG; + } else if (strcmp(optarg, "info") == 0) { + level = LIBSEAT_LOG_LEVEL_INFO; + } else if (strcmp(optarg, "error") == 0) { + level = LIBSEAT_LOG_LEVEL_ERROR; + } else if (strcmp(optarg, "silent") == 0) { + level = LIBSEAT_LOG_LEVEL_SILENT; + } else { + fprintf(stderr, "Invalid loglevel: %s\n", optarg); + return 1; + } + break; case 'v': printf("seatd version %s\n", SEATD_VERSION); return 0; @@ -131,6 +133,9 @@ int main(int argc, char *argv[]) { } } + log_init(); + libseat_set_log_level(level); + struct stat st; if (stat(socket_path, &st) == 0) { if (!S_ISSOCK(st.st_mode)) { From 466efea49bc6ab5672555c31f04b39741c502c70 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 19:37:49 +0100 Subject: [PATCH 32/66] seatd: Handle socket unlink errors This ensures early failure and better error messages. --- seatd/seatd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 2a41146..ef6c781 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -144,7 +144,10 @@ int main(int argc, char *argv[]) { return 1; } else { log_infof("Removing leftover socket at %s", socket_path); - unlink(socket_path); + if (unlink(socket_path) == -1) { + log_errorf("Could not remove leftover socket: %s", strerror(errno)); + return 1; + } } } @@ -186,7 +189,9 @@ int main(int argc, char *argv[]) { ret = 0; error_socket: - unlink(socket_path); + if (unlink(socket_path) == -1) { + log_errorf("Could not remove socket: %s", strerror(errno)); + } error_server: server_finish(&server); log_info("seatd stopped"); From 0d6bdf4f01e5be10c29dd786f2531b96e1d935cd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 20:25:22 +0100 Subject: [PATCH 33/66] seatd: Remove runtime socket path configuration Configurable socket paths exist mainly to facilitate multiple parallel seatd instances. However, the only valid use-case for running multiple instances of seatd is testing during development, which can just as well be done by changing SEATD_DEFAULTPATH at compile-time for test builds. Remove the command-line argument in seatd for runtime configuration of socket path, hardcode the socket path in seatd-launch, and change seatd unlink/chmod/chown code to not run when started by seatd-launch. This means that seatd-launch will now fail to start seatd if another seatd instance is already running. The unlink code still runs when seatd is started normally to assist in system crash recovery, but this may be removed later if we deem it unnecessary. --- man/seatd-launch.1.scd | 3 --- man/seatd.1.scd | 5 ++-- seatd-launch/seatd-launch.c | 11 +++----- seatd/seatd.c | 53 ++++++++++++++++++++++++++----------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index d66ad3e..73d302d 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -17,9 +17,6 @@ seatd-launch - Start a process with its own seatd instance *-h* Show help message and quit. -*-s * - Where to create the seatd socket. Defaults to a unique file path. - *-v* Show the version number and quit. diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 2de4326..f599a23 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -24,9 +24,6 @@ seatd - A seat management daemon *-g * Group to own the seatd socket. -*-s * - Where to create the seatd socket. Defaults to `/run/seatd.sock`. - *-l * Log-level to use. Must be one of debug, info, error or silent. Defaults to error. @@ -42,6 +39,8 @@ such as displays and input devices in a multi-session, multi-seat environment. seatd operates over a UNIX domain socket, with *libseat* providing the client-side of the protocol. +The location of the socket for seatd is set at compile-time. + # SEE ALSO The libseat library, **, *seatd-launch*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index f8ab8d4..329ccef 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -46,9 +46,6 @@ int main(int argc, char *argv[]) { } char **command = &argv[optind]; - char sockpath[32]; - snprintf(sockpath, sizeof sockpath, "/tmp/seatd.%d.sock", getpid()); - int readiness_pipe[2]; if (pipe(readiness_pipe) == -1) { perror("Could not create pipe"); @@ -67,7 +64,7 @@ int main(int argc, char *argv[]) { snprintf(pipebuf, sizeof pipebuf, "%d", readiness_pipe[1]); char *env[1] = {NULL}; - char *command[] = {"seatd", "-n", pipebuf, "-s", sockpath, "-l", loglevel, NULL}; + char *command[] = {"seatd", "-n", pipebuf, "-l", loglevel, "-z", NULL}; execve(SEATD_INSTALLPATH, command, env); perror("Could not start seatd"); _exit(1); @@ -117,11 +114,11 @@ int main(int argc, char *argv[]) { gid_t gid = getgid(); // Restrict access to the socket to just us - if (chown(sockpath, uid, gid) == -1) { + if (chown(SEATD_DEFAULTPATH, uid, gid) == -1) { perror("Could not chown seatd socket"); goto error_seatd; } - if (chmod(sockpath, 0700) == -1) { + if (chmod(SEATD_DEFAULTPATH, 0700) == -1) { perror("Could not chmod socket"); goto error_seatd; } @@ -141,7 +138,7 @@ int main(int argc, char *argv[]) { perror("Could not fork target process"); goto error_seatd; } else if (child == 0) { - setenv("SEATD_SOCK", sockpath, 1); + setenv("SEATD_SOCK", SEATD_DEFAULTPATH, 1); execvp(command[0], command); perror("Could not start target"); _exit(1); diff --git a/seatd/seatd.c b/seatd/seatd.c index ef6c781..f6bad9b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -40,15 +40,15 @@ static int open_socket(const char *path, int uid, int gid) { goto error; } if (uid != -1 || gid != -1) { + if (chmod(path, 0770) == -1) { + log_errorf("Could not chmod socket: %s", strerror(errno)); + goto error; + } if (chown(path, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); goto error; } - if (chmod(path, 0770) == -1) { - log_errorf("Could not chmod socket: %s", strerror(errno)); - goto error; - } } return fd; error: @@ -63,7 +63,6 @@ int main(int argc, char *argv[]) { " -n FD to notify readiness on\n" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" - " -s Where to create the seatd socket\n" " -l Log-level, one of debug, info, error or silent\n" " -v Show the version number\n" "\n"; @@ -71,9 +70,10 @@ int main(int argc, char *argv[]) { int c; int uid = -1, gid = -1; int readiness = -1; + bool unlink_existing_socket = true; + bool chown_socket = true; enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; - const char *socket_path = SEATD_DEFAULTPATH; - while ((c = getopt(argc, argv, "vhn:s:g:u:l:")) != -1) { + while ((c = getopt(argc, argv, "vhn:g:u:l:z")) != -1) { switch (c) { case 'n': readiness = atoi(optarg); @@ -82,10 +82,11 @@ int main(int argc, char *argv[]) { return 1; } break; - case 's': - socket_path = optarg; - break; case 'u': { + if (!chown_socket) { + fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); + return 1; + } struct passwd *pw = getpwnam(optarg); if (pw == NULL) { fprintf(stderr, "Could not find user by name '%s'.\n", optarg); @@ -96,6 +97,10 @@ int main(int argc, char *argv[]) { break; } case 'g': { + if (!chown_socket) { + fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); + return 1; + } struct group *gr = getgrnam(optarg); if (gr == NULL) { fprintf(stderr, "Could not find group by name '%s'.\n", optarg); @@ -119,6 +124,17 @@ int main(int argc, char *argv[]) { return 1; } break; + case 'z': + // Running under seatd-launch. We do not unlink files + // to protect against multiple instances, and + // seatd-launch takes care of ownership. + if (uid != -1 || gid != -1) { + fprintf(stderr, "-u/-g and -z are mutually exclusive\n"); + return 1; + } + unlink_existing_socket = false; + chown_socket = false; + break; case 'v': printf("seatd version %s\n", SEATD_VERSION); return 0; @@ -137,14 +153,19 @@ int main(int argc, char *argv[]) { libseat_set_log_level(level); struct stat st; - if (stat(socket_path, &st) == 0) { + if (lstat(SEATD_DEFAULTPATH, &st) == 0) { if (!S_ISSOCK(st.st_mode)) { log_errorf("Non-socket file found at socket path %s, refusing to start", - socket_path); + SEATD_DEFAULTPATH); + return 1; + } else if (!unlink_existing_socket) { + log_errorf("Socket file found at socket path %s, refusing to start", + SEATD_DEFAULTPATH); return 1; } else { - log_infof("Removing leftover socket at %s", socket_path); - if (unlink(socket_path) == -1) { + // We only do this if the socket path is not user specified + log_infof("Removing leftover socket at %s", SEATD_DEFAULTPATH); + if (unlink(SEATD_DEFAULTPATH) == -1) { log_errorf("Could not remove leftover socket: %s", strerror(errno)); return 1; } @@ -158,7 +179,7 @@ int main(int argc, char *argv[]) { } int ret = 1; - int socket_fd = open_socket(socket_path, uid, gid); + int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); goto error_server; @@ -189,7 +210,7 @@ int main(int argc, char *argv[]) { ret = 0; error_socket: - if (unlink(socket_path) == -1) { + if (unlink(SEATD_DEFAULTPATH) == -1) { log_errorf("Could not remove socket: %s", strerror(errno)); } error_server: From ae42d05513189c2215916c5586e9f8fb74c4d5e7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 26 Feb 2022 22:56:42 +0100 Subject: [PATCH 34/66] seatd: Change default log-level to info --- seatd/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index f6bad9b..f88e6c9 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { int readiness = -1; bool unlink_existing_socket = true; bool chown_socket = true; - enum libseat_log_level level = LIBSEAT_LOG_LEVEL_ERROR; + enum libseat_log_level level = LIBSEAT_LOG_LEVEL_INFO; while ((c = getopt(argc, argv, "vhn:g:u:l:z")) != -1) { switch (c) { case 'n': From abcecbb53b35cfb449ce1793f98bfdee5e604a94 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:40:40 +0100 Subject: [PATCH 35/66] meson: Only set libseat defines for libseat itself This allows us to distinguish between when we build seatd as part of the builtin libseat backend, or when we build seatd on its own. --- meson.build | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 960c3b6..1070b55 100644 --- a/meson.build +++ b/meson.build @@ -121,8 +121,10 @@ if with_seatd or with_builtin private_files += 'libseat/backend/seatd.c' endif +libseat_c_args = ['-DLIBSEAT=1'] + if with_seatd - add_project_arguments('-DSEATD_ENABLED=1', language: 'c') + libseat_c_args += '-DSEATD_ENABLED=1' endif logind = disabler() @@ -137,8 +139,8 @@ if get_option('libseat-logind') != 'disabled' endif if logind.found() - add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') - add_project_arguments('-DHAVE_@0@=1'.format(logind.name().to_upper()), language: 'c') + libseat_c_args += '-DLOGIND_ENABLED=1' + libseat_c_args += '-DHAVE_@0@=1'.format(logind.name().to_upper()) private_files += [ 'libseat/backend/logind.c', 'common/drm.c', @@ -152,7 +154,7 @@ realtime = meson.get_compiler('c').find_library('rt') private_deps += realtime if with_builtin - add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') + libseat_c_args += '-DBUILTIN_ENABLED=1' private_files += server_files endif @@ -161,6 +163,7 @@ private_lib = static_library( private_files, dependencies: private_deps, include_directories: [include_directories('.', 'include')], + c_args: libseat_c_args, ) symbols_file = 'libseat/libseat.syms' @@ -174,6 +177,7 @@ lib = library( install: true, link_args: symbols_flag, link_depends: symbols_file, + c_args: libseat_c_args, ) install_headers('include/libseat.h') From 46c83972fe66b917032a832bb8e3309ac6783d7d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:41:52 +0100 Subject: [PATCH 36/66] builtin: Close other end of socketpair after fork We will not get a socket hangup if we have duplicates socket fds in the parent or child, so make sure we clean this up properly after fork. --- libseat/backend/seatd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 6e90713..f55efe6 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -634,6 +634,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis close(fds[1]); return NULL; } else if (pid == 0) { + close(fds[1]); int fd = fds[0]; int res = 0; struct server server = {0}; @@ -662,6 +663,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis close(fd); exit(res); } else { + close(fds[0]); int fd = fds[1]; return _open_seat(listener, data, fd); } From 795cf169e779aa003a5f4e990d7c9d307132d570 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:43:13 +0100 Subject: [PATCH 37/66] seatd: Shut down on client disconnect in builtin If we're part of the libseat builtin backend, then we only have one client. Shut down the server when this client disconnects. --- seatd/client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/seatd/client.c b/seatd/client.c index 220c5d3..6b6f3b3 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -81,6 +81,13 @@ struct client *client_create(struct server *server, int client_fd) { void client_destroy(struct client *client) { assert(client); + +#ifdef LIBSEAT + // The built-in backend version of seatd should terminate once its only + // client disconnects. + client->server->running = false; +#endif + client->server = NULL; if (client->connection.fd != -1) { close(client->connection.fd); From 8dc6a50d88dcabda3f35135eacf075d5f4a18281 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 14:44:06 +0100 Subject: [PATCH 38/66] builtin: Remove deathsig and log start/stop Proper handling of client disconnect mean that we no longer need deathsig handling. --- libseat/backend/seatd.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index f55efe6..abcd2a5 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -600,25 +600,6 @@ const struct seat_impl seatd_impl = { }; #ifdef BUILTIN_ENABLED -#include - -static int set_deathsig(int signal); - -#if defined(__linux__) -#include - -static int set_deathsig(int signal) { - return prctl(PR_SET_PDEATHSIG, signal); -} -#elif defined(__FreeBSD__) -#include - -static int set_deathsig(int signal) { - return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signal); -} -#else -#error Unsupported platform -#endif static struct libseat *builtin_open_seat(const struct libseat_seat_listener *listener, void *data) { int fds[2]; @@ -649,7 +630,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis res = 1; goto server_error; } - set_deathsig(SIGTERM); + log_info("Started embedded seatd"); while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Could not poll server socket: %s", strerror(errno)); @@ -661,6 +642,7 @@ static struct libseat *builtin_open_seat(const struct libseat_seat_listener *lis server_finish(&server); error: close(fd); + log_info("Stopped embedded seatd"); exit(res); } else { close(fds[0]); From ce6a6b7d2eb84fc2eb72ef97f7102012668b17e4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 17:52:26 +0100 Subject: [PATCH 39/66] meson: Fix meson warnings --- meson.build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1070b55..9022dcd 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,12 @@ add_project_arguments(cc.get_supported_arguments( '-Wno-unknown-warning-option', '-Wno-unused-command-line-argument', '-Wvla', + ]), + language: 'c', +) + +add_project_arguments(cc.get_supported_link_arguments( + [ '-Wl,--exclude-libs=ALL', ]), language: 'c', @@ -66,7 +72,7 @@ endif # Hacks source_root = meson.current_source_dir().split('/') -build_root = meson.build_root().split('/') +build_root = meson.global_build_root().split('/') relative_dir_parts = [] i = 0 in_prefix = true From bb0efb65b3894e42ab86e212cfa747f5348d4f2c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 3 Mar 2022 17:52:50 +0100 Subject: [PATCH 40/66] Bump version to 0.7.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9022dcd..e6e583d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.3', + version: '0.7.0', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 1990f9b0348412a06acae0e7d17d746905cc75b1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 16 Mar 2022 21:27:05 +0100 Subject: [PATCH 41/66] ci: Set loglevel argument to debug --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index bb8904a..7e59203 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,7 +20,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/dri/card0 + timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/dri/card0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/dri/card0 - check-format: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index da300c8..185d232 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -19,7 +19,7 @@ tasks: ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - timeout -s KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 + timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 - smoketest-logind: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index b4bc7da..c8f9618 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -15,6 +15,6 @@ tasks: 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 KILL 30s sudo SEATD_LOGLEVEL=debug ./build/seatd-launch ./build/simpletest /dev/input/event0 + timeout -s KILL 30s sudo ./build/seatd-launch -l debug -- ./build/simpletest /dev/input/event0 - smoketest-builtin: | timeout -s KILL 30s sudo LIBSEAT_BACKEND=builtin ./build/simpletest /dev/input/event0 From 4ad48cb305b3f847ab7d3c2d3f59c27007519c77 Mon Sep 17 00:00:00 2001 From: illiliti Date: Fri, 4 Mar 2022 06:10:27 +0300 Subject: [PATCH 42/66] Initial netbsd support --- 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 #endif +#if defined(__NetBSD__) +#include +#include +#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..d2398fb 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,6 +9,9 @@ #include #elif defined(__FreeBSD__) #include +#elif defined(__NetBSD__) +#include +#include #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 +#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 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 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 #endif +#if defined(__NetBSD__) +#include +#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; } From a5f9a2a2c86abb7163d8f2c7fc34490dd6d26f29 Mon Sep 17 00:00:00 2001 From: illiliti Date: Fri, 4 Mar 2022 06:10:28 +0300 Subject: [PATCH 43/66] ci: Add NetBSD --- .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 From 845256009b0ef7fcf9d59ceaf769cc5e41200c15 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 23 Mar 2022 20:29:09 +0100 Subject: [PATCH 44/66] readme: Mention NetBSD --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ed6e8b..b8a705f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal seat management daemon, and a universal seat management library. -Currently supports Linux and FreeBSD. +Currently supports Linux and FreeBSD, and has experimental NetBSD support. ## What is seat management? From d5539dead8f258390c90e27acdc9f60a0cc68f2a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 28 Mar 2022 16:28:00 +0200 Subject: [PATCH 45/66] meson: library soversion arg should be string muon, a meson implementation in C, is more strict with its types and revealed this discrepancy between meson behavior and documentation. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0f267a6..337a4ae 100644 --- a/meson.build +++ b/meson.build @@ -178,7 +178,7 @@ symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), lib = library( 'seat', # This results in the library being called 'libseat' [ 'libseat/libseat.c', 'libseat/backend/noop.c' ], - soversion: libseat_soversion, + soversion: '@0@'.format(libseat_soversion), link_with: private_lib, include_directories: [include_directories('.', 'include')], install: true, From 684dd619455011bc08c85ae4c1b39394268b5646 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 09:54:06 +0200 Subject: [PATCH 46/66] terminal: Revert FreeBSD behavior in set_keyboard 4ad48cb305b3f847ab7d3c2d3f59c27007519c77 introduced support for NetBSD, which modified a number of our ifdefs. In that process, FreeBSD was accidentally excluded from an important code path that controls keyboard usage on the kernel console. Revert part of that change to restore FreeBSD behavior. --- common/terminal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 183c9bd..fa220a2 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -244,13 +244,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) { log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } -#elif defined(__FreeBSD__) +#if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { log_errorf("Could not set get terminal mode: %s", strerror(errno)); From 0462e9331d1648171bd47e62a2808f0a4d647239 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 10:41:16 +0200 Subject: [PATCH 47/66] wscons: Move to its own device type This reduces ifdefs and avoids overloading evdev as something it is not. --- common/evdev.c | 26 ++++---------------------- common/wscons.c | 27 +++++++++++++++++++++++++++ include/evdev.h | 5 ----- include/seat.h | 1 + include/wscons.h | 6 ++++++ meson.build | 1 + seatd/seat.c | 12 ++++++++++++ 7 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 common/wscons.c create mode 100644 include/wscons.h diff --git a/common/evdev.c b/common/evdev.c index d2398fb..7ec0fe2 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -9,11 +9,6 @@ #include #elif defined(__FreeBSD__) #include -#elif defined(__NetBSD__) -#include -#include -#else -#error Unsupported platform #endif #include "evdev.h" @@ -30,28 +25,15 @@ 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; + (void)path; + return 0; } int evdev_revoke(int fd) { (void)fd; return 0; } +#else +#error Unsupported platform #endif diff --git a/common/wscons.c b/common/wscons.c new file mode 100644 index 0000000..7fc8df5 --- /dev/null +++ b/common/wscons.c @@ -0,0 +1,27 @@ +#include +#include + +#if defined(__NetBSD__) +#include +#include +#endif + +#include "wscons.h" + +#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) + +#if defined(__NetBSD__) +int path_is_wscons(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; +} +#else +int path_is_wscons(const char *path) { + (void)path; + return 0; +} +#endif diff --git a/include/evdev.h b/include/evdev.h index da57828..5e6cfbf 100644 --- a/include/evdev.h +++ b/include/evdev.h @@ -4,9 +4,4 @@ int evdev_revoke(int fd); int path_is_evdev(const char *path); -#if defined(__linux__) || defined(__NetBSD__) -#include -int dev_is_evdev(dev_t device); -#endif - #endif diff --git a/include/seat.h b/include/seat.h index cc243b6..ff857e7 100644 --- a/include/seat.h +++ b/include/seat.h @@ -13,6 +13,7 @@ enum seat_device_type { SEAT_DEVICE_TYPE_NORMAL, SEAT_DEVICE_TYPE_EVDEV, SEAT_DEVICE_TYPE_DRM, + SEAT_DEVICE_TYPE_WSCONS, }; struct seat_device { diff --git a/include/wscons.h b/include/wscons.h new file mode 100644 index 0000000..bf0c10c --- /dev/null +++ b/include/wscons.h @@ -0,0 +1,6 @@ +#ifndef _SEATD_WSCONS_H +#define _SEATD_WSCONS_H + +int path_is_wscons(const char *path); + +#endif diff --git a/meson.build b/meson.build index 337a4ae..661b39a 100644 --- a/meson.build +++ b/meson.build @@ -114,6 +114,7 @@ server_files = [ 'common/connection.c', 'common/evdev.c', 'common/drm.c', + 'common/wscons.c', 'seatd/poller.c', 'seatd/seat.c', 'seatd/client.c', diff --git a/seatd/seat.c b/seatd/seat.c index 354273f..7a66a20 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -17,6 +17,7 @@ #include "protocol.h" #include "seat.h" #include "terminal.h" +#include "wscons.h" static int seat_close_client(struct client *client); static int vt_close(int vt); @@ -235,6 +236,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { type = SEAT_DEVICE_TYPE_EVDEV; } else if (path_is_drm(sanitized_path)) { type = SEAT_DEVICE_TYPE_DRM; + } else if (path_is_wscons(sanitized_path)) { + type = SEAT_DEVICE_TYPE_WSCONS; } else { log_errorf("%s is not a supported device type ", sanitized_path); errno = ENOENT; @@ -281,6 +284,9 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { case SEAT_DEVICE_TYPE_EVDEV: // Nothing to do here break; + case SEAT_DEVICE_TYPE_WSCONS: + // Nothing to do here + break; default: log_error("Invalid seat device type"); abort(); @@ -333,6 +339,9 @@ static int seat_deactivate_device(struct seat_device *seat_device) { return -1; } break; + case SEAT_DEVICE_TYPE_WSCONS: + // Nothing to do here + break; default: log_error("Invalid seat device type"); abort(); @@ -382,6 +391,9 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ case SEAT_DEVICE_TYPE_EVDEV: errno = EINVAL; return -1; + case SEAT_DEVICE_TYPE_WSCONS: + // Nothing to do here + break; default: log_error("Invalid seat device type"); abort(); From 8f8c9558e6279060f3ccc3363cb3558ffc9efd84 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 29 Mar 2022 10:46:09 +0200 Subject: [PATCH 48/66] drm: Make dev_is_drm local to logind backend This function is only used for logind, which is Linux-specific, but the presence in common/drm.c suggested that it had to be portable. Move it to the logind backend for now. --- common/drm.c | 25 +------------------------ include/drm.h | 5 ----- libseat/backend/logind.c | 12 ++++++++++-- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/common/drm.c b/common/drm.c index 0d8096a..45ed7e5 100644 --- a/common/drm.c +++ b/common/drm.c @@ -2,15 +2,6 @@ #include #include -#if defined(__linux__) -#include -#endif - -#if defined(__NetBSD__) -#include -#include -#endif - #include "drm.h" // From libdrm @@ -29,32 +20,18 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) +#if defined(__linux__) || 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) == 226; -} #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/include/drm.h b/include/drm.h index c8c3eeb..a8a5461 100644 --- a/include/drm.h +++ b/include/drm.h @@ -5,9 +5,4 @@ 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 -int dev_is_drm(dev_t device); -#endif - #endif diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 53523c8..2589e2f 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -28,6 +28,14 @@ #include "libseat.h" #include "log.h" +static int dev_major_is_drm(unsigned int dev_major) { + return dev_major == 226; +} + +static int dev_is_drm(dev_t device) { + return dev_major_is_drm(major(device)); +} + struct backend_logind { struct libseat base; const struct libseat_seat_listener *seat_listener; @@ -387,7 +395,7 @@ static int pause_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_e return 0; } - if (dev_is_drm(makedev(major, minor)) && strcmp(type, "gone") != 0) { + if (dev_major_is_drm(major) && strcmp(type, "gone") != 0) { log_debugf("DRM device paused: %s", type); assert(session->has_drm > 0); set_active(session, false); @@ -419,7 +427,7 @@ static int resume_device(sd_bus_message *msg, void *userdata, sd_bus_error *ret_ return 0; } - if (dev_is_drm(makedev(major, minor))) { + if (dev_major_is_drm(major)) { log_debug("DRM device resumed"); assert(session->has_drm > 0); set_active(session, true); From 85d0bf594362bf5d85b191711e6fc2a51f6bd21a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:27:39 +0000 Subject: [PATCH 49/66] seatd: handle client_create failure Failure to create the client causes a null pointer dereference. --- seatd/server.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/seatd/server.c b/seatd/server.c index 8ead54d..47d6e91 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -129,6 +129,12 @@ int server_add_client(struct server *server, int fd) { } struct client *client = client_create(server, fd); + if (client == NULL) { + log_errorf("Could not create client: %s", strerror(errno)); + close(fd); + return -1; + } + client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { From 2842f0e2b1eef5b648c76a8ae0ecbf8590bc873d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 23 Oct 2021 14:27:40 +0000 Subject: [PATCH 50/66] seatd: refuse to compile with missing get_peer impl Instead of using a stub, error out when get_peer isn't implemented for the target platform. client_create relies on it. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 0097792..a33bfe7 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -70,7 +70,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : (gid_t)-1; return 0; #else - return -1; +#error Unsupported platform #endif } From 6888653a8dd7e0a3124f3b7f1e3356ae9dc782e9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 30 Mar 2022 00:39:35 +0200 Subject: [PATCH 51/66] wscons: Fix STRLEN --- common/wscons.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/wscons.c b/common/wscons.c index 7fc8df5..33c757e 100644 --- a/common/wscons.c +++ b/common/wscons.c @@ -12,9 +12,9 @@ #if defined(__NetBSD__) int path_is_wscons(const char *path) { - const char *wskbd = "/dev/wskbd"; - const char *wsmouse = "/dev/wsmouse"; - const char *wsmux = "/dev/wsmux"; + static const char wskbd[] = "/dev/wskbd"; + static const char wsmouse[] = "/dev/wsmouse"; + static const char wsmux[] = "/dev/wsmux"; return strncmp(path, wskbd, STRLEN(wskbd)) == 0 || strncmp(path, wsmouse, STRLEN(wsmouse)) == 0 || strncmp(path, wsmux, STRLEN(wsmouse)) == 0; From a803ba0502cccf147eec7fbcacd11c5b8643c0e0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 May 2022 22:03:38 +0200 Subject: [PATCH 52/66] seatd-launch: Avoid argv[0] in help text --- seatd-launch/seatd-launch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 329ccef..65d4f33 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) { printf("%s", usage); return 0; case '?': - fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); + fprintf(stderr, "Try 'seatd-launch -h' for more information.\n"); return 1; default: abort(); From 14355639f8a31e8a8b1d46fddcddfa924aa5f426 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Sep 2022 12:25:37 +0000 Subject: [PATCH 53/66] man: document SEATD_VTBOUND --- man/seatd.1.scd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index f599a23..48e3f64 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -41,6 +41,11 @@ client-side of the protocol. The location of the socket for seatd is set at compile-time. +# ENVIRONMENT + +*SEATD_VTBOUND* + If set to "0", the seat will not be bound to a VT. + # SEE ALSO The libseat library, **, *seatd-launch*(1) From 9b8b6e0bf88f02b77835c977ca97017ac6ed850f Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Fri, 13 Jan 2023 11:03:43 -0800 Subject: [PATCH 54/66] noop: initialize initial_setup Otherwise the enable_seat callback is never called. --- libseat/backend/noop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index f69aac6..7db8a55 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -115,6 +115,7 @@ static struct libseat *noop_open_seat(const struct libseat_seat_listener *listen return NULL; } + backend->initial_setup = true; backend->seat_listener = listener; backend->seat_listener_data = data; backend->base.impl = &noop_impl; From 207e2a59363037c192278bc51e3693d88d115514 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 Jan 2023 11:43:46 +0000 Subject: [PATCH 55/66] man: add missing arg in -n syntax --- man/seatd.1.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 48e3f64..92f8e4b 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -13,7 +13,7 @@ seatd - A seat management daemon *-h* Show help message and quit. -*-n* +*-n * FD to notify readiness on. A single newline will be written and the fd closed when seatd is ready to serve requests. This is compatible with s6's notification protocol. From 3e0d510b2c46eb18ab7239b029e01475eb2e3810 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Sat, 11 Mar 2023 13:56:57 +0000 Subject: [PATCH 56/66] meson: fix seatdpath with absolute bindir Quoting the Meson documentation: > Note that the value returned for built-in options that end in `dir` > such as `bindir` and `libdir` is usually a path relative to (and > inside) the `prefix` but you should not rely on that, as it can also > be an absolute path [in some cases](Builtin-options.md#universal-options). > [`install_dir` arguments](Installing.md) handle that as expected > but if you need an absolute path, e.g. to use in a define etc., > you should use the path concatenation operator like this: > `get_option('prefix') / get_option('localstatedir')`. > Never manually join paths as if they were strings. The concatenation of two absolute paths caused seatd-launch in Nixpkgs to try to launch e.g. /nix/store/43wyk9s2l2z8cparnshbf24d39vm5272-seatd-0.7.0//nix/store/j9a7k4qqwc3byyfmpqwg46shmh6g82yf-seatd-0.7.0-bin/bin/seatd. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 661b39a..0c6c823 100644 --- a/meson.build +++ b/meson.build @@ -22,7 +22,7 @@ if defaultpath == '' endif endif -seatdpath = '@0@/@1@/seatd'.format(get_option('prefix'), get_option('bindir')) +seatdpath = get_option('prefix') / get_option('bindir') / 'seatd' cc = meson.get_compiler('c') From e5b018def8a672cf099df4270e9f3f224b51c09b Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Thu, 30 Mar 2023 07:58:49 -0300 Subject: [PATCH 57/66] noop: Return seat0 as the seat name wlroots' libinput backend expects the name of the seat to either match ID_SEAT from udev, or in case ID_SEAT returns nothing, match seat0. As noop has no seat switching, always returning seat0 as the session name fixes that. Signed-off-by: Anna (navi) Figueiredo Gomes --- libseat/backend/noop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 7db8a55..141ffd9 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -46,7 +46,7 @@ static int disable_seat(struct libseat *base) { static const char *seat_name(struct libseat *base) { (void)base; - return "noop"; + return "seat0"; } static int open_device(struct libseat *base, const char *path, int *fd) { From 56720a6275032ebafc4aed53d03612e5cc9d8ff7 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Thu, 30 Mar 2023 07:58:51 -0300 Subject: [PATCH 58/66] noop: Additional open flags for `open(2)` Matching the functionallity by the seatd open call. O_NONBLOCK is specially important for libseat, otherwise it hangs while trying to drain all events from an input device fd. Signed-off-by: Anna (navi) Figueiredo Gomes --- libseat/backend/noop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 141ffd9..18f26c3 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -52,7 +52,7 @@ static const char *seat_name(struct libseat *base) { static int open_device(struct libseat *base, const char *path, int *fd) { (void)base; - int tmpfd = open(path, O_RDWR | O_CLOEXEC); + int tmpfd = open(path, O_RDWR | O_NOCTTY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK); if (tmpfd < 0) { log_errorf("Failed to open device: %s", strerror(errno)); return -1; From 1bd042e5b0a524fb7d30953179474e60974aa6ee Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Tue, 23 May 2023 21:31:21 +0100 Subject: [PATCH 59/66] drm: Support drm-subtree drivers on FreeBSD The drm-kmod drivers use linuxkpi and end up with /dev/drm being the canonical path for the devices, but the drm-subtree drivers use drmkpi which has them appear under /dev/dri like Linux. Thus, adapt path_is_drm to recognise both on FreeBSD. --- common/drm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/common/drm.c b/common/drm.c index 45ed7e5..06d6720 100644 --- a/common/drm.c +++ b/common/drm.c @@ -10,7 +10,8 @@ #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) +#define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) +#define STR_HAS_PREFIX(prefix, s) (strncmp(prefix, s, STRLEN(prefix)) == 0) int drm_set_master(int fd) { return ioctl(fd, DRM_IOCTL_SET_MASTER, 0); @@ -22,15 +23,18 @@ int drm_drop_master(int fd) { #if defined(__linux__) || 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; + if (STR_HAS_PREFIX("/dev/dri/", path)) + return 1; + 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; + if (STR_HAS_PREFIX("/dev/dri/", path)) + return 1; + /* Some drivers have /dev/dri/X symlinked to /dev/drm/X */ + if (STR_HAS_PREFIX("/dev/drm/", path)) + return 1; + return 0; } #else #error Unsupported platform From dbaa859f2899442909ece685634bb16d37f6a2ce Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:47:06 +0200 Subject: [PATCH 60/66] define _BSD_SOURCE rather then __BSD_VISIBLE __BSD_VISIBLE was set to 0, causing issues on OpenBSD The proper way is to set _BSD_SOURCE --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0c6c823..18aca69 100644 --- a/meson.build +++ b/meson.build @@ -29,7 +29,7 @@ cc = meson.get_compiler('c') add_project_arguments( [ '-D_XOPEN_SOURCE=700', - '-D__BSD_VISIBLE', + '-D_BSD_SOURCE', '-D_NETBSD_SOURCE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath), From f2ff233c264a6332522c2aa05259b913e2e4af4b Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:48:14 +0200 Subject: [PATCH 61/66] No -lrt on OpenBSD XXX This is crude, should add meson tests --- meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 18aca69..36665de 100644 --- a/meson.build +++ b/meson.build @@ -158,8 +158,8 @@ if get_option('libseat-logind') != 'disabled' endif # needed for cross-compilation -realtime = meson.get_compiler('c').find_library('rt') -private_deps += realtime +# realtime = meson.get_compiler('c').find_library('rt') +# private_deps += realtime if with_builtin libseat_c_args += '-DBUILTIN_ENABLED=1' @@ -220,14 +220,14 @@ if with_server [ server_files, 'seatd/seatd.c' ], include_directories: [include_directories('.', 'include')], install: true, - dependencies: [realtime], +# dependencies: [realtime], ) executable( 'seatd-launch', [ 'seatd-launch/seatd-launch.c' ], include_directories: [include_directories('.', 'include')], install: true, - dependencies: [realtime], +# dependencies: [realtime], ) endif From 4b2ecdf936366c79f3c58ef09dee3d87ccca88a8 Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:49:24 +0200 Subject: [PATCH 62/66] Add basic OpenBSD support XXX more work needed to manage VT switches and proper XXX fbtab(4) support to allow for non-root users --- common/drm.c | 2 +- common/evdev.c | 2 +- common/terminal.c | 12 ++++++++++-- seatd/client.c | 17 +++++++++++++++++ tests/poller.c | 4 ++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/common/drm.c b/common/drm.c index 06d6720..2fbadd5 100644 --- a/common/drm.c +++ b/common/drm.c @@ -21,7 +21,7 @@ int drm_drop_master(int fd) { return ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); } -#if defined(__linux__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) int path_is_drm(const char *path) { if (STR_HAS_PREFIX("/dev/dri/", path)) return 1; diff --git a/common/evdev.c b/common/evdev.c index 7ec0fe2..a77bf36 100644 --- a/common/evdev.c +++ b/common/evdev.c @@ -25,7 +25,7 @@ int path_is_evdev(const char *path) { int evdev_revoke(int fd) { return ioctl(fd, EVIOCREVOKE, NULL); } -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) int path_is_evdev(const char *path) { (void)path; return 0; diff --git a/common/terminal.c b/common/terminal.c index fa220a2..7c1342e 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,7 +21,7 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW @@ -147,6 +147,14 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { } return 0; } +#elif defined(__OpenBSD__) +static int get_tty_path(int tty, char path[static TTYPATHLEN]) { + assert(tty >= 0); + if (snprintf(path, TTYPATHLEN, "/dev/ttyC%d", tty) == -1) { + return -1; + } + return 0; +} #else #error Unsupported platform #endif @@ -175,7 +183,7 @@ int terminal_current_vt(int fd) { return -1; } return st.v_active; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) int vt; int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); diff --git a/seatd/client.c b/seatd/client.c index a33bfe7..0ab16f8 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -55,6 +55,23 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { *uid = cred.unp_euid; *gid = cred.unp_egid; return 0; +#elif defined(__OpenBSD__) + struct sockpeercred peercred; + socklen_t len = sizeof(peercred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &len) == -1) { + // assume builtin backend + if (errno == EINVAL) { + *pid = getpid(); + *uid = getuid(); + *gid = getgid(); + return 0; + } + return -1; + } + *pid = peercred.pid; + *uid = peercred.uid; + *gid = peercred.gid; + return 0; #elif defined(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; diff --git a/tests/poller.c b/tests/poller.c index 382d9d2..dd36c7d 100644 --- a/tests/poller.c +++ b/tests/poller.c @@ -123,6 +123,10 @@ static int test_signal_event(int signal, void *data) { return 0; } +#ifdef __OpenBSD__ +#define SIGRTMIN SIGUSR1 +#endif + static void test_poller_single_signal(void) { struct poller poller; test_assert(poller_init(&poller) == 0); From a8aee6fa70f68d54fe5f8a0db935cf85e83f849e Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 5 Jul 2023 10:49:24 +0200 Subject: [PATCH 63/66] Add basic OpenBSD support XXX more work needed to manage VT switches and proper XXX fbtab(4) support to allow for non-root users --- common/wscons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/wscons.c b/common/wscons.c index 33c757e..121074c 100644 --- a/common/wscons.c +++ b/common/wscons.c @@ -10,7 +10,7 @@ #define STRLEN(s) ((sizeof(s) / sizeof(s[0])) - 1) -#if defined(__NetBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) int path_is_wscons(const char *path) { static const char wskbd[] = "/dev/wskbd"; static const char wsmouse[] = "/dev/wsmouse"; From 3e9ef69f14f630a719dd464f3c90a7932f1c8296 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 19 Jul 2023 11:18:33 +0200 Subject: [PATCH 64/66] Bump version to 0.8.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0c6c823..516d7d2 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.7.0', + version: '0.8.0', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 0746edbeaeb1c94a54bf833f6167b4a6b8237cbf Mon Sep 17 00:00:00 2001 From: Adrien Demarez Date: Tue, 24 Oct 2023 00:42:37 +0200 Subject: [PATCH 65/66] seatd: fix small bug in assert --- seatd/seat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index 7a66a20..d09b2eb 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -537,7 +537,7 @@ static int seat_disable_client(struct client *client) { errno = EBUSY; return -1; } - assert(seat->active_client = client); + assert(seat->active_client == client); // We *deactivate* all remaining fds. These may later be reactivated. // The reason we cannot just close them is that certain device fds, such From b4462cb033ad3172e6daa98a4eff2883f88ea524 Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Wed, 10 Jul 2024 15:19:41 +0200 Subject: [PATCH 66/66] attempt to support VT switches on OpenBSD --- common/terminal.c | 36 +++++++++++++++++++++++++++++++++--- seatd/client.c | 3 ++- seatd/seat.c | 3 ++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 7c1342e..5aac2dd 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -21,11 +21,17 @@ #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG SIGIO -#elif defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(__NetBSD__) #include #define K_ENABLE K_XLATE #define K_DISABLE K_RAW #define FRSIG 0 // unimplemented +#elif defined(__OpenBSD__) +#include +#include +#define K_ENABLE K_XLATE +#define K_DISABLE K_RAW +#define FRSIG SIGIO #else #error Unsupported platform #endif @@ -161,10 +167,16 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { int terminal_open(int vt) { char path[TTYPATHLEN]; + log_debugf("terminal_open vt %d", vt); +#ifdef __OpenBSD__ + if (vt > 0) + vt--; +#endif if (get_tty_path(vt, path) == -1) { log_errorf("Could not generate tty path: %s", strerror(errno)); return -1; } + log_debugf("terminal_open path %s", path); int fd = open(path, O_RDWR | O_NOCTTY); if (fd == -1) { log_errorf("Could not open target tty: %s", strerror(errno)); @@ -174,7 +186,7 @@ int terminal_open(int vt) { } int terminal_current_vt(int fd) { -#if defined(__linux__) || defined(__NetBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) struct vt_stat st; int res = ioctl(fd, VT_GETSTATE, &st); close(fd); @@ -183,7 +195,7 @@ int terminal_current_vt(int fd) { return -1; } return st.v_active; -#elif defined(__FreeBSD__) || defined(__OpenBSD__) +#elif defined(__FreeBSD__) int vt; int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); @@ -252,11 +264,20 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("Setting KD keyboard state to %d", enable); +#ifndef __OpenBSD1__ 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; } +#else + int mode = enable ? WSKBD_RAW : WSKBD_TRANSLATED; + if (ioctl(fd, WSKBDIO_SETMODE, &mode) == -1) { + log_errorf("Could not set keyboard mode to %s: %s", + enable ? "translated" : "raw", strerror(errno)); + return -1; + } +#endif #if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { @@ -279,10 +300,19 @@ int terminal_set_keyboard(int fd, bool enable) { int terminal_set_graphics(int fd, bool enable) { log_debugf("Setting KD graphics state to %d", enable); +#ifndef __OpenBSD1__ if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { log_errorf("Could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", strerror(errno)); return -1; } +#else + int mode = enable ? WSDISPLAYIO_MODE_MAPPED : WSDISPLAYIO_MODE_EMUL; + if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) { + log_errorf("Could not set graphics mode to %s: %s", + enable ? "mapped" : "emul", strerror(errno)); + return -1; + } +#endif return 0; } diff --git a/seatd/client.c b/seatd/client.c index 0ab16f8..481704e 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -327,7 +327,7 @@ static int handle_switch_session(struct client *client, int session) { log_error("Protocol error: no seat associated with client"); return -1; } - + log_debugf("handle_switch_session %d", session); if (seat_set_next_session(client, session) == -1) { goto error; } @@ -370,6 +370,7 @@ static int handle_ping(struct client *client) { static int client_handle_opcode(struct client *client, uint16_t opcode, size_t size) { int res = 0; + log_debugf("client_handle_opcode: %d\n", opcode); switch (opcode) { case CLIENT_OPEN_SEAT: { if (size != 0) { diff --git a/seatd/seat.c b/seatd/seat.c index d09b2eb..8820992 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -87,8 +87,8 @@ static int vt_close(int vt) { return -1; } terminal_set_process_switching(ttyfd, true); - terminal_set_keyboard(ttyfd, true); terminal_set_graphics(ttyfd, false); + terminal_set_keyboard(ttyfd, true); close(ttyfd); return 0; } @@ -107,6 +107,7 @@ static int vt_switch(struct seat *seat, int vt) { static int vt_ack(struct seat *seat, bool release) { int tty0fd = terminal_open(seat->cur_vt); + log_debugf("vt_ack VT %d %d\n", seat->cur_vt, release); if (tty0fd == -1) { log_errorf("Could not open tty0 to ack VT signal: %s", strerror(errno)); return -1;