From 2185e8f180f30a87d1a1f76505d9133e27cda1d6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 3 Nov 2020 15:22:46 +0100 Subject: [PATCH 001/159] ci: Clean up build manifests --- .builds/alpine.yml | 15 ++++----------- .builds/archlinux.yml | 12 +++--------- .builds/freebsd.yml | 13 ++++--------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index e048494..048e3ef 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -9,25 +9,18 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson build -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - scan-build: | - cd seatd ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh - check-format: | - cd seatd ninja -C build clang-format - git diff --exit-code + git -C seatd diff --exit-code diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 419254f..301e88b 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,21 +9,15 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build + meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - scan-build: | - cd seatd ninja -C build scan-build [ -z "$(ls -A build/meson-logs/scanbuild/ 2>/dev/null)" ] - smoketest: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index ca9a3c1..e13566a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -5,20 +5,15 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - cd seatd - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd - build: | - cd seatd ninja -C build - unittest: | - cd seatd ninja -C build test - smoketest: | - cd seatd rm -rf build - meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build + meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd ninja -C build - timeout -s KILL 30s ./.builds/smoketest-seatd.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | - cd seatd - timeout -s KILL 30s ./.builds/smoketest-builtin.sh + timeout -s KILL 30s ./seatd/.builds/smoketest-builtin.sh From 3c80a9db9628aec7009d7e51c1a3393bc801078c Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 21 Nov 2020 16:59:01 +0100 Subject: [PATCH 002/159] libseat: log error when failing to open socket The most common pain point I've seen with people trying out seat is forgetting to add themselves to whatever group the distro has chosen to own the socket. Logging this error and path of the socket should make it easier to tell why things aren't working. --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index f728a33..e4ce7c4 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -75,7 +75,7 @@ static int seatd_connect(void) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { - log_debugf("Could not connect to socket: %s", strerror(errno)); + log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); close(fd); return -1; }; From df8494af61356be3b2c575bd3f6a33090a286248 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 16:48:18 +0100 Subject: [PATCH 003/159] poller: Retry poll immediately on EINTR There is nothing for us to dispatch unless we wake on an fd, so just retry poll if it fails with EINTR instead of doing a full dispatch loop. --- seatd/poller.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/seatd/poller.c b/seatd/poller.c index 267929b..ceadb24 100644 --- a/seatd/poller.c +++ b/seatd/poller.c @@ -315,8 +315,10 @@ int poller_poll(struct poller *poller) { poller->dirty = false; } - if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { - return -1; + while (poll(poller->pollfds, poller->fd_event_sources, -1) == -1) { + if (errno != EINTR) { + return -1; + } } dispatch(poller); From e0782a825e769c67dab8222911414765c0839d24 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 01:03:37 +0100 Subject: [PATCH 004/159] client: More robust handling of client links --- seatd/client.c | 10 ++++------ seatd/seat.c | 7 +------ seatd/server.c | 3 +-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/seatd/client.c b/seatd/client.c index fcb238d..5cacae7 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -70,6 +70,7 @@ struct client *client_create(struct server *server, int client_fd) { client->server = server; client->connection.fd = client_fd; linked_list_init(&client->devices); + linked_list_insert(&server->idle_clients, &client->link); return client; } @@ -80,14 +81,9 @@ void client_destroy(struct client *client) { close(client->connection.fd); client->connection.fd = -1; } + linked_list_remove(&client->link); if (client->seat != NULL) { - // This should also close and remove all devices. This unlinks - // the client. seat_remove_client(client); - } else { - // If we are not a member of a seat, we will be on the idle - // clients list, so unlink the client manually. - linked_list_remove(&client->link); } if (client->event_source != NULL) { event_source_fd_destroy(client->event_source); @@ -149,6 +145,7 @@ static int handle_open_seat(struct client *client) { log_errorf("unable to add client to target seat: %s", strerror(errno)); return -1; } + linked_list_insert(&seat->clients, &client->link); size_t seat_name_len = strlen(seat_name); @@ -177,6 +174,7 @@ static int handle_close_seat(struct client *client) { return -1; } + linked_list_remove(&client->link); if (seat_remove_client(client) == -1) { log_error("unable to remove client from seat"); return -1; diff --git a/seatd/seat.c b/seatd/seat.c index 66b623d..b530a36 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -149,9 +149,8 @@ int seat_add_client(struct seat *seat, struct client *client) { log_debugf("registered client %p as session %d", (void *)client, client->session); client->seat = seat; - - linked_list_insert(&seat->clients, &client->link); log_debug("added client"); + return 0; } @@ -160,10 +159,6 @@ int seat_remove_client(struct client *client) { assert(client->seat); struct seat *seat = client->seat; - - // We must first remove the client to avoid reactivation - linked_list_remove(&client->link); - if (seat->next_client == client) { seat->next_client = NULL; } diff --git a/seatd/server.c b/seatd/server.c index acb366e..3ca73b3 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -132,13 +132,12 @@ int server_add_client(struct server *server, int fd) { client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { - client_destroy(client); log_errorf("could not add client socket to poller: %s", strerror(errno)); + client_destroy(client); return -1; } log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, client->gid); - linked_list_insert(&server->idle_clients, &client->link); return 0; } From 0d5f48f4339b984c2f5c44287984072506461fc9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 23 Nov 2020 01:49:09 +0100 Subject: [PATCH 005/159] terminal: Improve logging --- common/terminal.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 7e4088d..67cb1a1 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -182,7 +182,7 @@ int terminal_current_vt(int fd) { } int terminal_set_process_switching(int fd, bool enable) { - log_debug("setting process switching"); + log_debugf("setting process switching to %d", enable); struct vt_mode mode = { .mode = enable ? VT_PROCESS : VT_AUTO, .waitv = 0, @@ -192,7 +192,8 @@ int terminal_set_process_switching(int fd, bool enable) { }; if (ioctl(fd, VT_SETMODE, &mode) == -1) { - log_errorf("could not set VT mode: %s", strerror(errno)); + log_errorf("could not set VT mode to %s process switching: %s", + enable ? "enable" : "disable", strerror(errno)); return -1; } return 0; @@ -201,7 +202,7 @@ int terminal_set_process_switching(int fd, bool enable) { int terminal_switch_vt(int fd, int vt) { log_debugf("switching to VT %d", vt); if (ioctl(fd, VT_ACTIVATE, vt) == -1) { - log_errorf("could not activate VT: %s", strerror(errno)); + log_errorf("could not activate VT %d: %s", vt, strerror(errno)); return -1; } @@ -231,7 +232,8 @@ int terminal_ack_acquire(int fd) { int terminal_set_keyboard(int fd, bool enable) { log_debugf("setting KD keyboard state to %d", enable); if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { - log_errorf("could not set KD keyboard mode: %s", strerror(errno)); + log_errorf("could not set KD keyboard mode to %s: %s", + enable ? "enabled" : "disabled", strerror(errno)); return -1; } #if defined(__FreeBSD__) @@ -246,7 +248,8 @@ int terminal_set_keyboard(int fd, bool enable) { cfmakeraw(&tios); } if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) { - log_errorf("could not set terminal mode: %s", strerror(errno)); + log_errorf("could not set terminal mode to %s: %s", enable ? "sane" : "raw", + strerror(errno)); return -1; } #endif @@ -256,7 +259,8 @@ 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); if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { - log_errorf("could not set KD graphics mode: %s", strerror(errno)); + log_errorf("could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", + strerror(errno)); return -1; } return 0; From 1dbf1002055627f473ac891d1ea309f1f3ddc2c3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 24 Nov 2020 13:12:31 +0100 Subject: [PATCH 006/159] logind: switch_session should return 0 on success It currently returned -1 on failure and 1 on success. The API is intended to return -1 on failure and 0 on success, so fix that. --- 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 76297ce..f0cadce 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -172,7 +172,7 @@ static int switch_session(struct libseat *base, int s) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret < 0 ? -1 : 0; } static int disable_seat(struct libseat *base) { From e3a357badea76a6f67f00b07c15dc67dd08be560 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Dec 2020 19:01:56 +0000 Subject: [PATCH 007/159] libseat/backend/logind: stop waiting for CanGraphical Upstream says compositors should wait for DRM nodes using udev instead. --- libseat/backend/logind.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index f0cadce..c9a22c0 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -39,7 +39,6 @@ struct backend_logind { char *path; char *seat_path; - bool can_graphical; bool active; bool initial_setup; int has_drm; @@ -384,8 +383,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error goto error; } - if ((is_session && strcmp(s, "Active") == 0) || - (is_seat && strcmp(s, "CanGraphical"))) { + if (is_session && strcmp(s, "Active") == 0) { int ret; ret = sd_bus_message_enter_container(msg, 'v', "b"); if (ret < 0) { @@ -399,11 +397,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error } log_debugf("%s state changed: %d", s, value); - if (is_session) { - set_active(session, value); - } else { - session->can_graphical = value; - } + set_active(session, value); return 0; } else { sd_bus_message_skip(msg, "{sv}"); @@ -427,12 +421,10 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error // PropertiesChanged arg 3: changed properties without values sd_bus_message_enter_container(msg, 'a', "s"); while ((ret = sd_bus_message_read_basic(msg, 's', &s)) > 0) { - if ((is_session && strcmp(s, "Active") == 0) || - (is_seat && strcmp(s, "CanGraphical"))) { + if (is_session && strcmp(s, "Active") == 0) { sd_bus_error error = SD_BUS_ERROR_NULL; - const char *obj = is_session ? "org.freedesktop.login1.Session" - : "org.freedesktop.login1.Seat"; - const char *field = is_session ? "Active" : "CanGraphical"; + const char *obj = "org.freedesktop.login1.Session"; + const char *field = "Active"; bool value; ret = sd_bus_get_property_trivial(session->bus, "org.freedesktop.login1", session->path, obj, field, &error, 'b', @@ -443,11 +435,7 @@ static int properties_changed(sd_bus_message *msg, void *userdata, sd_bus_error } log_debugf("%s state changed: %d", field, value); - if (is_session) { - set_active(session, value); - } else { - session->can_graphical = value; - } + set_active(session, value); return 0; } } @@ -650,14 +638,6 @@ static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, goto error; } - backend->can_graphical = sd_seat_can_graphical(backend->seat); - while (!backend->can_graphical) { - if (poll_connection(backend, -1) == -1) { - log_errorf("Could not poll connection: %s", strerror(errno)); - goto error; - } - } - const char *env = getenv("XDG_SESSION_TYPE"); if (env != NULL) { set_type(backend, env); From e99e7d71f75394b68b581e86af4bdbdb43ee64ea Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Dec 2020 16:38:17 +0100 Subject: [PATCH 008/159] client: Do not use SOL_SOCKET for LOCAL_PEERCRED This is wrong, and leads to LOCAL_PEERCRED being interpreted as SO_DEBUG. 0 should be used instead. See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246189. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 5cacae7..edea23c 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -37,7 +37,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { #elif defined(__FreeBSD__) struct xucred cred; socklen_t len = sizeof cred; - if (getsockopt(fd, SOL_SOCKET, LOCAL_PEERCRED, &cred, &len) == -1) { + if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } *pid = -1; From 9b3bdcb12d0dea1cc5b96eefbc083114556df565 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 8 Dec 2020 16:42:13 +0100 Subject: [PATCH 009/159] client: Use cr_pid if available This is only available on FreeBSD 13, so test for that version. --- seatd/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seatd/client.c b/seatd/client.c index edea23c..162f4ba 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -40,7 +40,11 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } +#if __FreeBSD_version >= 1300030 + pid = cred.cr_pid; +#else *pid = -1; +#endif *uid = cred.cr_uid; *gid = cred.cr_ngroups > 0 ? cred.cr_groups[0] : (gid_t)-1; return 0; From 3755eea668cf7162ff861df9e8545ea5095792c1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 10 Dec 2020 10:07:43 +0100 Subject: [PATCH 010/159] client: Fix typo in cr_pid usage --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 162f4ba..a5a11ab 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -41,7 +41,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { return -1; } #if __FreeBSD_version >= 1300030 - pid = cred.cr_pid; + *pid = cred.cr_pid; #else *pid = -1; #endif From 1ececbbf361a227fa6449f51904f97f37763b5a4 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 14 Dec 2020 23:41:00 +0100 Subject: [PATCH 011/159] simpletest: Close fd after closing device --- examples/simpletest/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simpletest/main.c b/examples/simpletest/main.c index 0ec1c91..aeeace2 100644 --- a/examples/simpletest/main.c +++ b/examples/simpletest/main.c @@ -57,8 +57,8 @@ int main(int argc, char *argv[]) { return 1; } - close(fd); libseat_close_device(backend, device); + close(fd); libseat_close_seat(backend); return 0; } From 61b086511f86e8cc93528818ec0070c3c02a642f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 14 Dec 2020 23:40:44 +0100 Subject: [PATCH 012/159] logind: Send ReleaseControl when closing seat This is not strictly speaking necessary as detaching from the bus should trigger this automatically, but elogind apparently has issues with this. Doing this explicitly does no harm, so let's just do that. --- libseat/backend/logind.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index c9a22c0..0ae95b1 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -46,6 +46,7 @@ struct backend_logind { const struct seat_impl logind_impl; static struct backend_logind *backend_logind_from_libseat_backend(struct libseat *base); +static void release_control(struct backend_logind *backend); static void destroy(struct backend_logind *backend) { assert(backend); @@ -61,6 +62,7 @@ static void destroy(struct backend_logind *backend) { static int close_seat(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); + release_control(backend); destroy(backend); return 0; } @@ -280,6 +282,21 @@ static bool take_control(struct backend_logind *session) { return ret >= 0; } +static void release_control(struct backend_logind *session) { + sd_bus_message *msg = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + + int ret = sd_bus_call_method(session->bus, "org.freedesktop.login1", session->path, + "org.freedesktop.login1.Session", "ReleaseControl", &error, + &msg, ""); + if (ret < 0) { + log_errorf("Could not release control of session: %s", error.message); + } + + sd_bus_error_free(&error); + sd_bus_message_unref(msg); +} + static void set_active(struct backend_logind *backend, bool active) { if (backend->active == active) { return; @@ -652,9 +669,7 @@ static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, return &backend->base; error: - if (backend != NULL) { - destroy(backend); - } + destroy(backend); return NULL; } From b1f7ec1c4d753d0135cb88347efbc11c7039b2cb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Feb 2021 21:03:42 +0100 Subject: [PATCH 013/159] seat: Remove unused arg from seat_deactive_device --- seatd/seat.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index b530a36..a14eddd 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -302,9 +302,7 @@ done: return device; } -static int seat_deactivate_device(struct client *client, struct seat_device *seat_device) { - assert(client); - assert(client->seat); +static int seat_deactivate_device(struct seat_device *seat_device) { assert(seat_device && seat_device->fd > 0); if (!seat_device->active) { @@ -347,7 +345,7 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { linked_list_remove(&seat_device->link); if (seat_device->fd != -1) { - seat_deactivate_device(client, seat_device); + seat_deactivate_device(seat_device); close(seat_device->fd); } free(seat_device->path); @@ -512,7 +510,7 @@ static int seat_disable_client(struct client *client) { for (struct linked_list *elem = client->devices.next; elem != &client->devices; elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; - if (seat_deactivate_device(client, device) == -1) { + if (seat_deactivate_device(device) == -1) { log_errorf("unable to deactivate '%s': %s", device->path, strerror(errno)); } } From 45bab8b258b1cb0ba68eff3bfc3913e1e5d84b7d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 15:13:18 +0100 Subject: [PATCH 014/159] client: Replace pending_disable with state enum This simplifies logic in seat handling. --- include/client.h | 10 +++++++++- seatd/client.c | 1 + seatd/seat.c | 41 ++++++++++++++++++++--------------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/client.h b/include/client.h index 3b1f105..8746bea 100644 --- a/include/client.h +++ b/include/client.h @@ -10,6 +10,14 @@ struct server; +enum client_state { + CLIENT_NEW, + CLIENT_ACTIVE, + CLIENT_PENDING_DISABLE, + CLIENT_DISABLED, + CLIENT_CLOSED +}; + struct client { struct linked_list link; // seat::clients struct server *server; @@ -22,7 +30,7 @@ struct client { struct seat *seat; int session; - bool pending_disable; + enum client_state state; struct linked_list devices; }; diff --git a/seatd/client.c b/seatd/client.c index a5a11ab..949bbd8 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -73,6 +73,7 @@ struct client *client_create(struct server *server, int client_fd) { client->session = -1; client->server = server; client->connection.fd = client_fd; + client->state = CLIENT_NEW; linked_list_init(&client->devices); linked_list_insert(&server->idle_clients, &client->link); return client; diff --git a/seatd/seat.c b/seatd/seat.c index a14eddd..0893db7 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -200,15 +200,12 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { assert(strlen(path) > 0); struct seat *seat = client->seat; - if (client != seat->active_client) { - errno = EPERM; - return NULL; - } - - if (client->pending_disable) { + if (client->state != CLIENT_ACTIVE) { + log_error("client is not active"); errno = EPERM; return NULL; } + assert(seat->active_client == client); char sanitized_path[PATH_MAX]; if (realpath(path, sanitized_path) == NULL) { @@ -419,10 +416,15 @@ done: int seat_open_client(struct seat *seat, struct client *client) { assert(seat); assert(client); - assert(!client->pending_disable); + + if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { + log_error("client is not new or disabled"); + errno = EALREADY; + return -1; + } if (seat->active_client != NULL) { - log_error("client already active"); + log_error("seat already has active client"); errno = EBUSY; return -1; } @@ -439,6 +441,7 @@ int seat_open_client(struct seat *seat, struct client *client) { } } + client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { log_error("could not send enable signal"); @@ -474,7 +477,7 @@ int seat_close_client(struct client *client) { } } - client->pending_disable = false; + client->state = CLIENT_CLOSED; seat->active_client = NULL; log_debug("closed client"); @@ -491,17 +494,12 @@ static int seat_disable_client(struct client *client) { struct seat *seat = client->seat; - if (seat->active_client != client) { + if (client->state != CLIENT_ACTIVE) { log_error("client not active"); errno = EBUSY; return -1; } - - if (client->pending_disable) { - log_error("client already pending disable"); - errno = EBUSY; - return -1; - } + 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 @@ -515,7 +513,7 @@ static int seat_disable_client(struct client *client) { } } - client->pending_disable = true; + client->state = CLIENT_PENDING_DISABLE; if (client_send_disable_seat(seat->active_client) == -1) { log_error("could not send disable event"); return -1; @@ -530,13 +528,13 @@ int seat_ack_disable_client(struct client *client) { assert(client->seat); struct seat *seat = client->seat; - if (!client->pending_disable) { + if (client->state != CLIENT_PENDING_DISABLE) { log_error("client not pending disable"); errno = EBUSY; return -1; } - client->pending_disable = false; + client->state = CLIENT_DISABLED; log_debug("disabled client"); if (seat->active_client != client) { @@ -558,11 +556,12 @@ int seat_set_next_session(struct client *client, int session) { struct seat *seat = client->seat; - if (seat->active_client != client || client->pending_disable) { - log_error("client not active or pending disable"); + if (client->state != CLIENT_ACTIVE) { + log_error("client is not active"); errno = EPERM; return -1; } + assert(seat->active_client == client); if (session <= 0) { log_errorf("invalid session value: %d", session); From 65d91351ab8c2336601369b718cdc517ecbe6041 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 15:23:00 +0100 Subject: [PATCH 015/159] seatd: Tear down VT when disabled client closes If a client closed while it was disabled, the VT would not be torn down. If the user navigated back to the VT it belonged to, they would be stuck. When a client is disabled, open the fd for the VT it belonged to and perform regular teardown on it. --- include/seat.h | 1 - seatd/seat.c | 67 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/include/seat.h b/include/seat.h index cc21b7f..fa5873c 100644 --- a/include/seat.h +++ b/include/seat.h @@ -44,7 +44,6 @@ void seat_destroy(struct seat *seat); int seat_add_client(struct seat *seat, struct client *client); int seat_remove_client(struct client *client); int seat_open_client(struct seat *seat, struct client *client); -int seat_close_client(struct client *client); int seat_ack_disable_client(struct client *client); struct seat_device *seat_open_device(struct client *client, const char *path); diff --git a/seatd/seat.c b/seatd/seat.c index 0893db7..3e134b1 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -18,6 +18,8 @@ #include "seat.h" #include "terminal.h" +static int seat_close_client(struct client *client); + struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); if (seat == NULL) { @@ -77,19 +79,33 @@ static int vt_open(struct seat *seat, int vt) { return 0; } +static void vt_close_fd(int fd) { + terminal_set_process_switching(fd, true); + terminal_set_keyboard(fd, true); + terminal_set_graphics(fd, false); +} + static void vt_close(struct seat *seat) { if (seat->cur_ttyfd == -1) { return; } - terminal_set_process_switching(seat->cur_ttyfd, true); - terminal_set_keyboard(seat->cur_ttyfd, true); - terminal_set_graphics(seat->cur_ttyfd, false); - + vt_close_fd(seat->cur_ttyfd); close(seat->cur_ttyfd); seat->cur_ttyfd = -1; } +static int vt_close_num(int vt) { + int ttyfd = terminal_open(vt); + if (ttyfd == -1) { + log_errorf("could not open terminal %s", strerror(errno)); + return -1; + } + vt_close_fd(ttyfd); + close(ttyfd); + return 0; +} + static int vt_switch(struct seat *seat, int vt) { int ttyfd = terminal_open(seat->cur_vt); if (ttyfd == -1) { @@ -168,9 +184,7 @@ int seat_remove_client(struct client *client) { seat_close_device(client, device); } - if (seat->active_client == client) { - seat_close_client(client); - } + seat_close_client(client); client->seat = NULL; log_debug("removed client"); @@ -458,18 +472,12 @@ error: return -1; } -int seat_close_client(struct client *client) { +static int seat_close_client(struct client *client) { assert(client); assert(client->seat); struct seat *seat = client->seat; - if (seat->active_client != client) { - log_error("client not active"); - errno = EBUSY; - return -1; - } - while (!linked_list_empty(&client->devices)) { struct seat_device *device = (struct seat_device *)client->devices.next; if (seat_close_device(client, device) == -1) { @@ -477,14 +485,29 @@ int seat_close_client(struct client *client) { } } + bool was_current = seat->active_client == client; + if (was_current) { + seat->active_client = NULL; + seat_activate(seat); + } + + if (seat->vt_bound) { + if (was_current && seat->active_client == NULL) { + // This client was current, but there were no clients + // waiting to take this VT, so clean it up. + log_debug("closing active VT"); + vt_close(seat); + } else if (!was_current && client->state != CLIENT_CLOSED) { + // This client was not current, but as the client was + // running, we need to clean up the VT. + log_debug("closing inactive VT"); + vt_close_num(client->session); + } + } + client->state = CLIENT_CLOSED; - seat->active_client = NULL; log_debug("closed client"); - seat_activate(seat); - if (seat->vt_bound && seat->active_client == NULL) { - vt_close(seat); - } return 0; } @@ -543,10 +566,10 @@ int seat_ack_disable_client(struct client *client) { seat->active_client = NULL; seat_activate(seat); - if (seat->vt_bound && seat->active_client == NULL) { - vt_close(seat); - } + // If we're VT-bound, we've either de-activated a client on a foreign + // VT, in which case we need to do nothing, or disabled the current VT, + // in which case seat_activate would just immediately re-enable it. return 0; } From 152ee5102a10cf363222dc23ed9dd65ace2ebfc4 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 26 Feb 2021 20:34:27 -0800 Subject: [PATCH 016/159] meson: ignore 'man-pages' if 'server' is disabled `seatd.1` is the only man page, so it's not necessary to install it or require scdoc when the server is not built. --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cc13546..5b06e57 100644 --- a/meson.build +++ b/meson.build @@ -212,7 +212,11 @@ test( ) ) -scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) +if get_option('server').enabled() + scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) +else + scdoc = disabler() +endif if scdoc.found() sh = find_program('sh', native: true) From da3cbcc9436321e59b9e11fa8caa624e3d71ea35 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 18:23:53 +0100 Subject: [PATCH 017/159] libseat: Fix typo in doc string --- include/libseat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libseat.h b/include/libseat.h index 891cb86..5375cd6 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -131,7 +131,7 @@ int libseat_get_fd(struct libseat *seat); * milliseconds that might occur. * * Returns a positive number signifying processed internal messages on success. - * Returns 0-if no messages were processed. Returns -1 and sets errno on error. + * Returns 0 if no messages were processed. Returns -1 and sets errno on error. */ int libseat_dispatch(struct libseat *seat, int timeout); From 6cf751af2b0313bc9b78ea9e56dc72ec91325935 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 18:24:54 +0100 Subject: [PATCH 018/159] logind: Fix return values from close_device/get_fd --- libseat/backend/logind.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index 0ae95b1..c6f2aaf 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -151,7 +151,7 @@ static int close_device(struct libseat *base, int device_id) { sd_bus_error_free(&error); sd_bus_message_unref(msg); - return ret >= 0; + return ret < 0 ? -1 : 0; } static int switch_session(struct libseat *base, int s) { @@ -183,7 +183,13 @@ static int disable_seat(struct libseat *base) { static int get_fd(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); - return sd_bus_get_fd(backend->bus); + int fd = sd_bus_get_fd(backend->bus); + if (fd >= 0) { + return fd; + } + + errno = -fd; + return -1; } static int poll_connection(struct backend_logind *backend, int timeout) { From ff38ea595af7bdac330b44b01443742c015bf426 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Nov 2020 02:18:45 +0100 Subject: [PATCH 019/159] seatd: Set errno in seat_add_client --- seatd/seat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/seatd/seat.c b/seatd/seat.c index 3e134b1..4def100 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -139,16 +139,19 @@ int seat_add_client(struct seat *seat, struct client *client) { if (client->seat != NULL) { log_error("cannot add client: client is already a member of a seat"); + errno = EBUSY; return -1; } if (seat->vt_bound && seat->active_client != NULL) { log_error("cannot add client: seat is vt_bound and an active client already exists"); + errno = EBUSY; return -1; } if (client->session != -1) { log_error("cannot add client: client cannot be reused"); + errno = EINVAL; return -1; } @@ -156,6 +159,7 @@ int seat_add_client(struct seat *seat, struct client *client) { seat_update_vt(seat); if (seat->cur_vt == -1) { log_error("could not determine VT for client"); + errno = EINVAL; return -1; } client->session = seat->cur_vt; From 456d08dc834df5d980d6f95e9158b6b0673ebc2f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 19:57:20 +0100 Subject: [PATCH 020/159] Convert a few debug logs to error logs --- libseat/backend/seatd.c | 2 +- seatd/seat.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index e4ce7c4..2dea3ca 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -585,7 +585,7 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, } if (geteuid() != 0) { - log_debug("Built-in seatd instance requires root privileges"); + log_error("Built-in seatd instance requires root privileges"); return NULL; } diff --git a/seatd/seat.c b/seatd/seat.c index 4def100..5ed83b5 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -276,7 +276,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { switch (type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(fd) == -1) { - log_debugf("drm_set_master failed: %s", strerror(errno)); + log_errorf("could not make device fd drm master: %s", strerror(errno)); } break; case SEAT_DEVICE_TYPE_EVDEV: @@ -326,13 +326,13 @@ static int seat_deactivate_device(struct seat_device *seat_device) { switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_drop_master(seat_device->fd) == -1) { - log_debugf("drm_drop_master failed: %s", strerror(errno)); + log_errorf("could not revoke drm master on device fd: %s", strerror(errno)); return -1; } break; case SEAT_DEVICE_TYPE_EVDEV: if (evdev_revoke(seat_device->fd) == -1) { - log_debugf("evdev_revoke failed: %s", strerror(errno)); + log_errorf("could not revoke evdev on device fd: %s", strerror(errno)); return -1; } break; @@ -379,7 +379,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(seat_device->fd) == -1) { - log_debugf("drmset_master failed: %s", strerror(errno)); + log_errorf("could not make device fd drm master: %s", strerror(errno)); } seat_device->active = true; break; From ffd6f039f8b29ec9f53f6b88a432f8257a5489e2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:02:59 +0100 Subject: [PATCH 021/159] seatd: Clean up debug logs a bit --- seatd/seat.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index 5ed83b5..c34cfe1 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -34,7 +34,11 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { free(seat); return NULL; } - log_debugf("created seat '%s' (vt_bound: %d)", seat_name, vt_bound); + if (vt_bound) { + log_infof("created VT-bound seat '%s'", seat_name); + } else { + log_infof("created seat '%s'", seat_name); + } return seat; } @@ -144,7 +148,7 @@ int seat_add_client(struct seat *seat, struct client *client) { } if (seat->vt_bound && seat->active_client != NULL) { - log_error("cannot add client: seat is vt_bound and an active client already exists"); + log_error("cannot add client: seat is VT-bound and an active client already exists"); errno = EBUSY; return -1; } @@ -166,10 +170,9 @@ int seat_add_client(struct seat *seat, struct client *client) { } else { client->session = seat->session_cnt++; } - log_debugf("registered client %p as session %d", (void *)client, client->session); client->seat = seat; - log_debug("added client"); + log_infof("added client %d", client->session); return 0; } @@ -191,7 +194,7 @@ int seat_remove_client(struct client *client) { seat_close_client(client); client->seat = NULL; - log_debug("removed client"); + log_infof("removed client %d", client->session); return 0; } @@ -311,8 +314,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", (void *)seat, - (void *)client, path, device_id, device->ref_cnt); + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", seat->seat_name, + client->session, path, device_id, device->ref_cnt); return device; } @@ -349,8 +352,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(client->seat); assert(seat_device && seat_device->fd != -1); - log_debugf("seat: %p, client: %p, path: '%s', device_id: %d, ref_cnt: %d", - (void *)client->seat, (void *)client, seat_device->path, seat_device->device_id, + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", + client->seat->seat_name, client->session, seat_device->path, seat_device->device_id, seat_device->ref_cnt); seat_device->ref_cnt--; @@ -403,18 +406,20 @@ static int seat_activate(struct seat *seat) { struct client *next_client = NULL; if (seat->next_client != NULL) { - log_info("activating next queued client"); + log_debug("activating next queued client"); next_client = seat->next_client; seat->next_client = NULL; } else if (linked_list_empty(&seat->clients)) { log_info("no clients on seat to activate"); return -1; + } else if (seat->vt_bound && seat->cur_vt == -1) { + return -1; } else if (seat->vt_bound) { for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; elem = elem->next) { struct client *client = (struct client *)elem; if (client->session == seat->cur_vt) { - log_infof("activating client belonging to VT %d", seat->cur_vt); + log_debugf("activating client belonging to VT %d", seat->cur_vt); next_client = client; goto done; } @@ -423,7 +428,7 @@ static int seat_activate(struct seat *seat) { log_infof("no clients belonging to VT %d to activate", seat->cur_vt); return -1; } else { - log_info("activating first client on seat"); + log_debug("activating first client on seat"); next_client = (struct client *)seat->clients.next; } @@ -436,18 +441,21 @@ int seat_open_client(struct seat *seat, struct client *client) { assert(client); if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { - log_error("client is not new or disabled"); + log_errorf("could not enable client %d: client is not new or disabled", + client->session); errno = EALREADY; return -1; } if (seat->active_client != NULL) { - log_error("seat already has active client"); + log_errorf("could not enable client %d: seat already has active client", + client->session); errno = EBUSY; return -1; } if (seat->vt_bound && vt_open(seat, client->session) == -1) { + log_errorf("could not open VT for client %d", client->session); goto error; } @@ -455,18 +463,19 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s': %s", device->path, strerror(errno)); + log_errorf("unable to activate '%s' for client %d: %s", + device->path, client->session, strerror(errno)); } } client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { - log_error("could not send enable signal"); + log_errorf("could not send enable signal to client %d", client->session); goto error; } - log_info("client successfully enabled"); + log_infof("enabled client %d", client->session); return 0; error: @@ -510,7 +519,7 @@ static int seat_close_client(struct client *client) { } client->state = CLIENT_CLOSED; - log_debug("closed client"); + log_infof("closed client %d", client->session); return 0; } @@ -546,7 +555,7 @@ static int seat_disable_client(struct client *client) { return -1; } - log_debug("disabling client"); + log_infof("disabling client %d", client->session); return 0; } @@ -562,7 +571,7 @@ int seat_ack_disable_client(struct client *client) { } client->state = CLIENT_DISABLED; - log_debug("disabled client"); + log_infof("disabled client %d", client->session); if (seat->active_client != client) { return 0; @@ -607,7 +616,7 @@ int seat_set_next_session(struct client *client, int session) { } if (seat->vt_bound) { - log_infof("switching to VT %d from %d", session, seat->cur_vt); + log_infof("switching to VT %d from VT %d", session, seat->cur_vt); if (vt_switch(seat, session) == -1) { log_error("could not switch VT"); return -1; From cedd64c283794c5b6593f308cddde2cdab7c2bcf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:22:45 +0100 Subject: [PATCH 022/159] client: Remove link if seat_add_client succeeds Removing the link before before means that we can return without a link, resulting in a double-remove. --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index 949bbd8..286a3ae 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -145,11 +145,11 @@ static int handle_open_seat(struct client *client) { return -1; } - linked_list_remove(&client->link); if (seat_add_client(seat, client) == -1) { log_errorf("unable to add client to target seat: %s", strerror(errno)); return -1; } + linked_list_remove(&client->link); linked_list_insert(&seat->clients, &client->link); size_t seat_name_len = strlen(seat_name); From e173691cfd0fd06baec924f5df90eb1e9f4e8fb5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:44:31 +0100 Subject: [PATCH 023/159] seatd: Close cur_ttyfd in seat_destroy This fd would only still be set after closing clients if no clients were active on the current VT. --- seatd/seat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index c34cfe1..c737979 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -19,6 +19,8 @@ #include "terminal.h" static int seat_close_client(struct client *client); +static void vt_close(struct seat *seat); + struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); @@ -49,7 +51,7 @@ void seat_destroy(struct seat *seat) { assert(client->seat == seat); client_destroy(client); } - assert(seat->cur_ttyfd == -1); + vt_close(seat); linked_list_remove(&seat->link); free(seat->seat_name); free(seat); From 3a6a7e6b4c52119ddd0828808a210ae69c4392fe Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 27 Feb 2021 21:48:03 +0100 Subject: [PATCH 024/159] clang-format --- seatd/seat.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/seatd/seat.c b/seatd/seat.c index c737979..9c9f7eb 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -21,7 +21,6 @@ static int seat_close_client(struct client *client); static void vt_close(struct seat *seat); - struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); if (seat == NULL) { @@ -316,8 +315,8 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", seat->seat_name, - client->session, path, device_id, device->ref_cnt); + log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", + seat->seat_name, client->session, path, device_id, device->ref_cnt); return device; } @@ -355,8 +354,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(seat_device && seat_device->fd != -1); log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - client->seat->seat_name, client->session, seat_device->path, seat_device->device_id, - seat_device->ref_cnt); + client->seat->seat_name, client->session, seat_device->path, + seat_device->device_id, seat_device->ref_cnt); seat_device->ref_cnt--; if (seat_device->ref_cnt > 0) { @@ -444,14 +443,14 @@ int seat_open_client(struct seat *seat, struct client *client) { if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { log_errorf("could not enable client %d: client is not new or disabled", - client->session); + client->session); errno = EALREADY; return -1; } if (seat->active_client != NULL) { log_errorf("could not enable client %d: seat already has active client", - client->session); + client->session); errno = EBUSY; return -1; } @@ -465,8 +464,8 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s' for client %d: %s", - device->path, client->session, strerror(errno)); + log_errorf("unable to activate '%s' for client %d: %s", device->path, + client->session, strerror(errno)); } } From 79b90788bd1b836e3d5449722e40e4628326574d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 1 Mar 2021 01:11:37 +0100 Subject: [PATCH 025/159] log: Remove function name from log --- include/log.h | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/include/log.h b/include/log.h index 9aee33c..f5f423e 100644 --- a/include/log.h +++ b/include/log.h @@ -17,27 +17,21 @@ #define __FILENAME__ __FILE__ #endif -#define log_infof(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_infof(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_info(str) \ - _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_info(str) _logf(LIBSEAT_LOG_LEVEL_INFO, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#define log_errorf(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_errorf(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_error(str) \ - _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_error(str) _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s", __FILENAME__, __LINE__, str) #ifdef DEBUG -#define log_debugf(fmt, ...) \ - _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s: " fmt, __FILENAME__, __LINE__, __func__, \ - __VA_ARGS__) +#define log_debugf(fmt, ...) \ + _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) -#define log_debug(str) \ - _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s: %s", __FILENAME__, __LINE__, __func__, str) +#define log_debug(str) _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s", __FILENAME__, __LINE__, str) #else #define log_debugf(fmt, ...) #define log_debug(str) From e4c28227ec1de65ee6ce5bb52412a2a2cf4c0628 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Mar 2021 00:14:32 +0100 Subject: [PATCH 026/159] Normalize log texts a bit --- common/terminal.c | 38 +++++++------- seatd/client.c | 72 ++++++++++++++------------ seatd/seat.c | 128 ++++++++++++++++++++++------------------------ seatd/seatd.c | 18 +++---- seatd/server.c | 14 ++--- 5 files changed, 135 insertions(+), 135 deletions(-) diff --git a/common/terminal.c b/common/terminal.c index 67cb1a1..6274957 100644 --- a/common/terminal.c +++ b/common/terminal.c @@ -141,12 +141,12 @@ static int get_tty_path(int tty, char path[static TTYPATHLEN]) { int terminal_open(int vt) { char path[TTYPATHLEN]; if (get_tty_path(vt, path) == -1) { - log_errorf("could not generate tty path: %s", strerror(errno)); + log_errorf("Could not generate tty path: %s", strerror(errno)); return -1; } int fd = open(path, O_RDWR | O_NOCTTY); if (fd == -1) { - log_errorf("could not open target tty: %s", strerror(errno)); + log_errorf("Could not open target tty: %s", strerror(errno)); return -1; } return fd; @@ -158,7 +158,7 @@ int terminal_current_vt(int fd) { int res = ioctl(fd, VT_GETSTATE, &st); close(fd); if (res == -1) { - log_errorf("could not retrieve VT state: %s", strerror(errno)); + log_errorf("Could not retrieve VT state: %s", strerror(errno)); return -1; } return st.v_active; @@ -167,12 +167,12 @@ int terminal_current_vt(int fd) { int res = ioctl(fd, VT_GETACTIVE, &vt); close(fd); if (res == -1) { - log_errorf("could not retrieve VT state: %s", strerror(errno)); + log_errorf("Could not retrieve VT state: %s", strerror(errno)); return -1; } if (vt == -1) { - log_errorf("invalid vt: %d", vt); + log_errorf("Invalid VT: %d", vt); return -1; } return vt; @@ -182,7 +182,7 @@ int terminal_current_vt(int fd) { } int terminal_set_process_switching(int fd, bool enable) { - log_debugf("setting process switching to %d", enable); + log_debugf("Setting process switching to %d", enable); struct vt_mode mode = { .mode = enable ? VT_PROCESS : VT_AUTO, .waitv = 0, @@ -192,7 +192,7 @@ int terminal_set_process_switching(int fd, bool enable) { }; if (ioctl(fd, VT_SETMODE, &mode) == -1) { - log_errorf("could not set VT mode to %s process switching: %s", + log_errorf("Could not set VT mode to %s process switching: %s", enable ? "enable" : "disable", strerror(errno)); return -1; } @@ -200,9 +200,9 @@ int terminal_set_process_switching(int fd, bool enable) { } int terminal_switch_vt(int fd, int vt) { - log_debugf("switching to VT %d", vt); + log_debugf("Switching to VT %d", vt); if (ioctl(fd, VT_ACTIVATE, vt) == -1) { - log_errorf("could not activate VT %d: %s", vt, strerror(errno)); + log_errorf("Could not activate VT %d: %s", vt, strerror(errno)); return -1; } @@ -210,9 +210,9 @@ int terminal_switch_vt(int fd, int vt) { } int terminal_ack_release(int fd) { - log_debug("acking VT release"); + log_debug("Acking VT release"); if (ioctl(fd, VT_RELDISP, 1) == -1) { - log_errorf("could not ack VT release: %s", strerror(errno)); + log_errorf("Could not ack VT release: %s", strerror(errno)); return -1; } @@ -220,9 +220,9 @@ int terminal_ack_release(int fd) { } int terminal_ack_acquire(int fd) { - log_debug("acking VT acquire"); + log_debug("Acking VT acquire"); if (ioctl(fd, VT_RELDISP, VT_ACKACQ) == -1) { - log_errorf("could not ack VT acquire: %s", strerror(errno)); + log_errorf("Could not ack VT acquire: %s", strerror(errno)); return -1; } @@ -230,16 +230,16 @@ int terminal_ack_acquire(int fd) { } int terminal_set_keyboard(int fd, bool enable) { - log_debugf("setting KD keyboard state to %d", enable); + log_debugf("Setting KD keyboard state to %d", enable); if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) { - log_errorf("could not set KD keyboard mode to %s: %s", + log_errorf("Could not set KD keyboard mode to %s: %s", enable ? "enabled" : "disabled", strerror(errno)); return -1; } #if defined(__FreeBSD__) struct termios tios; if (tcgetattr(fd, &tios) == -1) { - log_errorf("could not set get terminal mode: %s", strerror(errno)); + log_errorf("Could not set get terminal mode: %s", strerror(errno)); return -1; } if (enable) { @@ -248,7 +248,7 @@ int terminal_set_keyboard(int fd, bool enable) { cfmakeraw(&tios); } if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) { - log_errorf("could not set terminal mode to %s: %s", enable ? "sane" : "raw", + log_errorf("Could not set terminal mode to %s: %s", enable ? "sane" : "raw", strerror(errno)); return -1; } @@ -257,9 +257,9 @@ 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); + log_debugf("Setting KD graphics state to %d", enable); if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) { - log_errorf("could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", + log_errorf("Could not set KD graphics mode to %s: %s", enable ? "graphics" : "text", strerror(errno)); return -1; } diff --git a/seatd/client.c b/seatd/client.c index 286a3ae..d0f321d 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -120,7 +120,7 @@ static int client_send_error(struct client *client, int error_code) { if (connection_put(&client->connection, &errheader, sizeof errheader) == -1 || connection_put(&client->connection, &errmsg, sizeof errmsg) == -1) { - log_error("could not send error to client"); + log_errorf("Could not send error to client: %s", strerror(errno)); return -1; } return 0; @@ -135,18 +135,18 @@ static char *client_get_seat_name(struct client *client) { static int handle_open_seat(struct client *client) { char *seat_name = client_get_seat_name(client); if (seat_name == NULL) { - log_error("could not get name of target seat"); + log_error("Could not get name of target seat"); return -1; } struct seat *seat = server_get_seat(client->server, seat_name); if (seat == NULL) { - log_error("unable to find seat by name"); + log_errorf("Could not find seat named %s", seat_name); return -1; } if (seat_add_client(seat, client) == -1) { - log_errorf("unable to add client to target seat: %s", strerror(errno)); + log_errorf("Could not add client to target seat: %s", strerror(errno)); return -1; } linked_list_remove(&client->link); @@ -165,7 +165,7 @@ static int handle_open_seat(struct client *client) { if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_put(&client->connection, &rmsg, sizeof rmsg) == -1 || connection_put(&client->connection, seat_name, seat_name_len) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -175,13 +175,13 @@ static int handle_open_seat(struct client *client) { static int handle_close_seat(struct client *client) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } linked_list_remove(&client->link); if (seat_remove_client(client) == -1) { - log_error("unable to remove client from seat"); + log_error("Could not remove client from seat"); return -1; } linked_list_insert(&client->server->idle_clients, &client->link); @@ -192,7 +192,7 @@ static int handle_close_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -201,25 +201,25 @@ static int handle_close_seat(struct client *client) { static int handle_open_device(struct client *client, char *path) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } struct seat_device *device = seat_open_device(client, path); if (device == NULL) { - log_errorf("could not open device: %s", strerror(errno)); + log_errorf("Could not open device: %s", strerror(errno)); goto fail; } int dupfd = dup(device->fd); if (dupfd == -1) { - log_errorf("could not dup fd: %s", strerror(errno)); + log_errorf("Could not dup fd: %s", strerror(errno)); seat_close_device(client, device); goto fail; } if (connection_put_fd(&client->connection, dupfd) == -1) { - log_errorf("unable to queue fd for sending: %s", strerror(errno)); + log_errorf("Could not queue fd for sending: %s", strerror(errno)); return -1; } @@ -233,7 +233,7 @@ static int handle_open_device(struct client *client, char *path) { if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_put(&client->connection, &msg, sizeof msg) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -245,19 +245,19 @@ fail: static int handle_close_device(struct client *client, int device_id) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } struct seat_device *device = seat_find_device(client, device_id); if (device == NULL) { - log_error("no such device"); + log_error("No such device"); errno = EBADF; goto fail; } if (seat_close_device(client, device) == -1) { - log_errorf("could not close device: %s", strerror(errno)); + log_errorf("Could not close device: %s", strerror(errno)); goto fail; } @@ -267,7 +267,7 @@ static int handle_close_device(struct client *client, int device_id) { }; if (connection_put(&client->connection, &header, sizeof header) == -1) { - log_errorf("unable to write response: %s", strerror(errno)); + log_errorf("Could not write response: %s", strerror(errno)); return -1; } @@ -279,7 +279,7 @@ fail: static int handle_switch_session(struct client *client, int session) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } @@ -295,7 +295,7 @@ error: static int handle_disable_seat(struct client *client) { if (client->seat == NULL) { - log_error("protocol error: no seat associated with client"); + log_error("Protocol error: no seat associated with client"); return -1; } @@ -314,7 +314,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s switch (opcode) { case CLIENT_OPEN_SEAT: { if (size != 0) { - log_error("protocol error: invalid open_seat message"); + log_error("Protocol error: invalid open_seat message"); return -1; } res = handle_open_seat(client); @@ -322,7 +322,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s } case CLIENT_CLOSE_SEAT: { if (size != 0) { - log_error("protocol error: invalid close_seat message"); + log_error("Protocol error: invalid close_seat message"); return -1; } res = handle_close_seat(client); @@ -333,11 +333,11 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s struct proto_client_open_device msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1 || sizeof msg + msg.path_len > size || msg.path_len > MAX_PATH_LEN) { - log_error("protocol error: invalid open_device message"); + log_error("Protocol error: invalid open_device message"); return -1; } if (connection_get(&client->connection, path, msg.path_len) == -1) { - log_error("protocol error: invalid open_device message"); + log_error("Protocol error: invalid open_device message"); return -1; } @@ -347,7 +347,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s case CLIENT_CLOSE_DEVICE: { struct proto_client_close_device msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1) { - log_error("protocol error: invalid close_device message"); + log_error("Protocol error: invalid close_device message"); return -1; } @@ -357,7 +357,7 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s case CLIENT_SWITCH_SESSION: { struct proto_client_switch_session msg; if (sizeof msg > size || connection_get(&client->connection, &msg, sizeof msg) == -1) { - log_error("protocol error: invalid switch_session message"); + log_error("Protocol error: invalid switch_session message"); return -1; } @@ -366,14 +366,14 @@ static int client_handle_opcode(struct client *client, uint16_t opcode, size_t s } case CLIENT_DISABLE_SEAT: { if (size != 0) { - log_error("protocol error: invalid disable_seat message"); + log_error("Protocol error: invalid disable_seat message"); return -1; } res = handle_disable_seat(client); break; } default: - log_errorf("protocol error: unknown opcode: %d", opcode); + log_errorf("Protocol error: unknown opcode: %d", opcode); res = -1; break; } @@ -390,7 +390,7 @@ int client_send_disable_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_flush(&client->connection) == -1) { - log_error("unable to send event"); + log_errorf("Could not send event: %s", strerror(errno)); return -1; } return 0; @@ -403,7 +403,7 @@ int client_send_enable_seat(struct client *client) { }; if (connection_put(&client->connection, &header, sizeof header) == -1 || connection_flush(&client->connection) == -1) { - log_error("unable to send event"); + log_errorf("Could not send event: %s", strerror(errno)); return -1; } return 0; @@ -414,18 +414,18 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { struct client *client = data; if (mask & EVENT_ERROR) { - log_error("connection error"); + log_error("Connection error"); goto fail; } if (mask & EVENT_HANGUP) { - log_info("client disconnected"); + log_info("Client disconnected"); goto fail; } if (mask & EVENT_WRITABLE) { int len = connection_flush(&client->connection); if (len == -1 && errno != EAGAIN) { - log_error("could not flush client connection"); + log_errorf("Could not flush client connection: %s", strerror(errno)); goto fail; } else if (len >= 0) { event_source_fd_update(client->event_source, EVENT_READABLE); @@ -434,8 +434,12 @@ int client_handle_connection(int fd, uint32_t mask, void *data) { if (mask & EVENT_READABLE) { int len = connection_read(&client->connection); - if (len == 0 || (len == -1 && errno != EAGAIN)) { - log_error("could not read client connection"); + if (len == -1 && errno != EAGAIN) { + log_errorf("Could not read client connection: %s", strerror(errno)); + goto fail; + } + if (len == 0) { + log_error("Could not read client connection: zero-length read"); goto fail; } diff --git a/seatd/seat.c b/seatd/seat.c index 9c9f7eb..9ad4af2 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -36,9 +36,9 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { return NULL; } if (vt_bound) { - log_infof("created VT-bound seat '%s'", seat_name); + log_infof("Created VT-bound seat %s", seat_name); } else { - log_infof("created seat '%s'", seat_name); + log_infof("Created seat %s", seat_name); } return seat; } @@ -59,7 +59,7 @@ void seat_destroy(struct seat *seat) { static void seat_update_vt(struct seat *seat) { int tty0fd = terminal_open(0); if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); + log_errorf("Could not open tty0 to update VT: %s", strerror(errno)); return; } seat->cur_vt = terminal_current_vt(tty0fd); @@ -74,7 +74,7 @@ static int vt_open(struct seat *seat, int vt) { } seat->cur_ttyfd = terminal_open(vt); if (seat->cur_ttyfd == -1) { - log_errorf("could not open terminal for vt %d: %s", vt, strerror(errno)); + log_errorf("Could not open terminal for VT %d: %s", vt, strerror(errno)); return -1; } @@ -103,7 +103,7 @@ static void vt_close(struct seat *seat) { static int vt_close_num(int vt) { int ttyfd = terminal_open(vt); if (ttyfd == -1) { - log_errorf("could not open terminal %s", strerror(errno)); + log_errorf("Could not open terminal to clean up VT %d: %s", vt, strerror(errno)); return -1; } vt_close_fd(ttyfd); @@ -114,7 +114,7 @@ static int vt_close_num(int vt) { static int vt_switch(struct seat *seat, int vt) { int ttyfd = terminal_open(seat->cur_vt); if (ttyfd == -1) { - log_errorf("could not open terminal: %s", strerror(errno)); + log_errorf("Could not open terminal to switch to VT %d: %s", vt, strerror(errno)); return -1; } terminal_set_process_switching(ttyfd, true); @@ -126,7 +126,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); if (tty0fd == -1) { - log_errorf("unable to open tty0: %s", strerror(errno)); + log_errorf("Could not open tty0 to ack VT signal: %s", strerror(errno)); return -1; } if (release) { @@ -143,19 +143,19 @@ int seat_add_client(struct seat *seat, struct client *client) { assert(client); if (client->seat != NULL) { - log_error("cannot add client: client is already a member of a seat"); + log_error("Could not add client: client is already a member of a seat"); errno = EBUSY; return -1; } if (seat->vt_bound && seat->active_client != NULL) { - log_error("cannot add client: seat is VT-bound and an active client already exists"); + log_error("Could not add client: seat is VT-bound and has an active client"); errno = EBUSY; return -1; } if (client->session != -1) { - log_error("cannot add client: client cannot be reused"); + log_error("Could not add client: client cannot be reused"); errno = EINVAL; return -1; } @@ -163,7 +163,7 @@ int seat_add_client(struct seat *seat, struct client *client) { if (seat->vt_bound) { seat_update_vt(seat); if (seat->cur_vt == -1) { - log_error("could not determine VT for client"); + log_error("Could not determine VT for client"); errno = EINVAL; return -1; } @@ -173,7 +173,7 @@ int seat_add_client(struct seat *seat, struct client *client) { } client->seat = seat; - log_infof("added client %d", client->session); + log_infof("Added client %d to %s", client->session, seat->seat_name); return 0; } @@ -195,7 +195,7 @@ int seat_remove_client(struct client *client) { seat_close_client(client); client->seat = NULL; - log_infof("removed client %d", client->session); + log_infof("Removed client %d from %s", client->session, seat->seat_name); return 0; } @@ -222,8 +222,10 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { assert(strlen(path) > 0); struct seat *seat = client->seat; + log_debugf("Opening device %s for client %d on %s", path, client->session, seat->seat_name); + if (client->state != CLIENT_ACTIVE) { - log_error("client is not active"); + log_error("Could open device: client is not active"); errno = EPERM; return NULL; } @@ -231,7 +233,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { char sanitized_path[PATH_MAX]; if (realpath(path, sanitized_path) == NULL) { - log_errorf("invalid path '%s': %s", path, strerror(errno)); + log_errorf("Could not canonicalize path %s: %s", path, strerror(errno)); return NULL; } @@ -241,7 +243,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { } else if (path_is_drm(sanitized_path)) { type = SEAT_DEVICE_TYPE_DRM; } else { - log_errorf("invalid path '%s'", sanitized_path); + log_errorf("%s is not a supported device type ", sanitized_path); errno = ENOENT; return NULL; } @@ -266,34 +268,34 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { } if (device_count >= MAX_SEAT_DEVICES) { - log_error("max seat devices exceeded"); + log_error("Client exceeded max seat devices"); errno = EMFILE; return NULL; } int fd = open(sanitized_path, O_RDWR | O_NOCTTY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK); if (fd == -1) { - log_errorf("could not open file: %s", strerror(errno)); + log_errorf("Could not open file: %s", strerror(errno)); return NULL; } switch (type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(fd) == -1) { - log_errorf("could not make device fd drm master: %s", strerror(errno)); + log_errorf("Could not make device fd drm master: %s", strerror(errno)); } break; case SEAT_DEVICE_TYPE_EVDEV: // Nothing to do here break; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } device = calloc(1, sizeof(struct seat_device)); if (device == NULL) { - log_errorf("could not alloc device for '%s': %s", sanitized_path, strerror(errno)); + log_errorf("Allocation failed: %s", strerror(errno)); close(fd); errno = ENOMEM; return NULL; @@ -301,7 +303,7 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { device->path = strdup(sanitized_path); if (device->path == NULL) { - log_errorf("could not dup path for '%s': %s", sanitized_path, strerror(errno)); + log_errorf("Allocation failed: %s", strerror(errno)); close(fd); free(device); return NULL; @@ -315,8 +317,6 @@ struct seat_device *seat_open_device(struct client *client, const char *path) { linked_list_insert(&client->devices, &device->link); done: - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - seat->seat_name, client->session, path, device_id, device->ref_cnt); return device; } @@ -330,18 +330,18 @@ static int seat_deactivate_device(struct seat_device *seat_device) { switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_drop_master(seat_device->fd) == -1) { - log_errorf("could not revoke drm master on device fd: %s", strerror(errno)); + log_errorf("Could not revoke drm master on device fd: %s", strerror(errno)); return -1; } break; case SEAT_DEVICE_TYPE_EVDEV: if (evdev_revoke(seat_device->fd) == -1) { - log_errorf("could not revoke evdev on device fd: %s", strerror(errno)); + log_errorf("Could not revoke evdev on device fd: %s", strerror(errno)); return -1; } break; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } seat_device->active = false; @@ -353,9 +353,8 @@ int seat_close_device(struct client *client, struct seat_device *seat_device) { assert(client->seat); assert(seat_device && seat_device->fd != -1); - log_debugf("seat: '%s', client: %d, path: '%s', device_id: %d, ref_cnt: %d", - client->seat->seat_name, client->session, seat_device->path, - seat_device->device_id, seat_device->ref_cnt); + log_debugf("Closing device %s for client %d on %s", seat_device->path, client->session, + client->seat->seat_name); seat_device->ref_cnt--; if (seat_device->ref_cnt > 0) { @@ -383,7 +382,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ switch (seat_device->type) { case SEAT_DEVICE_TYPE_DRM: if (drm_set_master(seat_device->fd) == -1) { - log_errorf("could not make device fd drm master: %s", strerror(errno)); + log_errorf("Could not make device fd drm master: %s", strerror(errno)); } seat_device->active = true; break; @@ -391,7 +390,7 @@ static int seat_activate_device(struct client *client, struct seat_device *seat_ errno = EINVAL; return -1; default: - log_error("invalid seat device type"); + log_error("Invalid seat device type"); abort(); } @@ -407,11 +406,11 @@ static int seat_activate(struct seat *seat) { struct client *next_client = NULL; if (seat->next_client != NULL) { - log_debug("activating next queued client"); + log_debugf("Activating next queued client on %s", seat->seat_name); next_client = seat->next_client; seat->next_client = NULL; } else if (linked_list_empty(&seat->clients)) { - log_info("no clients on seat to activate"); + log_infof("No clients on %s to activate", seat->seat_name); return -1; } else if (seat->vt_bound && seat->cur_vt == -1) { return -1; @@ -420,16 +419,16 @@ static int seat_activate(struct seat *seat) { elem = elem->next) { struct client *client = (struct client *)elem; if (client->session == seat->cur_vt) { - log_debugf("activating client belonging to VT %d", seat->cur_vt); + log_debugf("Activating client belonging to VT %d", seat->cur_vt); next_client = client; goto done; } } - log_infof("no clients belonging to VT %d to activate", seat->cur_vt); + log_infof("No clients belonging to VT %d to activate", seat->cur_vt); return -1; } else { - log_debug("activating first client on seat"); + log_debugf("Activating first client on %s", seat->seat_name); next_client = (struct client *)seat->clients.next; } @@ -442,21 +441,19 @@ int seat_open_client(struct seat *seat, struct client *client) { assert(client); if (client->state != CLIENT_NEW && client->state != CLIENT_DISABLED) { - log_errorf("could not enable client %d: client is not new or disabled", - client->session); + log_error("Could not enable client: client is not new or disabled"); errno = EALREADY; return -1; } if (seat->active_client != NULL) { - log_errorf("could not enable client %d: seat already has active client", - client->session); + log_error("Could not enable client: seat already has an active client"); errno = EBUSY; return -1; } if (seat->vt_bound && vt_open(seat, client->session) == -1) { - log_errorf("could not open VT for client %d", client->session); + log_error("Could not open VT for client"); goto error; } @@ -464,19 +461,18 @@ int seat_open_client(struct seat *seat, struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_activate_device(client, device) == -1) { - log_errorf("unable to activate '%s' for client %d: %s", device->path, - client->session, strerror(errno)); + log_errorf("Could not activate %s: %s", device->path, strerror(errno)); } } client->state = CLIENT_ACTIVE; seat->active_client = client; if (client_send_enable_seat(client) == -1) { - log_errorf("could not send enable signal to client %d", client->session); + log_error("Could not send enable signal to client"); goto error; } - log_infof("enabled client %d", client->session); + log_infof("Opened client %d on %s", client->session, seat->seat_name); return 0; error: @@ -495,7 +491,7 @@ static int seat_close_client(struct client *client) { while (!linked_list_empty(&client->devices)) { struct seat_device *device = (struct seat_device *)client->devices.next; if (seat_close_device(client, device) == -1) { - log_errorf("unable to close '%s': %s", device->path, strerror(errno)); + log_errorf("Could not close %s: %s", device->path, strerror(errno)); } } @@ -509,18 +505,18 @@ static int seat_close_client(struct client *client) { if (was_current && seat->active_client == NULL) { // This client was current, but there were no clients // waiting to take this VT, so clean it up. - log_debug("closing active VT"); + log_debug("Closing active VT"); vt_close(seat); } else if (!was_current && client->state != CLIENT_CLOSED) { // This client was not current, but as the client was // running, we need to clean up the VT. - log_debug("closing inactive VT"); + log_debug("Closing inactive VT"); vt_close_num(client->session); } } client->state = CLIENT_CLOSED; - log_infof("closed client %d", client->session); + log_infof("Closed client %d on %s", client->session, seat->seat_name); return 0; } @@ -532,7 +528,7 @@ static int seat_disable_client(struct client *client) { struct seat *seat = client->seat; if (client->state != CLIENT_ACTIVE) { - log_error("client not active"); + log_error("Could not disable client: client is not active"); errno = EBUSY; return -1; } @@ -546,17 +542,17 @@ static int seat_disable_client(struct client *client) { elem = elem->next) { struct seat_device *device = (struct seat_device *)elem; if (seat_deactivate_device(device) == -1) { - log_errorf("unable to deactivate '%s': %s", device->path, strerror(errno)); + log_errorf("Could not deactivate %s: %s", device->path, strerror(errno)); } } client->state = CLIENT_PENDING_DISABLE; if (client_send_disable_seat(seat->active_client) == -1) { - log_error("could not send disable event"); + log_error("Could not send disable event"); return -1; } - log_infof("disabling client %d", client->session); + log_infof("Disabling client %d on %s", client->session, seat->seat_name); return 0; } @@ -566,13 +562,13 @@ int seat_ack_disable_client(struct client *client) { struct seat *seat = client->seat; if (client->state != CLIENT_PENDING_DISABLE) { - log_error("client not pending disable"); + log_error("Could not ack disable: client is not pending disable"); errno = EBUSY; return -1; } client->state = CLIENT_DISABLED; - log_infof("disabled client %d", client->session); + log_infof("Disabled client %d on %s", client->session, seat->seat_name); if (seat->active_client != client) { return 0; @@ -594,32 +590,32 @@ int seat_set_next_session(struct client *client, int session) { struct seat *seat = client->seat; if (client->state != CLIENT_ACTIVE) { - log_error("client is not active"); + log_error("Could not set next session: client is not active"); errno = EPERM; return -1; } assert(seat->active_client == client); if (session <= 0) { - log_errorf("invalid session value: %d", session); + log_errorf("Could not set next session: invalid session value %d", session); errno = EINVAL; return -1; } if (session == client->session) { - log_info("requested session is already active"); + log_info("Could not set next session: requested session is already active"); return 0; } if (seat->next_client != NULL) { - log_info("switch is already queued"); + log_info("Could not set next session: switch is already queued"); return 0; } if (seat->vt_bound) { - log_infof("switching to VT %d from VT %d", session, seat->cur_vt); + log_infof("Switching from VT %d to VT %d", seat->cur_vt, session); if (vt_switch(seat, session) == -1) { - log_error("could not switch VT"); + log_error("Could not switch VT"); return -1; } return 0; @@ -636,12 +632,12 @@ int seat_set_next_session(struct client *client, int session) { } if (target == NULL) { - log_error("no valid switch available"); + log_error("Could not set next session: no such client"); errno = EINVAL; return -1; } - log_infof("queuing switch client with session %d", session); + log_infof("Queuing switch to client %d on %s", session, seat->seat_name); seat->next_client = target; seat_disable_client(seat->active_client); return 0; @@ -654,7 +650,7 @@ int seat_vt_activate(struct seat *seat) { return -1; } seat_update_vt(seat); - log_debug("activating VT"); + log_debug("Activating VT"); vt_ack(seat, false); if (seat->active_client == NULL) { seat_activate(seat); @@ -670,7 +666,7 @@ int seat_vt_release(struct seat *seat) { } seat_update_vt(seat); - log_debug("releasing VT"); + log_debug("Releasing VT"); if (seat->active_client != NULL) { seat_disable_client(seat->active_client); } diff --git a/seatd/seatd.c b/seatd/seatd.c index b601bce..278f857 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -24,7 +24,7 @@ static int open_socket(const char *path, int uid, int gid) { } addr = {{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)); + log_errorf("Could not create socket: %s", strerror(errno)); return -1; } @@ -32,21 +32,21 @@ static int open_socket(const char *path, int uid, int gid) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (bind(fd, &addr.generic, size) == -1) { - log_errorf("could not bind socket: %s", strerror(errno)); + log_errorf("Could not bind socket: %s", strerror(errno)); close(fd); return -1; } if (listen(fd, LISTEN_BACKLOG) == -1) { - log_errorf("could not listen on socket: %s", strerror(errno)); + log_errorf("Could not listen on socket: %s", strerror(errno)); close(fd); return -1; } if (uid != 0 || gid != 0) { if (chown(path, uid, gid) == -1) { - log_errorf("could not chown socket to uid %d, gid %d: %s", uid, gid, + log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); } else if (chmod(path, 0770) == -1) { - log_errorf("could not chmod socket: %s", strerror(errno)); + log_errorf("Could not chmod socket: %s", strerror(errno)); } } return fd; @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) { socket_path = SEATD_DEFAULTPATH; struct stat st; if (stat(socket_path, &st) == 0) { - log_info("removing leftover seatd socket"); + log_info("Removing leftover seatd socket"); unlink(socket_path); } } @@ -135,13 +135,13 @@ int main(int argc, char *argv[]) { int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { - log_errorf("could not create server socket: %s", strerror(errno)); + log_errorf("Could not create server socket: %s", strerror(errno)); server_finish(&server); return 1; } 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)); + log_errorf("Could not add socket to poller: %s", strerror(errno)); close(socket_fd); server_finish(&server); return 1; @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) { while (server.running) { if (poller_poll(&server.poller) == -1) { - log_errorf("poller failed: %s", strerror(errno)); + log_errorf("Poller failed: %s", strerror(errno)); return 1; } } diff --git a/seatd/server.c b/seatd/server.c index 3ca73b3..37235bc 100644 --- a/seatd/server.c +++ b/seatd/server.c @@ -111,11 +111,11 @@ static int server_handle_kill(int signal, void *data) { static int set_nonblock(int fd) { int flags; if ((flags = fcntl(fd, F_GETFD)) == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - log_errorf("could not set FD_CLOEXEC on socket: %s", strerror(errno)); + log_errorf("Could not set FD_CLOEXEC on socket: %s", strerror(errno)); return -1; } if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - log_errorf("could not set O_NONBLOCK on socket: %s", strerror(errno)); + log_errorf("Could not set O_NONBLOCK on socket: %s", strerror(errno)); return -1; } return 0; @@ -124,7 +124,7 @@ 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)); + log_errorf("Could not prepare new client socket: %s", strerror(errno)); return -1; } @@ -132,11 +132,11 @@ int server_add_client(struct server *server, int fd) { client->event_source = poller_add_fd(&server->poller, fd, EVENT_READABLE, client_handle_connection, client); if (client->event_source == NULL) { - log_errorf("could not add client socket to poller: %s", strerror(errno)); + log_errorf("Could not add client socket to poller: %s", strerror(errno)); client_destroy(client); return -1; } - log_infof("new client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, + log_infof("New client connected (pid: %d, uid: %d, gid: %d)", client->pid, client->uid, client->gid); return 0; } @@ -146,14 +146,14 @@ 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 recieved an error: %s", strerror(errno)); + log_errorf("Server socket recieved an error: %s", strerror(errno)); return -1; } if (mask & EVENT_READABLE) { int new_fd = accept(fd, NULL, NULL); if (fd == -1) { - log_errorf("could not accept client connection: %s", strerror(errno)); + log_errorf("Could not accept client connection: %s", strerror(errno)); return 0; } From d8ddf590faf49dec01453adc6ea238d94ba84478 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Mar 2021 00:15:03 +0100 Subject: [PATCH 027/159] log: Include debug logs in release builds --- include/log.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/log.h b/include/log.h index f5f423e..4cf5af3 100644 --- a/include/log.h +++ b/include/log.h @@ -27,15 +27,10 @@ #define log_error(str) _logf(LIBSEAT_LOG_LEVEL_ERROR, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#ifdef DEBUG #define log_debugf(fmt, ...) \ _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) #define log_debug(str) _logf(LIBSEAT_LOG_LEVEL_DEBUG, "[%s:%d] %s", __FILENAME__, __LINE__, str) -#else -#define log_debugf(fmt, ...) -#define log_debug(str) -#endif void log_init(void); void _logf(enum libseat_log_level level, const char *fmt, ...) ATTRIB_PRINTF(2, 3); From 951c1790fadf57e39c47f3d47451f86cca2d0889 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:22:55 +0100 Subject: [PATCH 028/159] meson: Clean up test declarations a bit --- meson.build | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/meson.build b/meson.build index 5b06e57..83c942b 100644 --- a/meson.build +++ b/meson.build @@ -186,31 +186,18 @@ if get_option('examples').enabled() ) endif -test( - 'linked_list', - executable( - 'linked_list_test', - ['common/linked_list.c', 'tests/linked_list.c'], - include_directories: [include_directories('.', 'include')], - ) -) -test( - 'poller', - executable( - 'poller_test', - ['common/linked_list.c', 'seatd/poller.c', 'tests/poller.c'], - include_directories: [include_directories('.', 'include')], - ) -) +tests = { + 'linked_list': ['common/linked_list.c'], + 'connection': ['common/connection.c'], + 'poller': ['common/linked_list.c', 'seatd/poller.c'], +} -test( - 'connection', - executable( - 'connection_test', - ['common/connection.c', 'tests/connection.c'], - include_directories: [include_directories('.', 'include')], - ) -) +foreach name, value : tests + test(name, executable( + '@0@_test'.format(name), + ['tests/@0@.c'.format(name), value], + include_directories: [include_directories('.', 'include')])) +endforeach if get_option('server').enabled() scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) From a9b20793199c038910344ff6ffc9d63c7a976fe9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:23:09 +0100 Subject: [PATCH 029/159] meson: Make summary prettier --- meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 83c942b..7f06821 100644 --- a/meson.build +++ b/meson.build @@ -232,8 +232,8 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled() ? 1 : 0, - 'builtin': get_option('builtin').enabled() ? 1 : 0, - 'systemd': logind_provider == 'systemd' ? 1 : 0, - 'elogind': logind_provider == 'elogind' ? 1 : 0, -}) + 'seatd': get_option('seatd').enabled(), + 'builtin': get_option('builtin').enabled(), + 'systemd': logind_provider == 'systemd', + 'elogind': logind_provider == 'elogind', +}, bool_yn: true) From c53c94985ee40a102a3229d5d584104da7ecaba6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:26:06 +0100 Subject: [PATCH 030/159] meson: Fix indentation --- meson.build | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 7f06821..dce4446 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,7 @@ add_project_arguments( ) if ['debugoptimized', 'release', 'minsize'].contains(get_option('buildtype')) - add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') + add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') endif # Hacks @@ -187,22 +187,22 @@ if get_option('examples').enabled() endif tests = { - 'linked_list': ['common/linked_list.c'], - 'connection': ['common/connection.c'], - 'poller': ['common/linked_list.c', 'seatd/poller.c'], + 'linked_list': ['common/linked_list.c'], + 'connection': ['common/connection.c'], + 'poller': ['common/linked_list.c', 'seatd/poller.c'], } foreach name, value : tests - test(name, executable( - '@0@_test'.format(name), - ['tests/@0@.c'.format(name), value], - include_directories: [include_directories('.', 'include')])) + test(name, executable( + '@0@_test'.format(name), + ['tests/@0@.c'.format(name), value], + include_directories: [include_directories('.', 'include')])) endforeach if get_option('server').enabled() - scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) + scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) else - scdoc = disabler() + scdoc = disabler() endif if scdoc.found() @@ -232,8 +232,8 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled(), - 'builtin': get_option('builtin').enabled(), - 'systemd': logind_provider == 'systemd', - 'elogind': logind_provider == 'elogind', + 'seatd': get_option('seatd').enabled(), + 'builtin': get_option('builtin').enabled(), + 'systemd': logind_provider == 'systemd', + 'elogind': logind_provider == 'elogind', }, bool_yn: true) From 9492054920c5e3d9789e72fc543680da7bfa3dea Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:31:51 +0100 Subject: [PATCH 031/159] ci: Add clang-extra-tools to alpine Needed for the clang-format target. --- .builds/alpine.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 048e3ef..01db99d 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -3,6 +3,7 @@ packages: - meson - linux-headers - clang + - clang-extra-tools - clang-analyzer - scdoc sources: From e303e113345f3774188f3c0d83af124984d58902 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Mar 2021 20:32:27 +0100 Subject: [PATCH 032/159] Bump version to 0.5.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index dce4446..ff56845 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.4.0', + version: '0.5.0', license: 'MIT', meson_version: '>=0.53.0', default_options: [ From e802d381a168789a593cdf583562758c3f26f305 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:52:31 +0100 Subject: [PATCH 033/159] meson: Fix logind backend auto mode --- meson.build | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/meson.build b/meson.build index ff56845..fe9ab21 100644 --- a/meson.build +++ b/meson.build @@ -111,25 +111,25 @@ if get_option('seatd').enabled() endif logind_provider = '' -if get_option('logind').enabled() - # Check for libelogind first, as elogind may provide a libsystemd wrapper - # which can cause issues. - logind = dependency('libelogind', required: false) - add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') - if logind.found() - add_project_arguments('-DHAVE_ELOGIND=1', language: 'c') - logind_provider = 'elogind' - else - logind = dependency('libsystemd') - add_project_arguments('-DHAVE_SYSTEMD=1', language: 'c') - logind_provider = 'systemd' - endif +if not get_option('logind').disabled() + foreach logind_provider : ['elogind', 'systemd'] + logind = dependency('lib@0@'.format(logind_provider), required: false) + if logind.found() + break + endif + endforeach - private_files += [ - 'libseat/backend/logind.c', - 'common/drm.c', - ] - private_deps += logind + if logind.found() + add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') + add_project_arguments('-DHAVE_@0@=1'.format(logind_provider.to_upper()), language: 'c') + private_files += [ + 'libseat/backend/logind.c', + 'common/drm.c', + ] + private_deps += logind + elif get_option('logind').enabled() + error('logind backend was enabled but no supported logind provider was found') + endif endif if get_option('builtin').enabled() From 75cb20e89113b163d792b8a623416cb32b684c80 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:53:39 +0100 Subject: [PATCH 034/159] meson: Minor cleanup --- meson.build | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index fe9ab21..f41b621 100644 --- a/meson.build +++ b/meson.build @@ -16,11 +16,9 @@ libseat_soversion = 1 defaultpath = get_option('defaultpath') if defaultpath == '' - system = target_machine.system() - if system == 'linux' - defaultpath = '/run/seatd.sock' - else - defaultpath = '/var/run/seatd.sock' + defaultpath = '/var/run/seatd.sock' + if target_machine.system() == 'linux' + defaultpath = '/run/seatd.sock' endif endif @@ -51,6 +49,10 @@ if ['debugoptimized', 'release', 'minsize'].contains(get_option('buildtype')) add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c') endif +if get_option('buildtype').startswith('debug') + add_project_arguments('-DDEBUG', language : 'c') +endif + # Hacks source_root = meson.current_source_dir().split('/') build_root = meson.build_root().split('/') @@ -74,11 +76,6 @@ foreach p : source_root i += 1 endforeach -if get_option('buildtype').startswith('debug') - add_project_arguments('-DDEBUG', language : 'c') -endif - - add_project_arguments( '-DREL_SRC_DIR="@0@"'.format(join_paths(relative_dir_parts) + '/'), language: 'c', @@ -208,12 +205,9 @@ endif if scdoc.found() sh = find_program('sh', native: true) scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) - - man_pages = ['seatd.1.scd'] - mandir = get_option('mandir') - foreach src : man_pages + foreach src : ['seatd.1.scd'] topic = src.split('.')[0] section = src.split('.')[1] output = '@0@.@1@'.format(topic, section) From 4e65e1bf471453d99577e6f5a2e72bfed73a3881 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:56:30 +0100 Subject: [PATCH 035/159] Correct minor misspellings --- README.md | 2 +- seatd/server.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a0c8e1..96c1caf 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Seat management takes care of mediating access to shared devices (graphics, inpu ### seatd -A seat management deamon, that does everything it needs to do. Nothing more, nothing less. Depends only on libc. +A seat management daemon, that does everything it needs to do. Nothing more, nothing less. Depends only on libc. ### libseat diff --git a/seatd/server.c b/seatd/server.c index 37235bc..0a08f50 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 recieved an error: %s", strerror(errno)); + log_errorf("Server socket received an error: %s", strerror(errno)); return -1; } From 1f457b1df8a7153963974553f5e50e68cb7c24b7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:31:37 +0100 Subject: [PATCH 036/159] meson: Disable examples by default --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- meson_options.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 01db99d..22dd536 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -10,7 +10,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 301e88b..b323894 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled build seatd + meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index e13566a..b9a9eaa 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -12,7 +12,7 @@ tasks: ninja -C build test - smoketest: | rm -rf build - meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + meson -Db_lundef=false -Db_sanitize=address -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled -Dlogind=disabled build seatd ninja -C build timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | diff --git a/meson_options.txt b/meson_options.txt index e32221a..73b9634 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,6 @@ option('logind', type: 'feature', value: 'disabled', description: 'logind suppor option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') option('server', type: 'feature', value: 'enabled', description: 'seatd server') -option('examples', type: 'feature', value: 'enabled', description: 'libseat example programs') +option('examples', type: 'feature', value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('defaultpath', type: 'string', value: '', description: 'Default location for seatd socket (empty for default)') From 745d66292034c53aef1febc72248bc3800826149 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:33:20 +0100 Subject: [PATCH 037/159] ci: Reduce test runs from 5 to 2 --- .builds/smoketest-builtin.sh | 2 +- .builds/smoketest-seatd.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh index 8341466..b022b77 100755 --- a/.builds/smoketest-builtin.sh +++ b/.builds/smoketest-builtin.sh @@ -16,7 +16,7 @@ fi # Run simpletest a few times # cnt=0 -while [ "$cnt" -lt 5 ] +while [ "$cnt" -lt 2 ] do echo "Simpletest run $cnt" if ! sudo LIBSEAT_BACKEND=builtin LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index f6f9732..7c5b7fe 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -38,7 +38,7 @@ fi # Run simpletest a few times # cnt=0 -while [ "$cnt" -lt 5 ] +while [ "$cnt" -lt 2 ] do echo "Simpletest run $cnt" if ! LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file From a9865adb5f354f762a7d38c981187440ccb80a60 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 13:33:35 +0100 Subject: [PATCH 038/159] ci: Remove unnecessary env vars --- .builds/smoketest-builtin.sh | 4 ++-- .builds/smoketest-seatd.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/smoketest-builtin.sh b/.builds/smoketest-builtin.sh index b022b77..332c3f9 100755 --- a/.builds/smoketest-builtin.sh +++ b/.builds/smoketest-builtin.sh @@ -18,8 +18,8 @@ fi cnt=0 while [ "$cnt" -lt 2 ] do - echo "Simpletest run $cnt" - if ! sudo LIBSEAT_BACKEND=builtin LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file + echo "Simpletest run $((cnt+1))" + if ! sudo LIBSEAT_BACKEND=builtin ./build/simpletest $file then echo "Simpletest failed" exit $res diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index 7c5b7fe..d8c2ac3 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -40,8 +40,8 @@ fi cnt=0 while [ "$cnt" -lt 2 ] do - echo "Simpletest run $cnt" - if ! LIBSEAT_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/simpletest $file + echo "Simpletest run $((cnt+1))" + if ! SEATD_SOCK=./seatd.sock ./build/simpletest $file then echo "Simpletest failed" sudo killall seatd From 34f55a3e2479daf0dae294dd22af25fcb6b25a01 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 14:27:45 +0100 Subject: [PATCH 039/159] contrib: Add Documentation to systemd unit --- contrib/systemd/seatd.service | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/systemd/seatd.service b/contrib/systemd/seatd.service index 2751217..a450058 100644 --- a/contrib/systemd/seatd.service +++ b/contrib/systemd/seatd.service @@ -1,5 +1,6 @@ [Unit] Description=Seat management daemon +Documentation=man:seatd(1) [Service] Type=simple From 0d855a28f20ab3d7b2058fbe58a172a97affbde5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 18 Mar 2021 15:45:26 +0100 Subject: [PATCH 040/159] readme: Remove alpha label --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96c1caf..8291279 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. Alpha +Currently supports Linux and FreeBSD. ## What is seat management? From 5ad91ae9dad205331ede6579b2b24b53e02a6287 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 21 Mar 2021 13:44:57 +0100 Subject: [PATCH 041/159] client: enable cr_pid on FreeBSD >= 12.3 https://cgit.freebsd.org/src/commit/?id=925f44f33862908f9a2e72520a17af148c7d0db5 https://cgit.freebsd.org/src/commit/?id=2b61bda2c75f30f6eadd18fb891fd885e4c8d19d --- seatd/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seatd/client.c b/seatd/client.c index d0f321d..1bfe94a 100644 --- a/seatd/client.c +++ b/seatd/client.c @@ -40,7 +40,7 @@ static int get_peer(int fd, pid_t *pid, uid_t *uid, gid_t *gid) { if (getsockopt(fd, 0, LOCAL_PEERCRED, &cred, &len) == -1) { return -1; } -#if __FreeBSD_version >= 1300030 +#if __FreeBSD_version >= 1300030 || (__FreeBSD_version >= 1202506 && __FreeBSD_version < 1300000) *pid = cred.cr_pid; #else *pid = -1; From 9a7824b7c3ff5c957632671e91454fc84fbcdda8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Mar 2021 10:05:12 +0100 Subject: [PATCH 042/159] Add no-op session This is useful for headless testing, for instance with VKMS: modprobe vkms export WLR_DRM_DEVICES=/dev/dri/card1 export WLR_BACKENDS=drm export LIBSEAT_BACKEND=noop sway We don't need any of the VT handling in this case. --- include/libseat.h | 2 + libseat/backend/noop.c | 135 +++++++++++++++++++++++++++++++++++++++++ libseat/libseat.c | 5 ++ meson.build | 2 +- 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 libseat/backend/noop.c diff --git a/include/libseat.h b/include/libseat.h index 5375cd6..82098ea 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -1,6 +1,8 @@ #ifndef _LIBSEAT_H #define _LIBSEAT_H +#include + /* * An opaque struct containing an opened seat, created by libseat_open_seat and * destroyed by libseat_close_seat. diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c new file mode 100644 index 0000000..71d0224 --- /dev/null +++ b/libseat/backend/noop.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backend.h" +#include "log.h" + +struct backend_noop { + struct libseat base; + struct libseat_seat_listener *seat_listener; + void *seat_listener_data; + + bool initial_setup; + int sockets[2]; +}; + +extern const struct seat_impl noop_impl; + +static struct backend_noop *backend_noop_from_libseat_backend(struct libseat *base) { + assert(base->impl == &noop_impl); + return (struct backend_noop *)base; +} + +static void destroy(struct backend_noop *backend) { + close(backend->sockets[0]); + close(backend->sockets[1]); + free(backend); +} + +static int close_seat(struct libseat *base) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + destroy(backend); + return 0; +} + +static int disable_seat(struct libseat *base) { + (void)base; + return 0; +} + +static const char *seat_name(struct libseat *base) { + (void)base; + return "noop"; +} + +static int open_device(struct libseat *base, const char *path, int *fd) { + (void)base; + + int tmpfd = open(path, O_RDWR | O_CLOEXEC); + if (tmpfd < 0) { + log_errorf("Failed to open device: %s", strerror(errno)); + return -1; + } + + *fd = tmpfd; + return tmpfd; +} + +static int close_device(struct libseat *base, int device_id) { + (void)base; + (void)device_id; + return 0; +} + +static int switch_session(struct libseat *base, int s) { + (void)base; + (void)s; + log_errorf("No-op backend cannot switch to session %d", s); + return -1; +} + +static int get_fd(struct libseat *base) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + return backend->sockets[0]; +} + +static int dispatch_background(struct libseat *base, int timeout) { + struct backend_noop *backend = backend_noop_from_libseat_backend(base); + + if (backend->initial_setup) { + backend->initial_setup = false; + backend->seat_listener->enable_seat(&backend->base, backend->seat_listener_data); + } + + struct pollfd fd = { + .fd = backend->sockets[0], + .events = POLLIN, + }; + if (poll(&fd, 1, timeout) < 0) { + if (errno == EAGAIN || errno == EINTR) { + return 0; + } else { + return -1; + } + } + + return 0; +} + +static struct libseat *noop_open_seat(struct libseat_seat_listener *listener, void *data) { + struct backend_noop *backend = calloc(1, sizeof(struct backend_noop)); + if (backend == NULL) { + return NULL; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, backend->sockets) != 0) { + log_errorf("socketpair() failed: %s", strerror(errno)); + free(backend); + return NULL; + } + + backend->seat_listener = listener; + backend->seat_listener_data = data; + backend->base.impl = &noop_impl; + + return &backend->base; +} + +const struct seat_impl noop_impl = { + .open_seat = noop_open_seat, + .disable_seat = disable_seat, + .close_seat = close_seat, + .seat_name = seat_name, + .open_device = open_device, + .close_device = close_device, + .switch_session = switch_session, + .get_fd = get_fd, + .dispatch = dispatch_background, +}; diff --git a/libseat/libseat.c b/libseat/libseat.c index b1e8bb2..a7e079c 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -13,6 +13,7 @@ extern const struct seat_impl seatd_impl; extern const struct seat_impl logind_impl; extern const struct seat_impl builtin_impl; +extern const struct seat_impl noop_impl; static const struct named_backend impls[] = { #ifdef SEATD_ENABLED @@ -24,6 +25,7 @@ static const struct named_backend impls[] = { #ifdef BUILTIN_ENABLED {"builtin", &builtin_impl}, #endif + {"noop", &noop_impl}, {NULL, NULL}, }; @@ -62,6 +64,9 @@ struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void * struct libseat *backend = NULL; for (const struct named_backend *iter = impls; iter->backend != NULL; iter++) { + if (iter->backend == &noop_impl) { + continue; + } backend = iter->backend->open_seat(listener, data); if (backend != NULL) { log_infof("Seat opened with backend '%s'", iter->name); diff --git a/meson.build b/meson.build index f41b621..c3800ae 100644 --- a/meson.build +++ b/meson.build @@ -145,7 +145,7 @@ symbols_file = 'libseat/libseat.syms' symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), symbols_file) lib = library( 'seat', # This results in the library being called 'libseat' - [ 'libseat/libseat.c' ], + [ 'libseat/libseat.c', 'libseat/backend/noop.c' ], soversion: libseat_soversion, link_with: private_lib, include_directories: [include_directories('.', 'include')], From fa2700126fe355939744a5e77159e7fc4a631575 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Mar 2021 10:07:00 +0100 Subject: [PATCH 043/159] meson: declare libseat dependency This can be used by parent projects when seatd is a subproject: libseat = dependency('libseat', fallback: ['seatd', 'libseat']) --- meson.build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meson.build b/meson.build index c3800ae..482f877 100644 --- a/meson.build +++ b/meson.build @@ -164,6 +164,12 @@ pkgconfig.generate(lib, description: 'Seat management library', ) +libseat = declare_dependency( + link_with: lib, + dependencies: private_deps, + include_directories: include_directories('include', is_system: true), +) + if get_option('server').enabled() executable( 'seatd', From f9ba8b57bc6505964d8055c87428234eb20f7992 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 26 Mar 2021 11:32:23 +0100 Subject: [PATCH 044/159] Avoid a clang-format quirk clang-format wants to put the terminating NULLs on the same line as the noop backend when it doens't have any immediate non-NULL neighbors. Add a newline to stop it. --- libseat/libseat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libseat/libseat.c b/libseat/libseat.c index a7e079c..42449a8 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -26,6 +26,7 @@ static const struct named_backend impls[] = { {"builtin", &builtin_impl}, #endif {"noop", &noop_impl}, + {NULL, NULL}, }; From 50da164ddcf925225f360ae2178a3d72961bbc8a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Apr 2021 23:07:04 +0200 Subject: [PATCH 045/159] ci: Use 'auto' for arch linux logind --- .builds/archlinux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index b323894..27391f0 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=enabled -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd + meson -Db_sanitize=address -Dlogind=auto -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | From 3ce4c5781462a06bb08458e73df39840f9e2f731 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Apr 2021 23:00:13 +0200 Subject: [PATCH 046/159] meson: make 'logind' var always available --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 482f877..beb121c 100644 --- a/meson.build +++ b/meson.build @@ -107,6 +107,7 @@ if get_option('seatd').enabled() add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif +logind = disabler() logind_provider = '' if not get_option('logind').disabled() foreach logind_provider : ['elogind', 'systemd'] From 385cc0039db13448856f4241b05d46533dc98b16 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:24:19 +0200 Subject: [PATCH 047/159] build: add explicit logind provider option, auto-detect by default Allow package maintainers to explicitly select a logind provider by passing -Dlogind=systemd or -Dlogind=elogind. In case both are available (e.g. for distributions which support both), this makes it possible to gte deterministic behavior. By default, auto-detect the logind provider. That way, users which have systemd or elogind installed get the backend built by default. --- meson.build | 22 +++++++++++++--------- meson_options.txt | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index beb121c..5454053 100644 --- a/meson.build +++ b/meson.build @@ -109,13 +109,19 @@ endif logind = disabler() logind_provider = '' -if not get_option('logind').disabled() - foreach logind_provider : ['elogind', 'systemd'] - logind = dependency('lib@0@'.format(logind_provider), required: false) - if logind.found() - break - endif - endforeach +if get_option('logind') != 'disabled' + if get_option('logind') == 'auto' + assert(get_option('auto_features').auto(), '-Dlogind 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 + else + logind_provider = get_option('logind') + logind = dependency('lib@0@'.format(logind_provider)) + endif if logind.found() add_project_arguments('-DLOGIND_ENABLED=1', language: 'c') @@ -125,8 +131,6 @@ if not get_option('logind').disabled() 'common/drm.c', ] private_deps += logind - elif get_option('logind').enabled() - error('logind backend was enabled but no supported logind provider was found') endif endif diff --git a/meson_options.txt b/meson_options.txt index 73b9634..9c36fa3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,4 @@ -option('logind', type: 'feature', value: 'disabled', description: 'logind support') +option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') option('server', type: 'feature', value: 'enabled', description: 'seatd server') From 392da918e626641edb337d0afd9c0d72695babed Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:30:18 +0200 Subject: [PATCH 048/159] build: fix logind feature summary when auto-detected If -Dlogind=auto but systemd/elogind isn't available, logind_provider would get set to the last item of the foreach loop. This would incorrectly report "systemd: YES". --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 5454053..8f7efb2 100644 --- a/meson.build +++ b/meson.build @@ -239,6 +239,6 @@ endif summary({ 'seatd': get_option('seatd').enabled(), 'builtin': get_option('builtin').enabled(), - 'systemd': logind_provider == 'systemd', - 'elogind': logind_provider == 'elogind', + 'systemd': logind.found() and logind_provider == 'systemd', + 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) From ee409138109c5f53310f0d81d2b591157b39d622 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 13:36:41 +0200 Subject: [PATCH 049/159] build: don't explicitly search for sh This removes the "Program sh found" line in the build logs, and should not change anything else. --- meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 8f7efb2..60c96f0 100644 --- a/meson.build +++ b/meson.build @@ -214,7 +214,6 @@ else endif if scdoc.found() - sh = find_program('sh', native: true) scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) mandir = get_option('mandir') @@ -228,7 +227,7 @@ if scdoc.found() input: 'man/' + src, output: output, command: [ - sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) + 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) From 753c5276cf800ae1fb1c7747bfcdaeff5e45d6de Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 7 Apr 2021 14:30:04 +0200 Subject: [PATCH 050/159] build: don't allow "auto" for seatd, builtin, server and examples These features don't have any dependencies, so "auto" doesn't make sense. --- meson.build | 19 ++++++++++++------- meson_options.txt | 8 ++++---- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 60c96f0..722735a 100644 --- a/meson.build +++ b/meson.build @@ -102,7 +102,11 @@ server_files = [ 'seatd/server.c', ] -if get_option('seatd').enabled() +with_seatd = get_option('seatd') == 'enabled' +with_builtin = get_option('builtin') == 'enabled' +with_server = get_option('server') == 'enabled' + +if with_seatd private_files += 'libseat/backend/seatd.c' add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif @@ -134,7 +138,7 @@ if get_option('logind') != 'disabled' endif endif -if get_option('builtin').enabled() +if with_builtin add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') private_files += server_files endif @@ -175,7 +179,7 @@ libseat = declare_dependency( include_directories: include_directories('include', is_system: true), ) -if get_option('server').enabled() +if with_server executable( 'seatd', [ server_files, 'seatd/seatd.c' ], @@ -184,7 +188,7 @@ if get_option('server').enabled() ) endif -if get_option('examples').enabled() +if get_option('examples') == 'enabled' executable( 'simpletest', ['examples/simpletest/main.c'], @@ -207,7 +211,7 @@ foreach name, value : tests include_directories: [include_directories('.', 'include')])) endforeach -if get_option('server').enabled() +if with_server scdoc = dependency('scdoc', required: get_option('man-pages'), version: '>= 1.9.7', native: true) else scdoc = disabler() @@ -236,8 +240,9 @@ if scdoc.found() endif summary({ - 'seatd': get_option('seatd').enabled(), - 'builtin': get_option('builtin').enabled(), + 'seatd': with_seatd, + 'builtin': with_builtin, + 'server': with_server, 'systemd': logind.found() and logind_provider == 'systemd', 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 9c36fa3..144ce7a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') -option('seatd', type: 'feature', value: 'enabled', description: 'seatd support') -option('builtin', type: 'feature', value: 'disabled', description: 'builtin seatd server') -option('server', type: 'feature', value: 'enabled', description: 'seatd server') -option('examples', type: 'feature', value: 'disabled', description: 'libseat example programs') +option('seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support') +option('builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'builtin seatd server') +option('server', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd server') +option('examples', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('defaultpath', type: 'string', value: '', description: 'Default location for seatd socket (empty for default)') From 5884a6003ab77109050df11af0c06956257df910 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Apr 2021 09:05:05 +0200 Subject: [PATCH 051/159] build: disable logind on -Dauto_features=disabled -Dlogind=auto Setting auto_features=disabled is supposed to disable all optional dependencies. Since we aren't using a feature option here, we need to manually add logic to disable logind in this case. --- meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 722735a..a7e4734 100644 --- a/meson.build +++ b/meson.build @@ -114,7 +114,9 @@ endif logind = disabler() logind_provider = '' if get_option('logind') != 'disabled' - if get_option('logind') == 'auto' + if get_option('logind') == 'auto' and get_option('auto_features').disabled() + # Disable logind + elif get_option('logind') == 'auto' assert(get_option('auto_features').auto(), '-Dlogind 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) From 81ff0a09a93303233057f217aaa3f679db3bbe5c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 10 Apr 2021 09:15:47 +0200 Subject: [PATCH 052/159] build: set pkgconfig/dependency variables for features This allows libseat users to e.g. advise people to chmod a+s the executable if libseat is built with the builtin backend. While bumping the Meson version, adjust the scdoc logic to avoid the following warnings: WARNING: Project targeting '>=0.56.0' but tried to use feature deprecated since '0.56.0': Dependency.get_pkgconfig_variable. use Dependency.get_variable(pkgconfig : ...) instead WARNING: Project targeting '>=0.56.0' but tried to use feature deprecated since '0.55.0': ExternalProgram.path. use ExternalProgram.full_path() instead --- meson.build | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index a7e4734..7a70cb6 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.5.0', license: 'MIT', - meson_version: '>=0.53.0', + meson_version: '>=0.56.0', default_options: [ 'c_std=c11', 'warning_level=3', @@ -167,18 +167,26 @@ lib = library( install_headers('include/libseat.h') +libseat_vars = { + 'have_seatd': with_seatd.to_string(), + 'have_logind': logind.found().to_string(), + 'have_builtin': with_builtin.to_string(), +} + pkgconfig = import('pkgconfig') pkgconfig.generate(lib, version: meson.project_version(), filebase: 'libseat', name: 'libseat', description: 'Seat management library', + variables: libseat_vars, ) libseat = declare_dependency( link_with: lib, dependencies: private_deps, include_directories: include_directories('include', is_system: true), + variables: libseat_vars, ) if with_server @@ -220,7 +228,7 @@ else endif if scdoc.found() - scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) + scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') foreach src : ['seatd.1.scd'] @@ -233,7 +241,7 @@ if scdoc.found() input: 'man/' + src, output: output, command: [ - 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) + 'sh', '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.full_path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) From 5535c2c3b19b42ebfe4c451600059e9418e401a6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 17 Apr 2021 17:08:51 +0200 Subject: [PATCH 053/159] contrib/systemd: Use a different group "video" was used for convenience in the example, but a dedicated group is preferable so that a user does not gain the ability to bypass the seat manager and open devices directly. --- contrib/systemd/seatd.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/systemd/seatd.service b/contrib/systemd/seatd.service index a450058..bbbaf23 100644 --- a/contrib/systemd/seatd.service +++ b/contrib/systemd/seatd.service @@ -4,7 +4,8 @@ Documentation=man:seatd(1) [Service] Type=simple -ExecStart=seatd -g video +# Specify the group you'd like to grant access to seatd +ExecStart=seatd -g seat Restart=always RestartSec=1 From 36f54adc2c1b16943e5470af3ad85d2b4cdf480c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 23 Apr 2021 14:13:58 +0000 Subject: [PATCH 054/159] libseat/seatd: downgrade ENOENT log to info The socket is expected not to be found if seatd is not running. In general other backends will be attempted after seatd. There is already an error message in case no backend can be started. --- libseat/backend/seatd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 2dea3ca..07026ba 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -75,7 +75,11 @@ static int seatd_connect(void) { strncpy(addr.unix.sun_path, path, sizeof addr.unix.sun_path - 1); socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (connect(fd, &addr.generic, size) == -1) { - log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); + if (errno == ENOENT) { + log_infof("Could not connect to socket %s: %s", path, strerror(errno)); + } else { + log_errorf("Could not connect to socket %s: %s", path, strerror(errno)); + } close(fd); return -1; }; From 355cc9c944a29d29736de84e782a2e91168f1a59 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 25 Apr 2021 20:16:19 +0200 Subject: [PATCH 055/159] meson: Support building builtin without seatd The builtin backend relies on the seatd backend implementation. When builtin was enabled without seatd, compilation would fail due to the implementation not being included. Include the implementation if either seatd or builtin is enabled. --- meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 7a70cb6..6299f4e 100644 --- a/meson.build +++ b/meson.build @@ -106,8 +106,11 @@ with_seatd = get_option('seatd') == 'enabled' with_builtin = get_option('builtin') == 'enabled' with_server = get_option('server') == 'enabled' -if with_seatd +if with_seatd or with_builtin private_files += 'libseat/backend/seatd.c' +endif + +if with_seatd add_project_arguments('-DSEATD_ENABLED=1', language: 'c') endif From fc97206df9b8fbba09de8b320fab6f75235a5c7f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 19 May 2021 17:48:12 +0200 Subject: [PATCH 056/159] readme: Update discuss section --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8291279..9aa9e99 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,6 @@ Why spend time isolating logind and keeping up with upstream when we could inste Instead of giving user shell developers more work, libseat aims to make supporting seatd less work than what they're currently implementing. This is done by taking care of all the seat management needs with multiple backends, providing not only seatd support, but replacing the existing logind and direct seat management implementations. -## I want more +## How to discuss -Go to #kennylevinsen @ chat.freenode.net to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). +Go to #kennylevinsen @ irc.libera.chat to discuss, or use [~kennylevinsen/seatd-devel@lists.sr.ht](https://lists.sr.ht/~kennylevinsen/seatd-devel). From bff09d88594a35d343b16b21b75495c4284f1292 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Sun, 20 Jun 2021 22:28:33 +0200 Subject: [PATCH 057/159] link with rt Since seatd uses `clock_gettime`, this is needed when cross-compiling. This came up in https://github.com/JuliaPackaging/Yggdrasil/pull/3193. --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 6299f4e..89fa8df 100644 --- a/meson.build +++ b/meson.build @@ -143,6 +143,10 @@ if get_option('logind') != 'disabled' endif endif +# needed for cross-compilation +realtime = meson.get_compiler('c').find_library('rt') +private_deps += realtime + if with_builtin add_project_arguments('-DBUILTIN_ENABLED=1', language: 'c') private_files += server_files @@ -198,6 +202,7 @@ if with_server [ server_files, 'seatd/seatd.c' ], include_directories: [include_directories('.', 'include')], install: true, + dependencies: [realtime], ) endif From 2204db5531ed16bf32f969645e7177f6118f8a8e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 23 Jun 2021 08:08:33 +0000 Subject: [PATCH 058/159] build: add prefix to libseat options The option names are a little bit confusing, because it's not clear which ones toggle libseat features, and which ones toggle seatd features. Add a "libseat-" prefix to libseat-specific features, to make it more obvious that they only are about the library. --- meson.build | 22 +++++++++++----------- meson_options.txt | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/meson.build b/meson.build index 89fa8df..9d48706 100644 --- a/meson.build +++ b/meson.build @@ -102,8 +102,8 @@ server_files = [ 'seatd/server.c', ] -with_seatd = get_option('seatd') == 'enabled' -with_builtin = get_option('builtin') == 'enabled' +with_seatd = get_option('libseat-seatd') == 'enabled' +with_builtin = get_option('libseat-builtin') == 'enabled' with_server = get_option('server') == 'enabled' if with_seatd or with_builtin @@ -116,11 +116,11 @@ endif logind = disabler() logind_provider = '' -if get_option('logind') != 'disabled' - if get_option('logind') == 'auto' and get_option('auto_features').disabled() +if get_option('libseat-logind') != 'disabled' + if get_option('libseat-logind') == 'auto' and get_option('auto_features').disabled() # Disable logind - elif get_option('logind') == 'auto' - assert(get_option('auto_features').auto(), '-Dlogind must be set to systemd or elogind since auto_features != auto') + 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() @@ -128,7 +128,7 @@ if get_option('logind') != 'disabled' endif endforeach else - logind_provider = get_option('logind') + logind_provider = get_option('libseat-logind') logind = dependency('lib@0@'.format(logind_provider)) endif @@ -258,9 +258,9 @@ if scdoc.found() endif summary({ - 'seatd': with_seatd, - 'builtin': with_builtin, + 'libseat-seatd': with_seatd, + 'libseat-builtin': with_builtin, + 'libseat-systemd': logind.found() and logind_provider == 'systemd', + 'libseat-elogind': logind.found() and logind_provider == 'elogind', 'server': with_server, - 'systemd': logind.found() and logind_provider == 'systemd', - 'elogind': logind.found() and logind_provider == 'elogind', }, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 144ce7a..0731ac4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,6 +1,6 @@ -option('logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support') -option('seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support') -option('builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'builtin seatd server') +option('libseat-logind', type: 'combo', choices: ['auto', 'disabled', 'elogind', 'systemd'], value: 'auto', description: 'logind support for libseat') +option('libseat-seatd', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd support for libseat') +option('libseat-builtin', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'built-in seatd server for libseat') option('server', type: 'combo', choices: ['enabled', 'disabled'], value: 'enabled', description: 'seatd server') option('examples', type: 'combo', choices: ['enabled', 'disabled'], value: 'disabled', description: 'libseat example programs') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') From 7a6d12ff7a4e3e19d6c7c9e0f2d270491168e785 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 8 Jul 2021 23:41:09 +0200 Subject: [PATCH 059/159] libseat/seatd: Return executed events Dispatch needs to report if something has happened, which includes events executed from the queue as these could have lead to additional dispatch and queuing. --- libseat/backend/seatd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 07026ba..9bc5e6e 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -206,10 +206,11 @@ static int queue_event(struct backend_seatd *backend, int opcode) { return 0; } -static void execute_events(struct backend_seatd *backend) { +static int execute_events(struct backend_seatd *backend) { struct linked_list list; linked_list_init(&list); linked_list_take(&list, &backend->pending_events); + int executed = 0; while (!linked_list_empty(&list)) { struct pending_event *ev = (struct pending_event *)list.next; int opcode = ev->opcode; @@ -231,7 +232,9 @@ static void execute_events(struct backend_seatd *backend) { log_errorf("Invalid opcode: %d", opcode); abort(); } + executed++; } + return executed; } static int dispatch_pending(struct backend_seatd *backend, int *opcode) { @@ -341,7 +344,7 @@ static int dispatch_background(struct libseat *base, int timeout) { return -1; } - execute_events(backend); + dispatched += execute_events(backend); return dispatched; } From 5923e0edc9bb157cf6398b63d51cc3c0aaf06001 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 9 Jul 2021 00:09:14 +0200 Subject: [PATCH 060/159] libseat/seatd: Add dispatch_pending_and_execute This handler returns the number of dispatched or executed events, or -1 if dispatch_pending failed. This helper is used to clean up dispatch_background, which now ensures that all events are executed before we read or poll the connection, and have improved error handling in the corner case where the second dispatch_pending failed. --- libseat/backend/seatd.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 9bc5e6e..3600b50 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -262,6 +262,15 @@ static int dispatch_pending(struct backend_seatd *backend, int *opcode) { return packets; } +static int dispatch_pending_and_execute(struct backend_seatd *backend) { + int dispatched = dispatch_pending(backend, NULL); + if (dispatched == -1) { + return -1; + } + dispatched += execute_events(backend); + return dispatched; +} + static int poll_connection(struct backend_seatd *backend, int timeout) { struct pollfd fd = { .fd = backend->connection.fd, @@ -324,28 +333,34 @@ static int dispatch_background(struct libseat *base, int timeout) { return -1; } - int dispatched = dispatch_pending(backend, NULL); - if (dispatched > 0) { - // We don't want to block if we dispatched something, as the - // caller might be waiting for the result. However, we'd also - // like to read anything pending. - timeout = 0; + int predispatch = dispatch_pending_and_execute(backend); + if (predispatch == -1) { + return -1; } + + // We don't want to block if we dispatched something, as the + // caller might be waiting for the result. However, we'd also + // like to read anything pending. int read = 0; - if (timeout == 0) { + if (predispatch == 0 || timeout == 0) { read = connection_read(&backend->connection); } else { read = poll_connection(backend, timeout); } - if (read > 0) { - dispatched += dispatch_pending(backend, NULL); + + if (read == 0) { + return predispatch; } else if (read == -1 && errno != EAGAIN) { log_errorf("Could not read from connection: %s", strerror(errno)); return -1; } - dispatched += execute_events(backend); - return dispatched; + int postdispatch = dispatch_pending_and_execute(backend); + if (postdispatch == -1) { + return -1; + } + + return predispatch + postdispatch; } static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { From 6444da60930fbe92b8c7e868372c90887853e60b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 9 Jul 2021 00:16:10 +0200 Subject: [PATCH 061/159] libseat: Rename dispatch_background in backends This name never made much sense. dispatch_and_execute is more meaningful, especially when compared to the non-executing dispatch function. --- libseat/backend/logind.c | 4 ++-- libseat/backend/seatd.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index c6f2aaf..aa659a6 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -213,7 +213,7 @@ static int poll_connection(struct backend_logind *backend, int timeout) { return 0; } -static int dispatch_background(struct libseat *base, int timeout) { +static int dispatch_and_execute(struct libseat *base, int timeout) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); if (backend->initial_setup) { backend->initial_setup = false; @@ -688,5 +688,5 @@ const struct seat_impl logind_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 3600b50..96b4681 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -326,7 +326,7 @@ static int get_fd(struct libseat *base) { return backend->connection.fd; } -static int dispatch_background(struct libseat *base, int timeout) { +static int dispatch_and_execute(struct libseat *base, int timeout) { struct backend_seatd *backend = backend_seatd_from_libseat_backend(base); if (backend->error) { errno = ENOTCONN; @@ -575,7 +575,7 @@ const struct seat_impl seatd_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; #ifdef BUILTIN_ENABLED @@ -660,6 +660,6 @@ const struct seat_impl builtin_impl = { .close_device = close_device, .switch_session = switch_session, .get_fd = get_fd, - .dispatch = dispatch_background, + .dispatch = dispatch_and_execute, }; #endif From d03e9d1c35b491851c7097dd7b42faa02c9ff96f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 01:09:57 +0200 Subject: [PATCH 062/159] seatd: We shouldn't poll if predispatch > 0 This condition was accidentally botched as part of 5923e0edc9bb157cf6398b63d51cc3c0aaf06001 --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 96b4681..97971aa 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -342,7 +342,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { // caller might be waiting for the result. However, we'd also // like to read anything pending. int read = 0; - if (predispatch == 0 || timeout == 0) { + if (predispatch > 0 || timeout == 0) { read = connection_read(&backend->connection); } else { read = poll_connection(backend, timeout); From 312d6906aef9c9ae7aba62f0ad60c83bb5f95b00 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 20 Apr 2021 22:54:30 +0200 Subject: [PATCH 063/159] seatd: s6-style readiness notification support This adds the ability to specify the number of an fd that is inherited by the process as open. Once seatd is read to serve requests, it will write a single newline and close the fd. --- man/seatd.1.scd | 5 +++++ seatd/seatd.c | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/man/seatd.1.scd b/man/seatd.1.scd index ab79ee1..5945782 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -13,6 +13,11 @@ seatd - A seat management daemon *-h* Show help message and quit. +*-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. + *-u * User to own the seatd socket. diff --git a/seatd/seatd.c b/seatd/seatd.c index 278f857..420847d 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -70,6 +70,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" " -u User to own the seatd socket\n" " -g Group to own the seatd socket\n" " -s Where to create the seatd socket\n" @@ -78,9 +79,17 @@ int main(int argc, char *argv[]) { int c; int uid = 0, gid = 0; + int readiness = -1; const char *socket_path = getenv("SEATD_SOCK"); - while ((c = getopt(argc, argv, "vhs:g:u:")) != -1) { + while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { switch (c) { + case 'n': + readiness = atoi(optarg); + if (readiness < 0) { + fprintf(stderr, "Invalid readiness fd: %s\n", optarg); + return 1; + } + break; case 's': socket_path = optarg; break; @@ -149,6 +158,13 @@ int main(int argc, char *argv[]) { log_info("seatd started"); + if (readiness != -1) { + if (write(readiness, "\n", 1) == -1) { + log_errorf("Could not write readiness signal: %s\n", strerror(errno)); + } + close(readiness); + } + while (server.running) { if (poller_poll(&server.poller) == -1) { log_errorf("Poller failed: %s", strerror(errno)); From c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:45:25 +0200 Subject: [PATCH 064/159] seatd: Only set UID/GID when specified The UID/GID defaulted to 0, which results in trying to chown to root when a UID or GID isn't requested. Instead, deafult to -1 so that the unspecified values are left intact. --- seatd/seatd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 420847d..826b994 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -41,11 +41,11 @@ static int open_socket(const char *path, int uid, int gid) { close(fd); return -1; } - if (uid != 0 || gid != 0) { - if (chown(path, uid, gid) == -1) { + if (uid != -1 || gid != -1) { + if (fchown(fd, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); - } else if (chmod(path, 0770) == -1) { + } else if (fchmod(fd, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); } } @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { "\n"; int c; - int uid = 0, gid = 0; + int uid = -1, gid = -1; int readiness = -1; const char *socket_path = getenv("SEATD_SOCK"); while ((c = getopt(argc, argv, "vhn:s:g:u:")) != -1) { From 1e98727ae9dfdb23316249a4f32b3169d956e417 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:06:44 +0200 Subject: [PATCH 065/159] seatd-launch: Add seatd launch wrapper This launch wrapper is used to conveniently start a new seatd instance, wait for it to be ready, and launch a target application. --- meson.build | 7 ++ seatd-launch/seatd-launch.c | 123 ++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 seatd-launch/seatd-launch.c diff --git a/meson.build b/meson.build index 9d48706..1131b4b 100644 --- a/meson.build +++ b/meson.build @@ -204,6 +204,13 @@ if with_server install: true, dependencies: [realtime], ) + executable( + 'seatd-launch', + [ 'seatd-launch/seatd-launch.c' ], + include_directories: [include_directories('.', 'include')], + install: true, + dependencies: [realtime], + ) endif if get_option('examples') == 'enabled' diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c new file mode 100644 index 0000000..ffa6cc6 --- /dev/null +++ b/seatd-launch/seatd-launch.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + (void)argc; + char sockbuf[256]; + + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + unlink(sockbuf); + + int fds[2]; + if (pipe(fds) == -1) { + perror("Could not create pipe"); + goto error; + } + + 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]); + + char pipebuf[8]; + sprintf(pipebuf, "%d", fds[1]); + struct passwd *user = getpwuid(getuid()); + + // TODO: Make seatd accept the numeric UID + execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); + perror("Could not start seatd"); + goto error; + } + close(fds[1]); + + // Drop privileges + if (setgid(getgid()) == -1) { + perror("Could not set gid to drop privileges"); + goto error_seatd; + } + if (setuid(getuid()) == -1) { + perror("Could not set uid to drop privileges"); + goto error_seatd; + } + + char buf[1] = {0}; + while (true) { + pid_t p = waitpid(seatd_child, NULL, WNOHANG); + if (p == seatd_child) { + fprintf(stderr, "seatd exited prematurely\n"); + goto error_seatd; + } else if (p == -1 && (errno != EINTR && errno != ECHILD)) { + perror("Could not wait for seatd process"); + goto error_seatd; + } + + struct pollfd fd = { + .fd = fds[0], + .events = POLLIN, + }; + + // We poll with timeout to avoid a racing on a blocking read + if (poll(&fd, 1, 1000) == -1) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + perror("Could not poll notification fd"); + goto error_seatd; + } + } + + if (fd.revents & POLLIN) { + ssize_t n = read(fds[0], buf, 1); + if (n == -1 && errno != EINTR) { + perror("Could not read from pipe"); + goto error_seatd; + } else if (n > 0) { + break; + } + } + } + close(fds[0]); + + pid_t child = fork(); + if (child == -1) { + perror("Could not fork target process"); + goto error_seatd; + } else if (child == 0) { + setenv("SEATD_SOCK", sockbuf, 1); + execv(argv[1], &argv[1]); + perror("Could not start target"); + goto error_seatd; + } + + while (true) { + pid_t p = waitpid(child, NULL, 0); + if (p == child) { + break; + } else if (p == -1 && errno != EINTR) { + perror("Could not wait for target process"); + goto error_seatd; + } + } + + unlink(sockbuf); + kill(seatd_child, SIGTERM); + return 0; + +error_seatd: + unlink(sockbuf); + kill(seatd_child, SIGTERM); +error: + return 1; +} From 978dec42b052ae56f55fe4ea8a2554e5611ec0fa Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 00:46:49 +0200 Subject: [PATCH 066/159] ci: Use seatd-launch --- .builds/smoketest-seatd.sh | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/.builds/smoketest-seatd.sh b/.builds/smoketest-seatd.sh index d8c2ac3..96f554b 100755 --- a/.builds/smoketest-seatd.sh +++ b/.builds/smoketest-seatd.sh @@ -1,27 +1,5 @@ #!/bin/sh -# -# Start seatd -# -[ -f seatd.sock ] && sudo rm seatd.sock -sudo SEATD_LOGLEVEL=debug SEATD_SOCK=./seatd.sock ./build/seatd & - -# seatd is started in the background, so wait for it to come alive -cnt=0 -while ! [ -e ./seatd.sock ] && [ "$cnt" -lt 10 ] -do - sleep 0.1 - cnt=$((cnt+1)) -done - -if ! [ -e ./seatd.sock ] -then - echo "seatd socket not found" - exit 1 -fi - -sudo chmod 777 ./seatd.sock - # Devices that exist on sr.ht if [ -e "/dev/input/event0" ] then @@ -34,6 +12,8 @@ else exit 1 fi +export SEATD_LOGLEVEL=debug +export PATH=$(pwd)/build:$PATH # # Run simpletest a few times # @@ -41,18 +21,12 @@ cnt=0 while [ "$cnt" -lt 2 ] do echo "Simpletest run $((cnt+1))" - if ! SEATD_SOCK=./seatd.sock ./build/simpletest $file + if ! sudo -E seatd-launch ./build/simpletest $file then echo "Simpletest failed" - sudo killall seatd exit 1 fi cnt=$((cnt+1)) done -# -# Wait for it to shut down -# -sudo killall seatd 2>/dev/null - echo "smoketest-seatd completed" From 7d06b34ee248563a6c13d3ccfaa5370c0aa15d2d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 01:14:44 +0200 Subject: [PATCH 067/159] ci: Fix meson flags --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 22dd536..adea8ed 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -10,7 +10,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled -Dexamples=enabled build seatd + meson -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dlibseat-logind=disabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 27391f0..3e1574b 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -9,7 +9,7 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Db_sanitize=address -Dlogind=auto -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled build seatd + meson -Db_sanitize=address -Dlibseat-logind=auto -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled build seatd - build: | ninja -C build - unittest: | diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index b9a9eaa..1b4ceba 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -5,14 +5,14 @@ sources: - https://git.sr.ht/~kennylevinsen/seatd tasks: - prepare: | - meson -Dseatd=enabled -Dbuiltin=enabled -Dlogind=disabled build seatd + 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 -Dseatd=enabled -Dbuiltin=enabled -Dexamples=enabled -Dlogind=disabled build seatd + meson -Db_lundef=false -Db_sanitize=address -Dlibseat-seatd=enabled -Dlibseat-builtin=enabled -Dexamples=enabled -Dlibseat-logind=disabled build seatd ninja -C build timeout -s KILL 30s ./seatd/.builds/smoketest-seatd.sh - smoketest-builtin: | From f2a614dcd3b3e473df29a91ca9a7de77ef9b2609 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:01 +0000 Subject: [PATCH 068/159] seatd-launch: propagate child exit status When the child process exits with a non-zero code or is killed, return with a non-zero code as well. --- seatd-launch/seatd-launch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index ffa6cc6..1b53699 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -101,8 +101,9 @@ int main(int argc, char *argv[]) { goto error_seatd; } + int status = 0; while (true) { - pid_t p = waitpid(child, NULL, 0); + pid_t p = waitpid(child, &status, 0); if (p == child) { break; } else if (p == -1 && errno != EINTR) { @@ -113,7 +114,12 @@ int main(int argc, char *argv[]) { unlink(sockbuf); kill(seatd_child, SIGTERM); - return 0; + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } else { + return 1; + } error_seatd: unlink(sockbuf); From 3a843745c2dee17ec99d3c6b233251a5dc6ff5ad Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:02 +0000 Subject: [PATCH 069/159] seatd-launch: don't use gotos in child processes While forked (child pid is zero), don't use gotos. These will execute atexit functions and potentially mess up the stdlib. Instead, use _exit. --- 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 1b53699..cf9f93d 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { // TODO: Make seatd accept the numeric UID execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); perror("Could not start seatd"); - goto error; + _exit(1); } close(fds[1]); @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) { setenv("SEATD_SOCK", sockbuf, 1); execv(argv[1], &argv[1]); perror("Could not start target"); - goto error_seatd; + _exit(1); } int status = 0; From 369af8f9e4797be55c4b95facd50dd7cc20565d1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Aug 2021 08:23:03 +0000 Subject: [PATCH 070/159] seatd-launch: check for getpwuid errors --- seatd-launch/seatd-launch.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index cf9f93d..acec145 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -33,7 +33,12 @@ int main(int argc, char *argv[]) { char pipebuf[8]; sprintf(pipebuf, "%d", fds[1]); + struct passwd *user = getpwuid(getuid()); + if (!user) { + perror("getpwuid failed"); + _exit(1); + } // TODO: Make seatd accept the numeric UID execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); From 48727a0b6bc2f7127f2115470be27aa09be7a4a7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Aug 2021 23:00:05 +0200 Subject: [PATCH 071/159] seatd-launch: Command line argument support --- seatd-launch/seatd-launch.c | 46 +++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index acec145..9fd3f23 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -13,10 +13,42 @@ int main(int argc, char *argv[]) { (void)argc; - char sockbuf[256]; - sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); - unlink(sockbuf); + 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" + "\n"; + + int c; + char *sockpath = NULL; + while ((c = getopt(argc, argv, "vhs:")) != -1) { + switch (c) { + case 's': + sockpath = optarg; + break; + case 'v': + printf("seatd-launch version %s\n", SEATD_VERSION); + return 0; + case 'h': + printf("%s", usage); + return 0; + case '?': + fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); + return 1; + default: + abort(); + } + } + + char sockbuf[256]; + if (sockpath == NULL) { + sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); + sockpath = sockbuf; + } + + unlink(sockpath); int fds[2]; if (pipe(fds) == -1) { @@ -41,7 +73,7 @@ int main(int argc, char *argv[]) { } // TODO: Make seatd accept the numeric UID - execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockbuf, NULL); + execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockpath, NULL); perror("Could not start seatd"); _exit(1); } @@ -100,7 +132,7 @@ int main(int argc, char *argv[]) { perror("Could not fork target process"); goto error_seatd; } else if (child == 0) { - setenv("SEATD_SOCK", sockbuf, 1); + setenv("SEATD_SOCK", sockpath, 1); execv(argv[1], &argv[1]); perror("Could not start target"); _exit(1); @@ -117,7 +149,7 @@ int main(int argc, char *argv[]) { } } - unlink(sockbuf); + unlink(sockpath); kill(seatd_child, SIGTERM); if (WIFEXITED(status)) { @@ -127,7 +159,7 @@ int main(int argc, char *argv[]) { } error_seatd: - unlink(sockbuf); + unlink(sockpath); kill(seatd_child, SIGTERM); error: return 1; From 2cfc56d5ed87440c58ed7fa538c3a3dbf73fbfc2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 8 Aug 2021 18:16:58 +0200 Subject: [PATCH 072/159] seatd: Improve socket permission error handling chmod/chown errors were logged, but did not result in failure opening the seatd socket. This meant that errors would not get caught by CI. --- seatd/seatd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 826b994..4587e50 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -33,23 +33,27 @@ static int open_socket(const char *path, int uid, int gid) { socklen_t size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.unix.sun_path); if (bind(fd, &addr.generic, size) == -1) { log_errorf("Could not bind socket: %s", strerror(errno)); - close(fd); - return -1; + goto error; } if (listen(fd, LISTEN_BACKLOG) == -1) { log_errorf("Could not listen on socket: %s", strerror(errno)); - close(fd); - return -1; + goto error; } if (uid != -1 || gid != -1) { if (fchown(fd, uid, gid) == -1) { log_errorf("Could not chown socket to uid %d, gid %d: %s", uid, gid, strerror(errno)); - } else if (fchmod(fd, 0770) == -1) { + goto error; + } + if (fchmod(fd, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); + goto error; } } return fd; +error: + close(fd); + return -1; } int main(int argc, char *argv[]) { From 309650aa4d4be1310b20e7293a3bc0c47aeecf0e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 8 Aug 2021 18:22:17 +0200 Subject: [PATCH 073/159] seatd: Use path in chmod/chown operations c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 snuck in a change which converts chown/chmod to fchown/fchmod using the socket fd. This appears to succeed under Linux, but fails with EINVAL on FreeBSD. As the error handling in this area was flawed, CI failed to catch the regression. Partially revert c8b3a22d4ef0f69c3d22f0ec1170b89c93ef1dc3 to fix the regression on FreeBSD. --- seatd/seatd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index 4587e50..053d44b 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -40,12 +40,12 @@ static int open_socket(const char *path, int uid, int gid) { goto error; } if (uid != -1 || gid != -1) { - if (fchown(fd, uid, gid) == -1) { + 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 (fchmod(fd, 0770) == -1) { + if (chmod(path, 0770) == -1) { log_errorf("Could not chmod socket: %s", strerror(errno)); goto error; } @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) { int socket_fd = open_socket(socket_path, uid, gid); if (socket_fd == -1) { - log_errorf("Could not create server socket: %s", strerror(errno)); + log_error("Could not create server socket"); server_finish(&server); return 1; } From 166feaea3394e00af14418e074ae090e31922f33 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 14 Aug 2021 09:03:23 +0000 Subject: [PATCH 074/159] Make libseat_seat_listener const libseat will never write to that struct. Let's allow callers to make it read-only. --- include/backend.h | 2 +- include/libseat.h | 2 +- libseat/backend/logind.c | 4 ++-- libseat/backend/noop.c | 4 ++-- libseat/backend/seatd.c | 6 +++--- libseat/libseat.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/backend.h b/include/backend.h index 075f48c..8f6ff39 100644 --- a/include/backend.h +++ b/include/backend.h @@ -16,7 +16,7 @@ struct named_backend { }; struct seat_impl { - struct libseat *(*open_seat)(struct libseat_seat_listener *listener, void *data); + struct libseat *(*open_seat)(const struct libseat_seat_listener *listener, void *data); int (*disable_seat)(struct libseat *seat); int (*close_seat)(struct libseat *seat); const char *(*seat_name)(struct libseat *seat); diff --git a/include/libseat.h b/include/libseat.h index 82098ea..2647fb9 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -55,7 +55,7 @@ struct libseat_seat_listener { * Returns a pointer to an opaque libseat struct on success. Returns NULL and * sets errno on error. */ -struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void *userdata); +struct libseat *libseat_open_seat(const struct libseat_seat_listener *listener, void *userdata); /* * Disables a seat, used in response to a disable_seat event. After disabling diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index aa659a6..d62b976 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -30,7 +30,7 @@ struct backend_logind { struct libseat base; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; sd_bus *bus; @@ -621,7 +621,7 @@ static int set_type(struct backend_logind *backend, const char *type) { return ret; } -static struct libseat *logind_open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *logind_open_seat(const struct libseat_seat_listener *listener, void *data) { struct backend_logind *backend = calloc(1, sizeof(struct backend_logind)); if (backend == NULL) { return NULL; diff --git a/libseat/backend/noop.c b/libseat/backend/noop.c index 71d0224..7436c48 100644 --- a/libseat/backend/noop.c +++ b/libseat/backend/noop.c @@ -13,7 +13,7 @@ struct backend_noop { struct libseat base; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; bool initial_setup; @@ -103,7 +103,7 @@ static int dispatch_background(struct libseat *base, int timeout) { return 0; } -static struct libseat *noop_open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *noop_open_seat(const struct libseat_seat_listener *listener, void *data) { struct backend_noop *backend = calloc(1, sizeof(struct backend_noop)); if (backend == NULL) { return NULL; diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 97971aa..25d8e95 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -33,7 +33,7 @@ struct pending_event { struct backend_seatd { struct libseat base; struct connection connection; - struct libseat_seat_listener *seat_listener; + const struct libseat_seat_listener *seat_listener; void *seat_listener_data; struct linked_list pending_events; bool error; @@ -363,7 +363,7 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { return predispatch + postdispatch; } -static struct libseat *_open_seat(struct libseat_seat_listener *listener, void *data, int fd) { +static struct libseat *_open_seat(const struct libseat_seat_listener *listener, void *data, int fd) { assert(listener != NULL); assert(listener->enable_seat != NULL && listener->disable_seat != NULL); struct backend_seatd *backend = calloc(1, sizeof(struct backend_seatd)); @@ -411,7 +411,7 @@ alloc_error: return NULL; } -static struct libseat *open_seat(struct libseat_seat_listener *listener, void *data) { +static struct libseat *open_seat(const struct libseat_seat_listener *listener, void *data) { int fd = seatd_connect(); if (fd == -1) { return NULL; diff --git a/libseat/libseat.c b/libseat/libseat.c index 42449a8..8cc9ab2 100644 --- a/libseat/libseat.c +++ b/libseat/libseat.c @@ -34,7 +34,7 @@ static const struct named_backend impls[] = { #error At least one backend must be enabled #endif -struct libseat *libseat_open_seat(struct libseat_seat_listener *listener, void *data) { +struct libseat *libseat_open_seat(const struct libseat_seat_listener *listener, void *data) { if (listener == NULL || listener->enable_seat == NULL || listener->disable_seat == NULL) { errno = EINVAL; return NULL; From 6e7a1db32d1a10593fd3adb95f8243ec322f472d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 15 Aug 2021 13:34:26 +0200 Subject: [PATCH 075/159] logind: Remove redundant null check --- libseat/backend/logind.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libseat/backend/logind.c b/libseat/backend/logind.c index d62b976..cb809e7 100644 --- a/libseat/backend/logind.c +++ b/libseat/backend/logind.c @@ -245,10 +245,6 @@ static int dispatch_and_execute(struct libseat *base, int timeout) { static const char *seat_name(struct libseat *base) { struct backend_logind *backend = backend_logind_from_libseat_backend(base); - - if (backend->seat == NULL) { - return NULL; - } return backend->seat; } From d9ae4c3010abfa1a72f1030afd282b5490747775 Mon Sep 17 00:00:00 2001 From: Greg Depoire--Ferrer Date: Wed, 4 Aug 2021 07:55:28 +0200 Subject: [PATCH 076/159] Revert "libseat: Check euid before using builtin" This reverts commit 1ae6c3b3ddf0ce2a2e1817eb9c74e0c03153df58. A user might want to run the builtin server as non root, if they have permission to use the devices. The check was originally copied from wlroots's direct backend. It was reverted in fa05d3cde68d with a detailed explanation of why root priviledges are not always necessary to use the DRM device. --- libseat/backend/seatd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 25d8e95..3ff54d6 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -606,11 +606,6 @@ static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, return NULL; } - if (geteuid() != 0) { - log_error("Built-in seatd instance requires root privileges"); - return NULL; - } - pid_t pid = fork(); if (pid == -1) { log_errorf("Could not fork: %s", strerror(errno)); From d78859bc9a7ed3c8e62c95087c4a9e56be2e95ce Mon Sep 17 00:00:00 2001 From: Greg Depoire--Ferrer Date: Wed, 4 Aug 2021 10:54:09 +0200 Subject: [PATCH 077/159] libseat: Update builtin backend root requirement documentation The builtin backend no longer requires root, setuid or CAP_SYS_ADMIN. This commit updates the documentation accordingly. --- include/libseat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/libseat.h b/include/libseat.h index 2647fb9..385acd9 100644 --- a/include/libseat.h +++ b/include/libseat.h @@ -47,8 +47,10 @@ struct libseat_seat_listener { * The available backends, if enabled at compile-time, are: seatd, logind and * builtin. * - * To use builtin, the process must have CAP_SYS_ADMIN or be root at the time - * of the call. These privileges can be dropped at any point after the call. + * To use builtin, the process must have permission to open and use the seat's + * devices at the time of the call. In the case of DRM devices, this includes + * permission for drmSetMaster(3). These privileges can be dropped at any + * point after the call. * * The returned pointer must be destroyed with libseat_close_seat. * From 038c30f9b1f93fb7fc9514366db3f3aa61a3ca49 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 15 Aug 2021 14:31:50 +0200 Subject: [PATCH 078/159] libseat: Fix build of builtin backend This was regressed by 166feaea3394e00af14418e074ae090e31922f33 which missed the builtin backend when changing struct libseat_seat_listener to being passed around as const. --- libseat/backend/seatd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libseat/backend/seatd.c b/libseat/backend/seatd.c index 3ff54d6..85df9f5 100644 --- a/libseat/backend/seatd.c +++ b/libseat/backend/seatd.c @@ -599,7 +599,7 @@ static int set_deathsig(int signal) { #error Unsupported platform #endif -static struct libseat *builtin_open_seat(struct libseat_seat_listener *listener, void *data) { +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) { log_errorf("Could not create socket pair: %s", strerror(errno)); From 15b0972bd3b8dbd1dae16ab3eb31a1026a63d17e Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Sun, 8 Aug 2021 19:00:35 +0200 Subject: [PATCH 079/159] meson.build: fix build with gcc < 7 Test if arguments (e.g. -Wimplicit-fallthrough) is available before using it as -Wimplicit-fallthrough has been added only since gcc 7.1 and https://github.com/gcc-mirror/gcc/commit/81fea426da8c4687bb32e6894dc26f00ae211822 and so it will raise the following build failure with gcc < 7: arm-none-linux-gnueabi-gcc: error: unrecognized command line option '-Wimplicit-fallthrough' Fixes: - http://autobuild.buildroot.org/results/0ee6816a7cceebdafd07612677a594bdf68e0790 Signed-off-by: Fabrice Fontaine --- meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 1131b4b..17324ec 100644 --- a/meson.build +++ b/meson.build @@ -22,7 +22,8 @@ if defaultpath == '' endif endif -add_project_arguments( +cc = meson.get_compiler('c') +add_project_arguments(cc.get_supported_arguments( [ '-Wundef', '-Wunused', @@ -41,7 +42,7 @@ add_project_arguments( '-D__BSD_VISIBLE', '-DSEATD_VERSION="@0@"'.format(meson.project_version()), '-DSEATD_DEFAULTPATH="@0@"'.format(defaultpath) - ], + ]), language: 'c', ) From df3f307b8e013814384723371dbfc549542a3a8f Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 23 Apr 2021 00:17:19 +0200 Subject: [PATCH 080/159] seat: Avoid holding a tty fd The kernel Secure Attention Key killer, triggered by SysRq+k, kills all processes that hold an fd referencing the tty. To avoid its attention, we stop storing the fd for the currently active VT in seat state. This has the added benefit of simplifying state a bit. --- include/seat.h | 1 - seatd/seat.c | 51 ++++++++++++++++---------------------------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/include/seat.h b/include/seat.h index fa5873c..cc243b6 100644 --- a/include/seat.h +++ b/include/seat.h @@ -33,7 +33,6 @@ struct seat { struct client *next_client; bool vt_bound; - int cur_ttyfd; int cur_vt; int session_cnt; }; diff --git a/seatd/seat.c b/seatd/seat.c index 9ad4af2..842928e 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -19,7 +19,7 @@ #include "terminal.h" static int seat_close_client(struct client *client); -static void vt_close(struct seat *seat); +static int vt_close(int vt); struct seat *seat_create(const char *seat_name, bool vt_bound) { struct seat *seat = calloc(1, sizeof(struct seat)); @@ -30,7 +30,6 @@ struct seat *seat_create(const char *seat_name, bool vt_bound) { seat->vt_bound = vt_bound; seat->seat_name = strdup(seat_name); seat->cur_vt = 0; - seat->cur_ttyfd = -1; if (seat->seat_name == NULL) { free(seat); return NULL; @@ -50,7 +49,6 @@ void seat_destroy(struct seat *seat) { assert(client->seat == seat); client_destroy(client); } - vt_close(seat); linked_list_remove(&seat->link); free(seat->seat_name); free(seat); @@ -66,47 +64,30 @@ static void seat_update_vt(struct seat *seat) { close(tty0fd); } -static int vt_open(struct seat *seat, int vt) { +static int vt_open(int vt) { assert(vt != -1); - if (seat->cur_ttyfd != -1) { - terminal_set_process_switching(seat->cur_ttyfd, true); - close(seat->cur_ttyfd); - } - seat->cur_ttyfd = terminal_open(vt); - if (seat->cur_ttyfd == -1) { + int ttyfd = terminal_open(vt); + if (ttyfd == -1) { log_errorf("Could not open terminal for VT %d: %s", vt, strerror(errno)); return -1; } - terminal_set_process_switching(seat->cur_ttyfd, true); - terminal_set_keyboard(seat->cur_ttyfd, false); - terminal_set_graphics(seat->cur_ttyfd, true); + terminal_set_process_switching(ttyfd, true); + terminal_set_keyboard(ttyfd, false); + terminal_set_graphics(ttyfd, true); + close(ttyfd); return 0; } -static void vt_close_fd(int fd) { - terminal_set_process_switching(fd, true); - terminal_set_keyboard(fd, true); - terminal_set_graphics(fd, false); -} - -static void vt_close(struct seat *seat) { - if (seat->cur_ttyfd == -1) { - return; - } - - vt_close_fd(seat->cur_ttyfd); - close(seat->cur_ttyfd); - seat->cur_ttyfd = -1; -} - -static int vt_close_num(int vt) { +static int vt_close(int vt) { int ttyfd = terminal_open(vt); if (ttyfd == -1) { log_errorf("Could not open terminal to clean up VT %d: %s", vt, strerror(errno)); return -1; } - vt_close_fd(ttyfd); + terminal_set_process_switching(ttyfd, true); + terminal_set_keyboard(ttyfd, true); + terminal_set_graphics(ttyfd, false); close(ttyfd); return 0; } @@ -452,7 +433,7 @@ int seat_open_client(struct seat *seat, struct client *client) { return -1; } - if (seat->vt_bound && vt_open(seat, client->session) == -1) { + if (seat->vt_bound && vt_open(client->session) == -1) { log_error("Could not open VT for client"); goto error; } @@ -477,7 +458,7 @@ int seat_open_client(struct seat *seat, struct client *client) { error: if (seat->vt_bound) { - vt_close(seat); + vt_close(seat->cur_vt); } return -1; } @@ -506,12 +487,12 @@ static int seat_close_client(struct client *client) { // This client was current, but there were no clients // waiting to take this VT, so clean it up. log_debug("Closing active VT"); - vt_close(seat); + vt_close(seat->cur_vt); } else if (!was_current && client->state != CLIENT_CLOSED) { // This client was not current, but as the client was // running, we need to clean up the VT. log_debug("Closing inactive VT"); - vt_close_num(client->session); + vt_close(client->session); } } From 29a6832ca0354f9bdc868533f9399dc3a0fb20e3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 1 Sep 2021 09:14:10 +0000 Subject: [PATCH 081/159] Add .editorconfig Allows text editor auto-configuration. --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..51a7d86 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 8 From 60c370d4ecdd0645738a6532bed1c9647e2224cb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 2 Sep 2021 23:03:20 +0200 Subject: [PATCH 082/159] seat: Allow new clients when active is pending ack New clients could only be added to a VT bound seat if there were no "active" client, regardless of its actual state. This meant that if one switched from an "active" VT to an "inactive" VT, the seat would be blocked while the "active" client was in CLIENT_PENDING_DISABLE, causing new clients to possibly fail should the old client take its time with the ack. Instead, allow new clients to also be added if there is an active client whose state is CLIENT_PENDING_DISABLE, and there is no client with the new VT as its session ID. --- seatd/seat.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/seatd/seat.c b/seatd/seat.c index 842928e..354273f 100644 --- a/seatd/seat.c +++ b/seatd/seat.c @@ -129,7 +129,8 @@ int seat_add_client(struct seat *seat, struct client *client) { return -1; } - if (seat->vt_bound && seat->active_client != NULL) { + if (seat->vt_bound && seat->active_client != NULL && + seat->active_client->state != CLIENT_PENDING_DISABLE) { log_error("Could not add client: seat is VT-bound and has an active client"); errno = EBUSY; return -1; @@ -148,6 +149,17 @@ int seat_add_client(struct seat *seat, struct client *client) { errno = EINVAL; return -1; } + if (seat->active_client != NULL) { + for (struct linked_list *elem = seat->clients.next; elem != &seat->clients; + elem = elem->next) { + struct client *client = (struct client *)elem; + if (client->session == seat->cur_vt) { + log_error("Could not add client: seat is VT-bound and already has pending client"); + errno = EBUSY; + return -1; + } + } + } client->session = seat->cur_vt; } else { client->session = seat->session_cnt++; From 17cdbe0ad2d0aa563e269cd23c770c75b312bbcb Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:40:09 +0200 Subject: [PATCH 083/159] seatd-launch: Set socket permissions directly Instead of relying on seatd's user/group arguments, which require turning our UID back into a username, just chmod/chown the socket ourselves once seatd is ready. We also reduce the permissions to just user access, instead of user and group like seatd specifies. --- seatd-launch/seatd-launch.c | 46 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 9fd3f23..f7ed482 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -1,13 +1,12 @@ #include #include -#include #include #include #include #include #include #include -#include +#include #include #include @@ -66,29 +65,13 @@ int main(int argc, char *argv[]) { char pipebuf[8]; sprintf(pipebuf, "%d", fds[1]); - struct passwd *user = getpwuid(getuid()); - if (!user) { - perror("getpwuid failed"); - _exit(1); - } - - // TODO: Make seatd accept the numeric UID - execlp("seatd", "seatd", "-n", pipebuf, "-u", user->pw_name, "-s", sockpath, NULL); + execlp("seatd", "seatd", "-n", pipebuf, "-s", sockpath, NULL); perror("Could not start seatd"); _exit(1); } close(fds[1]); - // Drop privileges - if (setgid(getgid()) == -1) { - perror("Could not set gid to drop privileges"); - goto error_seatd; - } - if (setuid(getuid()) == -1) { - perror("Could not set uid to drop privileges"); - goto error_seatd; - } - + // Wait for seatd to be ready char buf[1] = {0}; while (true) { pid_t p = waitpid(seatd_child, NULL, WNOHANG); @@ -127,6 +110,29 @@ int main(int argc, char *argv[]) { } close(fds[0]); + uid_t uid = getuid(); + gid_t gid = getgid(); + + // Restrict access to the socket to just us + if (chown(sockpath, uid, gid) == -1) { + perror("Could not chown seatd socket"); + goto error_seatd; + } + if (chmod(sockpath, 0700) == -1) { + perror("Could not chmod socket"); + goto error; + } + + // Drop privileges + if (setgid(gid) == -1) { + perror("Could not set gid to drop privileges"); + goto error_seatd; + } + if (setuid(uid) == -1) { + perror("Could not set uid to drop privileges"); + goto error_seatd; + } + pid_t child = fork(); if (child == -1) { perror("Could not fork target process"); From e7343ca96f3a59a4e5c846000d37b72f440afd44 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:41:48 +0200 Subject: [PATCH 084/159] man: Add simple seatd-launch(1) page --- man/seatd-launch.1.scd | 49 ++++++++++++++++++++++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 man/seatd-launch.1.scd diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd new file mode 100644 index 0000000..7994692 --- /dev/null +++ b/man/seatd-launch.1.scd @@ -0,0 +1,49 @@ +seatd-launch(1) + +# NAME + +seatd-launch - Start a process with its own seatd instance + +# SYNOPSIS + +*seatd-launch* [options] [--] command + +# OPTIONS + +*-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. + +# DESCRIPTION + +seatd-launch starts a seatd instance with a dedicated socket path, waits for it +to be ready, and starts the specified command with SEATD_SOCK set +appropriately. Once the specified command terminates, the seatd instance is +also terminated. + +seatd requires root privileges to perform its tasks. This can be achieved +through SUID of seatd-launch, *sudo(8)*/*doas(1)*, or by running seatd-launch +as root. seatd-launch will drop privileges from the effective user to the real +user before running the specified command. If the real user is root, this is +simply a noop - only run directly as root if you intend for the specified +command to run as root as well. + +seatd-launch serves a similar purpose to the libseat "builtin" backend, but is +superior to it for two reasons: +. The specified command never runs as root +. The standard seatd executable and libseat backend is used + +# SEE ALSO + +The libseat library, **, *seatd(1)* + +# AUTHORS + +Maintained by Kenny Levinsen , who is assisted by other +open-source contributors. For more information about seatd development, see +https://sr.ht/~kennylevinsen/seatd. diff --git a/meson.build b/meson.build index 17324ec..6b2ca2f 100644 --- a/meson.build +++ b/meson.build @@ -247,7 +247,7 @@ if scdoc.found() scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) mandir = get_option('mandir') - foreach src : ['seatd.1.scd'] + foreach src : ['seatd.1.scd', 'seatd-launch.1.scd'] topic = src.split('.')[0] section = src.split('.')[1] output = '@0@.@1@'.format(topic, section) From d1c6bb9a15b5123ec39e675d876e321bf2ebaca9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 8 Sep 2021 20:54:18 +0200 Subject: [PATCH 085/159] seatd-launch: Fix chmod error goto --- 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 f7ed482..0903fe1 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) { } if (chmod(sockpath, 0700) == -1) { perror("Could not chmod socket"); - goto error; + goto error_seatd; } // Drop privileges From 3ad9164a896eacffd27588f5b1fd6ea3e0bcd92d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 11 Sep 2021 14:02:44 +0200 Subject: [PATCH 086/159] Bump version to 0.6.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6b2ca2f..a9fc773 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.5.0', + version: '0.6.0', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From da59bea7752799803ff59a714627e53a5857b74d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 11 Sep 2021 15:55:26 +0200 Subject: [PATCH 087/159] man: Add seatd-launch(1) to SEE ALSO of seatd(1) --- man/seatd-launch.1.scd | 2 +- man/seatd.1.scd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index 7994692..b1fb685 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -40,7 +40,7 @@ superior to it for two reasons: # SEE ALSO -The libseat library, **, *seatd(1)* +The libseat library, **, *seatd*(1) # AUTHORS diff --git a/man/seatd.1.scd b/man/seatd.1.scd index 5945782..de95843 100644 --- a/man/seatd.1.scd +++ b/man/seatd.1.scd @@ -52,7 +52,7 @@ client-side of the protocol. # SEE ALSO -The libseat library, ** +The libseat library, **, *seatd-launch*(1) # AUTHORS From d5c1a7811bf76abf22045f8f2f5c24fc0d1f6747 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 12 Sep 2021 06:12:33 +0200 Subject: [PATCH 088/159] seatd-launch: respect PATH when looking for command $ seatd-launch sway -c /dev/null Could not start target: No such file or directory --- 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 0903fe1..c362a15 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -139,7 +139,7 @@ int main(int argc, char *argv[]) { goto error_seatd; } else if (child == 0) { setenv("SEATD_SOCK", sockpath, 1); - execv(argv[1], &argv[1]); + execvp(argv[1], &argv[1]); perror("Could not start target"); _exit(1); } From 483dbf76faf9f23117454aa8fc6d22abee3edc89 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 12 Sep 2021 11:44:07 +0200 Subject: [PATCH 089/159] seatd-launch: Use optind to find the command The command indexing had not been updated afer the introduction of getopt, so combining a command with flags would fail. Add error handling for if no command was specified while we're at it. --- seatd-launch/seatd-launch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index c362a15..1877c98 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -41,6 +41,12 @@ int main(int argc, char *argv[]) { } } + if (optind >= argc) { + fprintf(stderr, "A command must be specified\n\n%s", usage); + return 1; + } + char **command = &argv[optind]; + char sockbuf[256]; if (sockpath == NULL) { sprintf(sockbuf, "/tmp/seatd.%d.sock", getpid()); @@ -139,7 +145,7 @@ int main(int argc, char *argv[]) { goto error_seatd; } else if (child == 0) { setenv("SEATD_SOCK", sockpath, 1); - execvp(argv[1], &argv[1]); + execvp(command[0], command); perror("Could not start target"); _exit(1); } From 8c85c46d2db93fcbb7ff1e0bbeaeb3e4dd0e71a1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 12 Sep 2021 12:04:38 +0200 Subject: [PATCH 090/159] man/seatd-launch: Make mssage about root clearer --- man/seatd-launch.1.scd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index b1fb685..d882ba5 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -27,11 +27,11 @@ appropriately. Once the specified command terminates, the seatd instance is also terminated. seatd requires root privileges to perform its tasks. This can be achieved -through SUID of seatd-launch, *sudo(8)*/*doas(1)*, or by running seatd-launch -as root. seatd-launch will drop privileges from the effective user to the real -user before running the specified command. If the real user is root, this is -simply a noop - only run directly as root if you intend for the specified -command to run as root as well. +through SUID of seatd-launch or by running seatd-launch as root. seatd-launch +will drop privileges from the effective user to the real user before running +the specified command. If the real user is root, this is simply a noop. You +should only run seatd-launch as root if you intend for the specified command to +run as root as well. seatd-launch serves a similar purpose to the libseat "builtin" backend, but is superior to it for two reasons: From fe600eac2be9bd09d6c9746cf273a7eaed4e6f7f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Sep 2021 09:54:18 +0000 Subject: [PATCH 091/159] seatd-launch: exit with status >128 if child is signalled Mimick shells and exit with a status >128 if our child has been signalled. Exiting with 128 + signal number is what most shells do (POSIX only requires them to exit with >128). --- man/seatd-launch.1.scd | 8 ++++++++ seatd-launch/seatd-launch.c | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/man/seatd-launch.1.scd b/man/seatd-launch.1.scd index d882ba5..9234203 100644 --- a/man/seatd-launch.1.scd +++ b/man/seatd-launch.1.scd @@ -38,6 +38,14 @@ superior to it for two reasons: . The specified command never runs as root . The standard seatd executable and libseat backend is used +# EXIT STATUS + +seatd-launch exits with the status of its child. When the child terminates on +a signal _N_, seatd-launch exits with the status 128 + _N_. + +If seatd-launch fails because of another error, it exits with a non-zero +status. + # SEE ALSO The libseat library, **, *seatd*(1) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index 1877c98..ba61f5d 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -166,8 +166,10 @@ int main(int argc, char *argv[]) { if (WIFEXITED(status)) { return WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + return 128 + WTERMSIG(status); } else { - return 1; + abort(); // unreachable } error_seatd: From 4e3b7b3bb605daf7337db0c922904c251c58289a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Sep 2021 09:59:46 +0000 Subject: [PATCH 092/159] seatd-launch: print unlink/kill errors Makes it easier to find out that something went wrong. --- seatd-launch/seatd-launch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/seatd-launch/seatd-launch.c b/seatd-launch/seatd-launch.c index ba61f5d..b9d33d7 100644 --- a/seatd-launch/seatd-launch.c +++ b/seatd-launch/seatd-launch.c @@ -161,8 +161,12 @@ int main(int argc, char *argv[]) { } } - unlink(sockpath); - kill(seatd_child, SIGTERM); + if (unlink(sockpath) != 0) { + perror("Could not unlink socket"); + } + if (kill(seatd_child, SIGTERM) != 0) { + perror("Could not kill seatd"); + } if (WIFEXITED(status)) { return WEXITSTATUS(status); From 66becee6dac74384439838c5c40624ae043fb7bf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 14 Sep 2021 11:58:56 +0200 Subject: [PATCH 093/159] Bump version to 0.6.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a9fc773..999380d 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'seatd', 'c', - version: '0.6.0', + version: '0.6.1', license: 'MIT', meson_version: '>=0.56.0', default_options: [ From 4091ba2c07efde82a109fa8a07db77c814e90e5c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 15 Sep 2021 23:30:53 +0200 Subject: [PATCH 094/159] 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 095/159] 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 096/159] 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 097/159] 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 098/159] 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 099/159] 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 100/159] 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 101/159] 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 102/159] 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 103/159] 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 104/159] 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 105/159] 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 106/159] 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 107/159] 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 108/159] 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 109/159] 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 110/159] 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 111/159] 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 112/159] 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 113/159] 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 114/159] 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 115/159] 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 116/159] 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 117/159] 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 118/159] 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 119/159] 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 120/159] 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 121/159] 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 122/159] 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 123/159] 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 124/159] 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 125/159] 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 126/159] 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 127/159] 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 128/159] 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 129/159] 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 130/159] 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 131/159] 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 132/159] 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 133/159] 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 134/159] 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 135/159] 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 136/159] 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 137/159] 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 138/159] 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 139/159] 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 140/159] 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 141/159] 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 142/159] 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 143/159] 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 144/159] 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 145/159] 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 146/159] 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 147/159] 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 148/159] 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 149/159] 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 150/159] 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 151/159] 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 152/159] 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 153/159] 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 154/159] 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 155/159] 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 156/159] 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 157/159] 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 158/159] 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 159/159] 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;