seatd already provides a systemd.service to start and run seatd. As seatd needs to run as root while it may be preferable to run users of the seat as non-root user, it is not possible to add a dependency from other systemd.services to the seatd.service. Therefore, the seatd.service always needs to run on such systems even if no other process actually needs it. Socket activation allows to start the seatd service only when some other process tries to connect to the socket. Michael Michael Tretter (2): seatd: Initialize server before removing socket seatd: Add support for systemd.socket activation contrib/systemd/seatd.socket | 9 +++++++ meson.build | 9 ++++++- seatd/seatd.c | 51 +++++++++++++++++++++++++++--------- 3 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 contrib/systemd/seatd.socket -- 2.30.2
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~kennylevinsen/seatd-devel/patches/38479/mbox | git am -3Learn more about email & git
Removing an existing socket is a preparation for creating a new socket. Initializing the service between removing a left-over socket and creating a new socket makes error handling difficult. This is a preparation for adding systemd socket activation. --- seatd/seatd.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/seatd/seatd.c b/seatd/seatd.c index f88e6c96aa71..bc200f0587dd 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -152,33 +152,33 @@ int main(int argc, char *argv[]) { log_init(); libseat_set_log_level(level); + struct server server = {0}; + if (server_init(&server) == -1) { + log_errorf("server_init failed: %s", strerror(errno)); + return 1; + } + + int ret = 1; struct stat st; 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", SEATD_DEFAULTPATH); - return 1; + goto error_server; } else if (!unlink_existing_socket) { log_errorf("Socket file found at socket path %s, refusing to start", SEATD_DEFAULTPATH); - return 1; + goto error_server; } else { // 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; + goto error_server; } } } - struct server server = {0}; - if (server_init(&server) == -1) { - log_errorf("server_init failed: %s", strerror(errno)); - return 1; - } - - int ret = 1; int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); -- 2.30.2
Allow to start seatd on demand using systemd.socket activation. This is especially helpful to start a seatd service as root user only if a user starts an application that needs a seat. --- contrib/systemd/seatd.socket | 9 +++++++++ meson.build | 9 ++++++++- seatd/seatd.c | 31 +++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 contrib/systemd/seatd.socket diff --git a/contrib/systemd/seatd.socket b/contrib/systemd/seatd.socket new file mode 100644 index 000000000000..e922def28ef0 --- /dev/null +++ b/contrib/systemd/seatd.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Seatd Socket +Before=sockets.target + +[Socket] +ListenStream=%t/seatd.sock + +[Install] +WantedBy=sockets.target diff --git a/meson.build b/meson.build index 661b39ab2c9b..5da8bb1b55eb 100644 --- a/meson.build +++ b/meson.build @@ -215,12 +215,19 @@ libseat = declare_dependency( meson.override_dependency('libseat', libseat) if with_server + libsystemd = dependency('libsystemd', required: false) + seatd_c_args = [] + if libsystemd.found() + seatd_c_args += '-DHAVE_LIBSYSTEMD' + endif + executable( 'seatd', [ server_files, 'seatd/seatd.c' ], include_directories: [include_directories('.', 'include')], install: true, - dependencies: [realtime], + dependencies: [realtime, libsystemd], + c_args: seatd_c_args, ) executable( 'seatd-launch', diff --git a/seatd/seatd.c b/seatd/seatd.c index bc200f0587dd..e4dcb7878c23 100644 --- a/seatd/seatd.c +++ b/seatd/seatd.c @@ -10,6 +10,10 @@ #include <sys/stat.h> #include <sys/un.h> +#if defined(HAVE_LIBSYSTEMD) +#include <systemd/sd-daemon.h> +#endif + #include "client.h" #include "log.h" #include "poller.h" @@ -17,6 +21,26 @@ #define LISTEN_BACKLOG 16 +#if defined(HAVE_LIBSYSTEMD) +static int accept_socket(const char *path) +{ + int n = sd_listen_fds(0); + int i; + for (i = 0; i < n; ++i) { + if (sd_is_socket_unix(SD_LISTEN_FDS_START + i, SOCK_STREAM, 1, path, 0) > 0) + return SD_LISTEN_FDS_START + i; + } + + return -1; +} +#else +static inline int accept_socket(const char *path) +{ + (void) path; + return -1; +} +#endif + static int open_socket(const char *path, int uid, int gid) { union { struct sockaddr_un unix; @@ -158,6 +182,8 @@ int main(int argc, char *argv[]) { return 1; } + int socket_fd = accept_socket(SEATD_DEFAULTPATH); + int ret = 1; struct stat st; if (lstat(SEATD_DEFAULTPATH, &st) == 0) { @@ -169,7 +195,7 @@ int main(int argc, char *argv[]) { log_errorf("Socket file found at socket path %s, refusing to start", SEATD_DEFAULTPATH); goto error_server; - } else { + } else if (socket_fd == -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) { @@ -179,7 +205,8 @@ int main(int argc, char *argv[]) { } } - int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); + if (socket_fd == -1) + socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid); if (socket_fd == -1) { log_error("Could not create server socket"); goto error_server; -- 2.30.2