It would be nice when seatd supports systemd's socket activation. E.g. the setup of the listening socket is done by systemd and seatd just uses the given fd. This will solve #20 implicitly because the the underlying problem (wait until service accepts requests) disappears.
I tested it with
From 4e0440268ef13a329bb329c3b1d4454f2a58aaef Mon Sep 17 00:00:00 2001
From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Date: Thu, 2 May 2024 16:47:34 +0200
Subject: [PATCH 1/2] sd-listen: implement sd_listen() function
From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Based on systemd sources with manual implementation of the safe_ato*()
functions.
Upstream-Status: Pending
Signed-off-by: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
---
meson.build | 1 +
seatd/sd-listen.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++
seatd/sd-listen.h | 8 +++
3 files changed, 168 insertions(+)
create mode 100644 seatd/sd-listen.c
create mode 100644 seatd/sd-listen.h
diff --git a/meson.build b/meson.build
index 516d7d2..43de87c 100644
--- a/meson.build
+++ b/meson.build
@@ -119,6 +119,7 @@ server_files = [
'seatd/seat.c',
'seatd/client.c',
'seatd/server.c',
+ 'seatd/sd-listen.c',
]
with_seatd = get_option('libseat-seatd') == 'enabled'
diff --git a/seatd/sd-listen.c b/seatd/sd-listen.c
new file mode 100644
index 0000000..c1c2884
--- /dev/null
+++ b/seatd/sd-listen.c
@@ -0,0 +1,159 @@
+#include "sd-listen.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+
+#define variable_is_signed(_var) \
+ _Generic(_var, \
+ signed char: true, \
+ unsigned char: false, \
+ int: true, \
+ short: true, \
+ long: true, \
+ long long: true, \
+ unsigned short: false, \
+ unsigned int: false, \
+ unsigned long: false, \
+ unsigned long long: false)
+
+#define integer_safe_assign(_dst, _src) __extension__ \
+ ({ \
+ int _safe_assign_res = 1; \
+ if ((__typeof__(_src))((__typeof__(_dst))(_src)) != (_src)) \
+ _safe_assign_res = 0; \
+ else \
+ (_dst) = (__typeof__(_dst))(_src); \
+ _safe_assign_res; \
+ })
+
+#define safe_atoX(_s, _res_ptr, _fn, _fn_type) \
+ do { \
+ char const *s = (_s); \
+ _fn_type res; \
+ char *e; \
+ \
+ errno = 0; \
+ res = _fn(s, &e, 0); \
+ if (errno > 0) { \
+ return -1; \
+ } else if (*s == '\0' || *e != '\0') { \
+ errno = EINVAL; \
+ return -1; \
+ } else if (!variable_is_signed(res) && *s == '-') { \
+ errno = EINVAL; \
+ return -1; \
+ } else if (!integer_safe_assign(*(_res_ptr), res)) { \
+ errno = ERANGE; \
+ return -1; \
+ } else { \
+ return 0; \
+ } \
+ } while (0)
+
+static int safe_atoi(char const *str, int *ret)
+{
+ safe_atoX(str, ret, strtol, long);
+}
+
+static int safe_atolu(char const *str, unsigned long *ret)
+{
+ safe_atoX(str, ret, strtoul, unsigned long);
+}
+
+static int parse_pid(char const *s, pid_t * ret)
+{
+ unsigned long pid;
+ int rc;
+
+ rc = safe_atolu(s, &pid);
+ if (rc < 0) {
+ return rc;
+ } else if (!integer_safe_assign(*ret, pid)) {
+ errno = EINVAL;
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static int fd_cloexec(int fd, bool ena)
+{
+ int flags = fcntl(fd, F_GETFD, 0);
+
+ if (flags < 0)
+ return flags;
+
+ if (ena)
+ flags |= FD_CLOEXEC;
+ else
+ flags &= ~FD_CLOEXEC;
+
+ return fcntl(fd, F_SETFD, flags);
+}
+
+static void unsetenv_all(bool unset_environment)
+{
+
+ if (!unset_environment)
+ return;
+
+ unsetenv("LISTEN_PID");
+ unsetenv("LISTEN_FDS");
+ unsetenv("LISTEN_FDNAMES");
+}
+
+int sd_listen_fds(int unset_environment)
+{
+ const char *e;
+ int n, r, fd;
+ pid_t pid;
+
+ e = getenv("LISTEN_PID");
+ if (!e) {
+ r = 0;
+ goto finish;
+ }
+
+ r = parse_pid(e, &pid);
+ if (r < 0)
+ goto finish;
+
+ /* Is this for us? */
+ if (getpid() != pid) {
+ r = 0;
+ goto finish;
+ }
+
+ e = getenv("LISTEN_FDS");
+ if (!e) {
+ r = 0;
+ goto finish;
+ }
+
+ r = safe_atoi(e, &n);
+ if (r < 0)
+ goto finish;
+
+ _Static_assert(SD_LISTEN_FDS_START < INT_MAX,
+ "SD_LISTEN_FDS_START out of range");
+ if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
+ r = fd_cloexec(fd, true);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = n;
+
+finish:
+ unsetenv_all(unset_environment);
+ return r;
+}
diff --git a/seatd/sd-listen.h b/seatd/sd-listen.h
new file mode 100644
index 0000000..3ee2f8b
--- /dev/null
+++ b/seatd/sd-listen.h
@@ -0,0 +1,8 @@
+#ifndef H_SEATD_SD_LISTEN_H
+#define H_SEATD_SD_LISTEN_H
+
+#define SD_LISTEN_FDS_START 3
+
+int sd_listen_fds(int unset_environment);
+
+#endif /* H_SEATD_SD_LISTEN_H */
--
2.44.0
From e19fc72390aaf98f712ed61553a0dbb2387923a9 Mon Sep 17 00:00:00 2001
From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Date: Thu, 2 May 2024 16:48:32 +0200
Subject: [PATCH 2/2] seatd: use systemd socket activation
From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Upstream-Status: Pending
Signed-off-by: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
---
seatd/seatd.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
Index: git/seatd/seatd.c
===================================================================
--- git.orig/seatd/seatd.c
+++ git/seatd/seatd.c
@@ -15,6 +15,8 @@
#include "poller.h"
#include "server.h"
+#include "sd-listen.h"
+
#define LISTEN_BACKLOG 16
static int open_socket(const char *path, int uid, int gid) {
@@ -152,8 +154,10 @@ int main(int argc, char *argv[]) {
log_init();
libseat_set_log_level(level);
+ bool systemd_socket = sd_listen_fds(1) > 0;
+
struct stat st;
- if (lstat(SEATD_DEFAULTPATH, &st) == 0) {
+ if (!systemd_socket && 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);
@@ -179,7 +183,11 @@ int main(int argc, char *argv[]) {
}
int ret = 1;
- int socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid);
+ int socket_fd = systemd_socket ? SD_LISTEN_FDS_START : -1;
+
+ if (socket_fd < 0)
+ socket_fd = open_socket(SEATD_DEFAULTPATH, uid, gid);
+
if (socket_fd == -1) {
log_error("Could not create server socket");
goto error_server;
@@ -210,7 +218,7 @@ int main(int argc, char *argv[]) {
ret = 0;
error_socket:
- if (unlink(SEATD_DEFAULTPATH) == -1) {
+ if (!systemd_socket && unlink(SEATD_DEFAULTPATH) == -1) {
log_errorf("Could not remove socket: %s", strerror(errno));
}
error_server:
and
## seatd.service
[Unit]
[Service]
Type=simple
ExecStart=/usr/bin/seatd
## seatd.socket
[Unit]
Description=seatd socket
[Socket]
ListenStream=/run/seatd.sock
SocketMode=0770
SocketGroup=video
RemoveOnStop=yes
[Install]
WantedBy=sockets.target