From e802d381a168789a593cdf583562758c3f26f305 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 16 Mar 2021 12:52:31 +0100 Subject: [PATCH 001/127] 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 002/127] 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 003/127] 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 004/127] 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 005/127] 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 006/127] 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 007/127] 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 008/127] 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 009/127] 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 010/127] 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 011/127] 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 012/127] 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 013/127] 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 014/127] 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 015/127] 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 016/127] 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 017/127] 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 018/127] 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 019/127] 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 020/127] 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 021/127] 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 022/127] 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 023/127] 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 024/127] 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 025/127] 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 026/127] 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 027/127] 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 028/127] 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 029/127] 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 030/127] 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 031/127] 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 032/127] 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 033/127] 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 034/127] 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 035/127] 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 036/127] 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 037/127] 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 038/127] 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 039/127] 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 040/127] 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 041/127] 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 042/127] 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 043/127] 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 044/127] 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 045/127] 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 046/127] 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 047/127] 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 048/127] 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 049/127] 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 050/127] 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 051/127] 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 052/127] 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 053/127] 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 054/127] 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 055/127] 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 056/127] 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 057/127] 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 058/127] 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 059/127] 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 060/127] 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 061/127] 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 062/127] 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 063/127] 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 064/127] 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 065/127] 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 066/127] 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 067/127] 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 068/127] 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 069/127] 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 070/127] 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 071/127] 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 072/127] 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 073/127] 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 074/127] 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 075/127] 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 076/127] 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 077/127] 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 078/127] 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 079/127] 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 080/127] 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 081/127] 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 082/127] 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 083/127] 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 084/127] 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 085/127] 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 086/127] 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 087/127] 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 088/127] 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 089/127] 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 090/127] 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 091/127] 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 092/127] 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 093/127] 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 094/127] 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 095/127] 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 096/127] 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 097/127] 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 098/127] 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 099/127] 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 100/127] 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 101/127] 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 102/127] 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 103/127] 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 104/127] 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 105/127] 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 106/127] 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 107/127] 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 108/127] 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 109/127] 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 110/127] 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 111/127] 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 112/127] 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 113/127] 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 114/127] 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 115/127] 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 116/127] 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 117/127] 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 118/127] 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 119/127] 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 120/127] 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 121/127] 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 122/127] 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 123/127] 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 124/127] 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 125/127] 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 126/127] 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 127/127] 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;