From 8d983291165e4c2b5d31dc71142d7706ac424108 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 15 Feb 2022 17:03:50 +0100 Subject: [PATCH] Add generator for logger.ko device dependencies This will dynamically generate needed systemd unit dependencies when logger.ko devices are available (/dev/log_* devices are assumed to be used when these are available due to backend autodetection). Change-Id: I1b280d3878e6c4db5261f410722d3de84c583b60 --- Makefile.am | 16 +++ configs/dlog_logger.service.in | 9 +- packaging/dlog.spec | 3 +- src/logger-unit-generator/logger-unit-generator.c | 124 ++++++++++++++++++++++ 4 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 src/logger-unit-generator/logger-unit-generator.c diff --git a/Makefile.am b/Makefile.am index d030026..32fe5c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -150,6 +150,22 @@ dlog_logger_SOURCES = \ src/shared/util_parser.c \ src/shared/log_file.c +systemgeneratordir = /usr/lib/systemd/system-generators + +systemgenerator_PROGRAMS = dlog-unit-generator + +dlog_unit_generator_CFLAGS = \ + $(AM_CFLAGS) \ + -fPIE + +dlog_unit_generator_LDFLAGS = \ + $(AM_LDFLAGS) \ + -pie + +dlog_unit_generator_SOURCES = \ + src/logger-unit-generator/logger-unit-generator.c + + bin_PROGRAMS += dlogsend dlogsend_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/configs/dlog_logger.service.in b/configs/dlog_logger.service.in index 285d101..ac967d2 100644 --- a/configs/dlog_logger.service.in +++ b/configs/dlog_logger.service.in @@ -6,12 +6,9 @@ Before=basic.target DefaultDependencies=no # Note: -# This unit would typically wait for /dev/log_* devices to appear in the system and only then exec service. -# However, when backend is determined automatically should not delay the startup waiting for devices that -# will never appear. -# -# Wants=dev-log_main.device dev-log_system.device dev-log_radio.device -# After=dev-log_main.device dev-log_system.device dev-log_radio.device dev-log_events.device dev-log_apps.device +# Requires=/After= are added dynamically via dlog-unit-generator (see systemd.generator(7)) if logger +# devices are available. This is required as dlog_logger has to have devices available and with proper +# permissions being set before it starts (as we run as 'log' user). [Service] Type=notify diff --git a/packaging/dlog.spec b/packaging/dlog.spec index b0d3e15..fccb367 100644 --- a/packaging/dlog.spec +++ b/packaging/dlog.spec @@ -3,7 +3,7 @@ Name: dlog Summary: Logging service -Version: 7.0.1 +Version: 7.0.2 Release: 1 Group: System/Libraries License: Apache-2.0, MIT @@ -267,6 +267,7 @@ chsmack -e 'System' %{_libexecdir}/dlog-log-critical %attr(750,log,log) %{_bindir}/dlog_logger %{_unitdir}/basic.target.wants/dlog_logger.service %{_unitdir}/dlog_logger.service +/usr/lib/systemd/system-generators/dlog-unit-generator %files config-syslog %manifest dlog.manifest diff --git a/src/logger-unit-generator/logger-unit-generator.c b/src/logger-unit-generator/logger-unit-generator.c new file mode 100644 index 0000000..ed2dde7 --- /dev/null +++ b/src/logger-unit-generator/logger-unit-generator.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +// +// This is systemd.generator(7) interface program used to generate dlog_logger.service dependencies for +// logger (kernel) driver. +// +// This code is going to run in controlled environment, before any of userspace is running so there is +// no danger of a malicious race condition (only other processes running are other systemd-generators +// and systemd itself). + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SERVICE_DIR "dlog_logger.service.d" +#define SERVICE_SNIPPET "loggerdevs.conf" + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) +#define LINE_MAX 128 + +struct dev_node { + const char *name; + bool have; +}; + +static void print_devs(int fd, struct dev_node devs[], unsigned int devs_size) +{ + for (unsigned int i = 0; i < devs_size; i++) { + if (!devs[i].have) + continue; + dprintf(fd, "dev-%s.device ", devs[i].name); + } +} + +static int make_subdir(const char *rootdir, const char *subdir) +{ + int rootdirfd = open(rootdir, O_DIRECTORY); + if (rootdirfd < 0) + return false; + (void)mkdirat(rootdirfd, subdir, 0755); // no error checking needed here as success is determined by ability to open unitdir below + + int subdirfd = openat(rootdirfd, subdir, O_DIRECTORY); + close(rootdirfd); + + return subdirfd; +} + +static bool write_unit(const char *unitpath, const char *unitdir, const char *unitname, struct dev_node devs[], unsigned int devs_size) +{ + int subdirfd = make_subdir(unitpath, unitdir); + if (subdirfd < 0) + return false; + + int fd = openat(subdirfd, unitname, O_CREAT | O_EXCL | O_WRONLY, 0644); + close(subdirfd); + if (fd < 0) + return false; + + dprintf(fd, "[Unit]\nRequires="); + print_devs(fd, devs, devs_size); + dprintf(fd, "\nAfter="); + print_devs(fd, devs, devs_size); + dprintf(fd, "\n"); + + close(fd); + + return true; +} + +static bool check_and_mark_devs(struct dev_node devs[], unsigned int devs_size) +{ + bool have = false; + + DIR *dir = opendir("/dev"); + if (!dir) + return false; + + struct dirent *de; + while ((de = readdir(dir))) { + for (unsigned int i = 0; i < devs_size; ++i) { + if (0 != strcmp(de->d_name, devs[i].name)) + continue; + + devs[i].have = true; + have = true; + break; + } + } + closedir(dir); + + return have; +} + +int main(int ac, char *av[]) +{ + char *unitpath = NULL; + + // This program follows systemd.generator(7) interface + if (2 == ac) + unitpath = av[1]; + else if (4 == ac) + unitpath = av[2]; + else { + printf("usage: %s {normal-dir [early-dir late-dir]}\n", av[0]); + exit(EXIT_FAILURE); + } + + struct dev_node devs[] = { + { .name = "log_main", .have = false }, + { .name = "log_system", .have = false }, + { .name = "log_events", .have = false }, + { .name = "log_radio", .have = false }, + }; + + if (check_and_mark_devs(devs, ARRAY_SIZE(devs))) + write_unit(unitpath, SERVICE_DIR, SERVICE_SNIPPET, devs, ARRAY_SIZE(devs)); + + return EXIT_SUCCESS; +} -- 2.7.4