]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-config: serialize/deserialize dynamical configurations
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Apr 2025 19:33:14 +0000 (04:33 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 11 Apr 2025 20:08:20 +0000 (05:08 +0900)
Previously, configurations set by 'udevadm control' such as log level,
maximum number of childrens, global properties, and so on were discarded
on restart. This makes udevd serialize those configurations on stop, and
deserialize them in the next invocation.

src/udev/udev-config.c
src/udev/udev-config.h
src/udev/udev-manager.c

index d88c18ba15dcc28ba2877731988466b32b38f735..52855145da7071f1a6d8d742b4f696f75a2a2cb5 100644 (file)
@@ -5,10 +5,14 @@
 
 #include "conf-parser.h"
 #include "cpu-set-util.h"
+#include "daemon-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "limits-util.h"
 #include "parse-util.h"
 #include "pretty-print.h"
 #include "proc-cmdline.h"
+#include "serialize.h"
 #include "signal-util.h"
 #include "syslog-util.h"
 #include "udev-config.h"
@@ -512,6 +516,115 @@ UdevReloadFlags manager_revert_config(Manager *manager) {
         return flags | manager_needs_reload(manager, &old);
 }
 
+int manager_serialize_config(Manager *manager) {
+        int r;
+
+        assert(manager);
+
+        _cleanup_fclose_ FILE *f = NULL;
+        r = open_serialization_file("systemd-udevd", &f);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to open new serialization file: %m");
+
+        if (manager->config_by_control.log_level >= 0) {
+                r = serialize_item_format(f, "log-level", "%i", manager->config_by_control.log_level);
+                if (r < 0)
+                        return r;
+        }
+
+        if (manager->config_by_control.children_max > 0) {
+                r = serialize_item_format(f, "children-max", "%u", manager->config_by_control.children_max);
+                if (r < 0)
+                        return r;
+        }
+
+        r = serialize_bool_elide(f, "trace", manager->config_by_control.trace);
+        if (r < 0)
+                return r;
+
+        const char *k, *v;
+        HASHMAP_FOREACH_KEY(v, k, manager->properties) {
+                r = serialize_item_format(f, "property", "%s=%s", k, v);
+                if (r < 0)
+                        return r;
+        }
+
+        r = finish_serialization_file(f);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to finalize serialization file: %m");
+
+        /* Remove the previous serialization to make it replaced with the new one. */
+        (void) notify_remove_fd_warn("config-serialization");
+
+        r = notify_push_fd(fileno(f), "config-serialization");
+        if (r < 0)
+                return log_warning_errno(r, "Failed to push serialization fd to service manager: %m");
+
+        log_debug("Serialized configurations.");
+        return 0;
+}
+
+int manager_deserialize_config(Manager *manager, int *fd) {
+        int r;
+
+        assert(manager);
+        assert(fd);
+        assert(*fd >= 0);
+
+        /* This may invalidate passed file descriptor even on failure. */
+
+        _cleanup_fclose_ FILE *f = take_fdopen(fd, "r");
+        if (!f)
+                return log_warning_errno(errno, "Failed to open serialization fd: %m");
+
+        for (;;) {
+                _cleanup_free_ char *l = NULL;
+                const char *val;
+
+                r = deserialize_read_line(f, &l);
+                if (r < 0)
+                        return r;
+                if (r == 0) /* eof or end marker */
+                        break;
+
+                if ((val = startswith(l, "log-level="))) {
+                        r = log_level_from_string(val);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to parse serialized log level (%s), ignoring: %m", val);
+                        else
+                                manager->config_by_control.log_level = r;
+
+                } else if ((val = startswith(l, "children-max="))) {
+                        r = safe_atou(val, &manager->config_by_control.children_max);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to parse serialized children max (%s), ignoring: %m", val);
+
+                } else if ((val = startswith(l, "trace="))) {
+                        r = parse_boolean(val);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to parse serialized trace (%s), ignoring: %m", val);
+                        else
+                                manager->config_by_control.trace = r;
+
+                } else if ((val = startswith(l, "property="))) {
+                        if (!udev_property_assignment_is_valid(val))
+                                r = -EINVAL;
+                        else
+                                r = manager_set_environment_one(manager, val);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to deserialize property (%s), ignoring: %m", val);
+
+                } else
+                        log_debug("Unknown serialization item, ignoring: %s", l);
+        }
+
+        manager_merge_config(manager);
+        manager_adjust_config(&manager->config);
+
+        log_debug("Deserialized configurations.");
+        return 0;
+}
+
 static usec_t extra_timeout_usec(void) {
         static usec_t saved = 10 * USEC_PER_SEC;
         static bool parsed = false;
index 72ac3920ab411ad9a0cc690647b73cbab7d02866..127b3b9a1be0b93db3173cd7a39918c65ed3091b 100644 (file)
@@ -36,4 +36,7 @@ int manager_load(Manager *manager, int argc, char *argv[]);
 UdevReloadFlags manager_reload_config(Manager *manager);
 UdevReloadFlags manager_revert_config(Manager *manager);
 
+int manager_serialize_config(Manager *manager);
+int manager_deserialize_config(Manager *manager, int *fd);
+
 usec_t manager_kill_worker_timeout(Manager *manager);
index 919314b54682167005dedf034b7ff03a536d1e6b..d35100198bfac16c95a76f0dafc92a2cab5c056b 100644 (file)
@@ -237,6 +237,7 @@ void manager_exit(Manager *manager) {
         /* close sources of new events and discard buffered events */
         manager->ctrl = udev_ctrl_unref(manager->ctrl);
         manager->varlink_server = sd_varlink_server_unref(manager->varlink_server);
+        (void) manager_serialize_config(manager);
 
         /* Disable the event source, but does not close the inotify fd here, as we may still receive
          * notification messages about requests to add or remove inotify watches. */
@@ -1178,6 +1179,8 @@ static int manager_listen_fds(Manager *manager) {
                         r = manager_init_device_monitor(manager, fd);
                 else if (streq(names[i], "inotify"))
                         r = manager_init_inotify(manager, fd);
+                else if (streq(names[i], "config-serialization"))
+                        r = manager_deserialize_config(manager, &fd);
                 else
                         r = log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
                                             "Received unexpected fd (%s), ignoring.", names[i]);