diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 7bbcb6051e..943bc56319 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -353,26 +353,36 @@ int fchmod_opath(int fd, mode_t m) { return 0; } +int stat_warn_permissions(const char *path, const struct stat *st) { + assert(path); + assert(st); + + /* Don't complain if we are reading something that is not a file, for example /dev/null */ + if (!S_ISREG(st->st_mode)) + return 0; + + if (st->st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st->st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid_cached() == 1 && (st->st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + int fd_warn_permissions(const char *path, int fd) { struct stat st; + assert(path); + assert(fd >= 0); + if (fstat(fd, &st) < 0) return -errno; - /* Don't complain if we are reading something that is not a file, for example /dev/null */ - if (!S_ISREG(st.st_mode)) - return 0; - - if (st.st_mode & 0111) - log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); - - if (st.st_mode & 0002) - log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); - - if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044) - log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); - - return 0; + return stat_warn_permissions(path, &st); } int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index dd101c61cc..b184570f9f 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -40,6 +40,7 @@ int fchmod_umask(int fd, mode_t mode); int fchmod_opath(int fd, mode_t m); int fd_warn_permissions(const char *path, int fd); +int stat_warn_permissions(const char *path, const struct stat *st); #define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index f61e9da6f2..0da3eafb12 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 a24c7877f9..49fdcaff7e 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 32b963d4a4..e1de821e66 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 42231dbd6b..d156d98efc 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 d3993cf123..34f59a4437 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 14ec8b336d..df3a17358b 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 551b84130d..948b2d2fce 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 bf656ac670..bd58fdbcdf 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 9efa65a294..5865bf9809 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 1375f438e4..4289461df6 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 a990c64b55..1889f6f13c 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 350fea634c..30625117e4 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 b928f7585c..50e50fd945 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 4e1cb3835c..996c0027c3 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 16cb5e45c4..4c6e459529 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 5c812b5d5b..59d0b5b74e 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 e915343c01..9a6b1e88e1 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 c331b2d94c..4458ad1d2d 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 b04eb3912c..2122657342 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; @@ -331,7 +341,7 @@ int config_parse(const char *unit, return r; } if (r < 0) { - if (CONFIG_PARSE_WARN) + if (FLAGS_SET(flags, CONFIG_PARSE_WARN)) log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); return r; @@ -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 480988f392..6c8c1092ea 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 60005967e7..5dd5d2aa9a 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 5cee1ce1aa..81862c776d 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 510b1de72d..07edc17f92 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 a26c2dad7f..532d6ea7ec 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 0e33c0b48f..eb84719111 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 806f457458..abe1276dfa 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 c99b6cc883..6d10d7052b 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);