diff --git a/src/udev/udev-config.c b/src/udev/udev-config.c index d88c18ba15..52855145da 100644 --- a/src/udev/udev-config.c +++ b/src/udev/udev-config.c @@ -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; diff --git a/src/udev/udev-config.h b/src/udev/udev-config.h index 72ac3920ab..127b3b9a1b 100644 --- a/src/udev/udev-config.h +++ b/src/udev/udev-config.h @@ -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); diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 919314b546..d35100198b 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -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]);