From 4f9ff96a55187927a4164a19df580329f4c6522b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 2 Jun 2020 14:55:12 +0200 Subject: [PATCH] conf-parser: return mtime in config_parse() and friends This is a follow-up for 9f83091e3cceb646a66fa9df89de6d9a77c21d86. Instead of reading the mtime off the configuration files after reading, let's do so before reading, but with the fd we read the data from. This is not only cleaner (as it allows us to save one stat()), but also has the benefit that we'll detect changes that happen while we read the files. This also reworks unit file drop-ins to use the common code for determining drop-in mtime, instead of reading system clock for that. --- src/core/load-dropin.c | 13 +- src/core/load-fragment.c | 4 +- src/core/main.c | 8 +- src/coredump/coredump.c | 13 +- src/fuzz/fuzz-unit-file.c | 11 +- src/home/homed-conf.c | 13 +- src/journal-remote/journal-remote-main.c | 12 +- src/journal-remote/journal-upload.c | 15 ++- src/journal/journald-server.c | 23 ++-- src/login/logind-core.c | 12 +- src/network/netdev/netdev.c | 21 ++-- src/network/networkd-conf.c | 14 ++- src/network/networkd-network.c | 118 ++++++++---------- src/nspawn/nspawn-settings.c | 2 +- src/partition/repart.c | 7 +- src/pstore/pstore.c | 13 +- src/resolve/resolved-conf.c | 13 +- src/resolve/resolved-dnssd.c | 11 +- src/shared/conf-parser.c | 52 +++++--- src/shared/conf-parser.h | 11 +- src/shared/install.c | 3 +- src/shared/sleep-config.c | 12 +- src/test/test-conf-parser.c | 10 +- src/timesync/timesyncd-conf.c | 13 +- .../tty-ask-password-agent.c | 4 +- src/udev/net/link-config.c | 3 +- .../xdg-autostart-service.c | 3 +- 27 files changed, 253 insertions(+), 181 deletions(-) diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index f61e9da6f28..0da3eafb129 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -114,12 +114,13 @@ int unit_load_dropin(Unit *u) { } STRV_FOREACH(f, u->dropin_paths) - (void) config_parse(u->id, *f, NULL, - UNIT_VTABLE(u)->sections, - config_item_perf_lookup, load_fragment_gperf_lookup, - 0, u); - - u->dropin_mtime = now(CLOCK_REALTIME); + (void) config_parse( + u->id, *f, NULL, + UNIT_VTABLE(u)->sections, + config_item_perf_lookup, load_fragment_gperf_lookup, + 0, + u, + &u->dropin_mtime); return 0; } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a967627946c..780692ce0eb 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -4864,7 +4864,9 @@ int unit_load_fragment(Unit *u) { r = config_parse(u->id, fragment, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, load_fragment_gperf_lookup, - CONFIG_PARSE_ALLOW_INCLUDE, u); + CONFIG_PARSE_ALLOW_INCLUDE, + u, + NULL); if (r == -ENOEXEC) log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started."); if (r < 0) diff --git a/src/core/main.c b/src/core/main.c index 32b963d4a4f..e1de821e665 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -657,7 +657,13 @@ static int parse_config_file(void) { CONF_PATHS_NULSTR("systemd/system.conf.d") : CONF_PATHS_NULSTR("systemd/user.conf.d"); - (void) config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL); + (void) config_parse_many_nulstr( + fn, conf_dirs_nulstr, + "Manager\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY * like everywhere else. */ diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 42231dbd6b6..d156d98efcd 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -155,11 +155,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf", - CONF_PATHS_NULSTR("systemd/coredump.conf.d"), - "Coredump\0", - config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/coredump.conf", + CONF_PATHS_NULSTR("systemd/coredump.conf.d"), + "Coredump\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static uint64_t storage_size_max(void) { diff --git a/src/fuzz/fuzz-unit-file.c b/src/fuzz/fuzz-unit-file.c index d3993cf123f..34f59a44372 100644 --- a/src/fuzz/fuzz-unit-file.c +++ b/src/fuzz/fuzz-unit-file.c @@ -70,10 +70,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { name = strjoina("a.", unit_type_to_string(t)); assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0); - (void) config_parse(name, name, f, - UNIT_VTABLE(u)->sections, - config_item_perf_lookup, load_fragment_gperf_lookup, - CONFIG_PARSE_ALLOW_INCLUDE, u); + (void) config_parse( + name, name, f, + UNIT_VTABLE(u)->sections, + config_item_perf_lookup, load_fragment_gperf_lookup, + CONFIG_PARSE_ALLOW_INCLUDE, + u, + NULL); g = open_memstream_unlocked(&out, &out_size); assert_se(g); diff --git a/src/home/homed-conf.c b/src/home/homed-conf.c index 14ec8b336d4..df3a17358bb 100644 --- a/src/home/homed-conf.c +++ b/src/home/homed-conf.c @@ -10,11 +10,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf", - CONF_PATHS_NULSTR("systemd/homed.conf.d"), - "Home\0", - config_item_perf_lookup, homed_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/homed.conf", + CONF_PATHS_NULSTR("systemd/homed.conf.d"), + "Home\0", + config_item_perf_lookup, homed_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index 551b84130dd..948b2d2fce6 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -762,10 +762,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf", - CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), - "Remote\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journal-remote.conf", + CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), + "Remote\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static int help(void) { diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index bf656ac6706..bd58fdbcdfb 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -562,12 +562,17 @@ static int parse_config(void) { { "Upload", "ServerKeyFile", config_parse_path_or_ignore, 0, &arg_key }, { "Upload", "ServerCertificateFile", config_parse_path_or_ignore, 0, &arg_cert }, { "Upload", "TrustedCertificateFile", config_parse_path_or_ignore, 0, &arg_trust }, - {}}; + {} + }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf", - CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), - "Upload\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journal-upload.conf", + CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), + "Upload\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } static int help(void) { diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 9efa65a2942..5865bf98096 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1633,23 +1633,24 @@ static int server_parse_config_file(Server *s) { /* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */ namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf"); - r = config_parse( - NULL, - namespaced, NULL, - "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s); + r = config_parse(NULL, + namespaced, NULL, + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, s, + NULL); if (r < 0) return r; return 0; } - return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf", - CONF_PATHS_NULSTR("systemd/journald.conf.d"), - "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/journald.conf", + CONF_PATHS_NULSTR("systemd/journald.conf.d"), + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, s, NULL); } static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) { diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 1375f438e4b..4289461df68 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -69,11 +69,13 @@ void manager_reset_config(Manager *m) { int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf", - CONF_PATHS_NULSTR("systemd/logind.conf.d"), - "Login\0", - config_item_perf_lookup, logind_gperf_lookup, - CONFIG_PARSE_WARN, m); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/logind.conf", + CONF_PATHS_NULSTR("systemd/logind.conf.d"), + "Login\0", + config_item_perf_lookup, logind_gperf_lookup, + CONFIG_PARSE_WARN, m, + NULL); } int manager_add_device(Manager *m, const char *sysfs, bool master, Device **ret_device) { diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index a990c64b55f..1889f6f13c9 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -686,10 +686,13 @@ int netdev_load_one(Manager *manager, const char *filename) { }; dropin_dirname = strjoina(basename(filename), ".d"); - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, - config_item_perf_lookup, network_netdev_gperf_lookup, - CONFIG_PARSE_WARN, netdev_raw, NULL); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, + config_item_perf_lookup, network_netdev_gperf_lookup, + CONFIG_PARSE_WARN, + netdev_raw, + NULL); if (r < 0) return r; @@ -726,10 +729,12 @@ int netdev_load_one(Manager *manager, const char *filename) { if (NETDEV_VTABLE(netdev)->init) NETDEV_VTABLE(netdev)->init(netdev); - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - NETDEV_VTABLE(netdev)->sections, - config_item_perf_lookup, network_netdev_gperf_lookup, - CONFIG_PARSE_WARN, netdev, NULL); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + NETDEV_VTABLE(netdev)->sections, + config_item_perf_lookup, network_netdev_gperf_lookup, + CONFIG_PARSE_WARN, + netdev, NULL); if (r < 0) return r; diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 350fea634c6..30625117e40 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -23,11 +23,15 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/networkd.conf", - CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "Network\0DHCP\0", - config_item_perf_lookup, networkd_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "Network\0" + "DHCP\0", + config_item_perf_lookup, networkd_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index b928f7585c3..50e50fd945b 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -335,7 +335,6 @@ int network_verify(Network *network) { int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) { _cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_(network_unrefp) Network *network = NULL; - _cleanup_strv_free_ char **dropins = NULL; _cleanup_fclose_ FILE *file = NULL; const char *dropin_dirname; char *d; @@ -477,54 +476,57 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ip_service_type = -1, }; - r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname, - "Match\0" - "Link\0" - "Network\0" - "Address\0" - "Neighbor\0" - "IPv6AddressLabel\0" - "RoutingPolicyRule\0" - "Route\0" - "NextHop\0" - "DHCP\0" /* compat */ - "DHCPv4\0" - "DHCPv6\0" - "DHCPServer\0" - "IPv6AcceptRA\0" - "IPv6NDPProxyAddress\0" - "Bridge\0" - "BridgeFDB\0" - "BridgeVLAN\0" - "IPv6PrefixDelegation\0" - "IPv6Prefix\0" - "IPv6RoutePrefix\0" - "LLDP\0" - "TrafficControlQueueingDiscipline\0" - "CAN\0" - "QDisc\0" - "BFIFO\0" - "CAKE\0" - "ControlledDelay\0" - "DeficitRoundRobinScheduler\0" - "DeficitRoundRobinSchedulerClass\0" - "PFIFO\0" - "PFIFOFast\0" - "PFIFOHeadDrop\0" - "FairQueueing\0" - "FairQueueingControlledDelay\0" - "GenericRandomEarlyDetection\0" - "HeavyHitterFilter\0" - "HierarchyTokenBucket\0" - "HierarchyTokenBucketClass\0" - "NetworkEmulator\0" - "PIE\0" - "StochasticFairBlue\0" - "StochasticFairnessQueueing\0" - "TokenBucketFilter\0" - "TrivialLinkEqualizer\0", - config_item_perf_lookup, network_network_gperf_lookup, - CONFIG_PARSE_WARN, network, &dropins); + r = config_parse_many( + filename, NETWORK_DIRS, dropin_dirname, + "Match\0" + "Link\0" + "Network\0" + "Address\0" + "Neighbor\0" + "IPv6AddressLabel\0" + "RoutingPolicyRule\0" + "Route\0" + "NextHop\0" + "DHCP\0" /* compat */ + "DHCPv4\0" + "DHCPv6\0" + "DHCPServer\0" + "IPv6AcceptRA\0" + "IPv6NDPProxyAddress\0" + "Bridge\0" + "BridgeFDB\0" + "BridgeVLAN\0" + "IPv6PrefixDelegation\0" + "IPv6Prefix\0" + "IPv6RoutePrefix\0" + "LLDP\0" + "TrafficControlQueueingDiscipline\0" + "CAN\0" + "QDisc\0" + "BFIFO\0" + "CAKE\0" + "ControlledDelay\0" + "DeficitRoundRobinScheduler\0" + "DeficitRoundRobinSchedulerClass\0" + "PFIFO\0" + "PFIFOFast\0" + "PFIFOHeadDrop\0" + "FairQueueing\0" + "FairQueueingControlledDelay\0" + "GenericRandomEarlyDetection\0" + "HeavyHitterFilter\0" + "HierarchyTokenBucket\0" + "HierarchyTokenBucketClass\0" + "NetworkEmulator\0" + "PIE\0" + "StochasticFairBlue\0" + "StochasticFairnessQueueing\0" + "TokenBucketFilter\0" + "TrivialLinkEqualizer\0", + config_item_perf_lookup, network_network_gperf_lookup, + CONFIG_PARSE_WARN, + network, + &network->timestamp); if (r < 0) return r; @@ -539,24 +541,6 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m", network->filename); - struct stat stats; - if (stat(filename, &stats) >= 0) - network->timestamp = timespec_load(&stats.st_mtim); - - char **f; - STRV_FOREACH(f, dropins) { - usec_t t; - - if (stat(*f, &stats) < 0) { - network->timestamp = 0; - break; - } - - t = timespec_load(&stats.st_mtim); - if (t > network->timestamp) - network->timestamp = t; - } - if (network_verify(network) < 0) /* Ignore .network files that do not match the conditions. */ return 0; diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 4e1cb3835c6..996c0027c38 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -78,7 +78,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) { "Files\0", config_item_perf_lookup, nspawn_gperf_lookup, CONFIG_PARSE_WARN, - s); + s, NULL); if (r < 0) return r; diff --git a/src/partition/repart.c b/src/partition/repart.c index 16cb5e45c45..4c6e4595299 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -976,7 +976,12 @@ static int partition_read_definition(Partition *p, const char *path) { }; int r; - r = config_parse(NULL, path, NULL, "Partition\0", config_item_table_lookup, table, CONFIG_PARSE_WARN, p); + r = config_parse(NULL, path, NULL, + "Partition\0", + config_item_table_lookup, table, + CONFIG_PARSE_WARN, + p, + NULL); if (r < 0) return r; diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c index 5c812b5d5b4..59d0b5b74e8 100644 --- a/src/pstore/pstore.c +++ b/src/pstore/pstore.c @@ -78,11 +78,14 @@ static int parse_config(void) { {} }; - return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf", - CONF_PATHS_NULSTR("systemd/pstore.conf.d"), - "PStore\0", - config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + return config_parse_many_nulstr( + PKGSYSCONFDIR "/pstore.conf", + CONF_PATHS_NULSTR("systemd/pstore.conf.d"), + "PStore\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); } /* File list handling - PStoreEntry is the struct and diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index e915343c012..9a6b1e88e17 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -381,11 +381,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/resolved.conf", - CONF_PATHS_NULSTR("systemd/resolved.conf.d"), - "Resolve\0", - config_item_perf_lookup, resolved_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), + "Resolve\0", + config_item_perf_lookup, resolved_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index c331b2d94c9..4458ad1d2d4 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -86,10 +86,13 @@ static int dnssd_service_load(Manager *manager, const char *filename) { dropin_dirname = strjoina(service->name, ".dnssd.d"); - r = config_parse_many(filename, DNSSD_SERVICE_DIRS, dropin_dirname, - "Service\0", - config_item_perf_lookup, resolved_dnssd_gperf_lookup, - false, service, NULL); + r = config_parse_many( + filename, DNSSD_SERVICE_DIRS, dropin_dirname, + "Service\0", + config_item_perf_lookup, resolved_dnssd_gperf_lookup, + CONFIG_PARSE_WARN, + service, + NULL); if (r < 0) return r; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 2eda6ae03ac..21226573428 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -199,7 +199,7 @@ static int parse_line( if (!fn) return -ENOMEM; - return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata); + return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata, NULL); } if (!utf8_is_valid(l)) @@ -289,13 +289,15 @@ int config_parse(const char *unit, ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false, bom_seen = false; int r, fd; + usec_t mtime; assert(filename); assert(lookup); @@ -313,8 +315,16 @@ int config_parse(const char *unit, } fd = fileno(f); - if (fd >= 0) /* stream might not have an fd, let's be careful hence */ - fd_warn_permissions(filename, fd); + if (fd >= 0) { /* stream might not have an fd, let's be careful hence */ + struct stat st; + + if (fstat(fd, &st) < 0) + return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno, + "Failed to fstat(%s): %m", filename); + + (void) stat_warn_permissions(filename, &st); + mtime = timespec_load(&st.st_mtim); + } for (;;) { _cleanup_free_ char *buf = NULL; @@ -434,6 +444,9 @@ int config_parse(const char *unit, } } + if (ret_mtime) + *ret_mtime = mtime; + return 0; } @@ -444,23 +457,32 @@ static int config_parse_many_files( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { + usec_t mtime = 0; char **fn; int r; if (conf_file) { - r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata); + r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime); if (r < 0) return r; } STRV_FOREACH(fn, files) { - r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata); + usec_t t; + + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t); if (r < 0) return r; + if (t > mtime) /* Find the newest */ + mtime = t; } + if (ret_mtime) + *ret_mtime = mtime; + return 0; } @@ -472,7 +494,8 @@ int config_parse_many_nulstr( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) { + void *userdata, + usec_t *ret_mtime) { _cleanup_strv_free_ char **files = NULL; int r; @@ -481,7 +504,7 @@ int config_parse_many_nulstr( if (r < 0) return r; - return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); } /* Parse each config file in the directories specified as strv. */ @@ -494,7 +517,7 @@ int config_parse_many( const void *table, ConfigParseFlags flags, void *userdata, - char ***ret_dropins) { + usec_t *ret_mtime) { _cleanup_strv_free_ char **dropin_dirs = NULL; _cleanup_strv_free_ char **files = NULL; @@ -510,14 +533,7 @@ int config_parse_many( if (r < 0) return r; - r = config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); - if (r < 0) - return r; - - if (ret_dropins) - *ret_dropins = TAKE_PTR(files); - - return 0; + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); } #define DEFINE_PARSER(type, vartype, conv_func) \ diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 480988f392b..6c8c1092ea5 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -10,6 +10,7 @@ #include "alloc-util.h" #include "log.h" #include "macro.h" +#include "time-util.h" /* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */ @@ -84,11 +85,12 @@ int config_parse( const char *unit, const char *filename, FILE *f, - const char *sections, /* nulstr */ + const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata); + void *userdata, + usec_t *ret_mtime); /* possibly NULL */ int config_parse_many_nulstr( const char *conf_file, /* possibly NULL */ @@ -97,7 +99,8 @@ int config_parse_many_nulstr( ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata); + void *userdata, + usec_t *ret_mtime); /* possibly NULL */ int config_parse_many( const char *conf_file, /* possibly NULL */ @@ -108,7 +111,7 @@ int config_parse_many( const void *table, ConfigParseFlags flags, void *userdata, - char ***ret_dropins); /* possibly NULL */ + usec_t *ret_mtime); /* possibly NULL */ CONFIG_PARSER_PROTOTYPE(config_parse_int); CONFIG_PARSER_PROTOTYPE(config_parse_unsigned); diff --git a/src/shared/install.c b/src/shared/install.c index 60005967e79..5dd5d2aa9ae 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1304,7 +1304,8 @@ static int unit_file_load( "-Target\0" "-Timer\0", config_item_table_lookup, items, - CONFIG_PARSE_ALLOW_INCLUDE, info); + CONFIG_PARSE_ALLOW_INCLUDE, info, + NULL); if (r < 0) return log_debug_errno(r, "Failed to parse %s: %m", info->name); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 5cee1ce1aa8..81862c776d6 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -59,10 +59,14 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) { {} }; - (void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf", - CONF_PATHS_NULSTR("systemd/sleep.conf.d"), - "Sleep\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + (void) config_parse_many_nulstr( + PKGSYSCONFDIR "/sleep.conf", + CONF_PATHS_NULSTR("systemd/sleep.conf.d"), + "Sleep\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + NULL, + NULL); /* use default values unless set */ sc->allow_suspend = allow_suspend != 0; diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 510b1de72d1..07edc17f92e 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -335,13 +335,17 @@ static void test_config_parse(unsigned i, const char *s) { ConfigItemLookup lookup, const void *table, ConfigParseFlags flags, - void *userdata) + void *userdata, + usec_t *ret_mtime) */ r = config_parse(NULL, name, f, - "Section\0-NoWarnSection\0", + "Section\0" + "-NoWarnSection\0", config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + CONFIG_PARSE_WARN, + NULL, + NULL); switch (i) { case 0 ... 4: diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index a26c2dad7fb..532d6ea7ec0 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -102,11 +102,14 @@ int manager_parse_config_file(Manager *m) { assert(m); - r = config_parse_many_nulstr(PKGSYSCONFDIR "/timesyncd.conf", - CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), - "Time\0", - config_item_perf_lookup, timesyncd_gperf_lookup, - CONFIG_PARSE_WARN, m); + r = config_parse_many_nulstr( + PKGSYSCONFDIR "/timesyncd.conf", + CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), + "Time\0", + config_item_perf_lookup, timesyncd_gperf_lookup, + CONFIG_PARSE_WARN, + m, + NULL); if (r < 0) return r; diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 0e33c0b48f0..eb847191113 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -192,7 +192,9 @@ static int process_one_password_file(const char *filename) { r = config_parse(NULL, filename, NULL, NULL, config_item_table_lookup, items, - CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL); + CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, + NULL, + NULL); if (r < 0) return r; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 806f4574581..abe1276dfa1 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -161,7 +161,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename) { r = config_parse(NULL, filename, file, "Match\0Link\0", config_item_perf_lookup, link_config_gperf_lookup, - CONFIG_PARSE_WARN, link); + CONFIG_PARSE_WARN, link, + NULL); if (r < 0) return r; diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c index c99b6cc8839..6d10d7052b5 100644 --- a/src/xdg-autostart-generator/xdg-autostart-service.c +++ b/src/xdg-autostart-generator/xdg-autostart-service.c @@ -319,7 +319,8 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) { r = config_parse(NULL, service->path, NULL, "Desktop Entry\0", xdg_config_item_table_lookup, items, - CONFIG_PARSE_WARN, service); + CONFIG_PARSE_WARN, service, + NULL); /* If parsing failed, only hide the file so it will still mask others. */ if (r < 0) { log_warning_errno(r, "Failed to parse %s, ignoring it", service->path); -- 2.47.3