config_item_perf_lookup, network_network_gperf_lookup,
CONFIG_PARSE_WARN,
network,
- &network->timestamp);
+ &network->stats_by_path);
if (r < 0)
return r;
return 0;
}
+static bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
+ struct stat *st_a, *st_b;
+ const char *path;
+
+ assert(a);
+ assert(b);
+
+ if (hashmap_size(a) != hashmap_size(b))
+ return false;
+
+ HASHMAP_FOREACH_KEY(st_a, path, a) {
+ st_b = hashmap_get(b, path);
+ if (!st_b)
+ return false;
+
+ if (!stat_inode_unmodified(st_a, st_b))
+ return false;
+ }
+
+ return true;
+}
+
int network_reload(Manager *manager) {
OrderedHashmap *new_networks = NULL;
Network *n, *old;
ORDERED_HASHMAP_FOREACH(n, new_networks) {
r = network_get_by_name(manager, n->name, &old);
- if (r < 0)
- continue; /* The .network file is new. */
-
- if (n->timestamp != old->timestamp)
- continue; /* The .network file is modified. */
+ if (r < 0) {
+ log_debug("Found new .network file: %s", n->filename);
+ continue;
+ }
- if (!streq(n->filename, old->filename))
+ if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
+ log_debug("Found updated .network file: %s", n->filename);
continue;
+ }
r = ordered_hashmap_replace(new_networks, old->name, old);
if (r < 0)
return NULL;
free(network->filename);
+ hashmap_free(network->stats_by_path);
net_match_clear(&network->match);
condition_free_list(network->conditions);
const void *table,
ConfigParseFlags flags,
void *userdata,
- usec_t *latest_mtime) {
+ struct stat *ret_stat) {
_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;
+ struct stat st;
int r, fd;
- usec_t mtime;
assert(filename);
assert(lookup);
- /* latest_mtime is an input-output parameter: it will be updated if the mtime of the file we're
- * looking at is later than the current *latest_mtime value. */
-
if (!f) {
f = ours = fopen(filename, "re");
if (!f) {
if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
"Failed to open configuration file '%s': %m", filename);
- return errno == ENOENT ? 0 : -errno;
+
+ if (errno == ENOENT) {
+ if (ret_stat)
+ *ret_stat = (struct stat) {};
+
+ return 0;
+ }
+
+ return -errno;
}
}
fd = fileno(f);
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);
} else
- mtime = 0;
+ st = (struct stat) {};
for (;;) {
_cleanup_free_ char *buf = NULL;
}
}
- if (latest_mtime)
- *latest_mtime = MAX(*latest_mtime, mtime);
+ if (ret_stat)
+ *ret_stat = st;
return 1;
}
+static int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) {
+ _cleanup_free_ struct stat *st_copy = NULL;
+ _cleanup_free_ char *path_copy = NULL;
+ int r;
+
+ assert(stats_by_path);
+ assert(path);
+ assert(st);
+
+ r = hashmap_ensure_allocated(stats_by_path, &path_hash_ops_free_free);
+ if (r < 0)
+ return r;
+
+ st_copy = newdup(struct stat, st, 1);
+ if (!st_copy)
+ return -ENOMEM;
+
+ path_copy = strdup(path);
+ if (!path)
+ return -ENOMEM;
+
+ r = hashmap_put(*stats_by_path, path_copy, st_copy);
+ if (r < 0)
+ return r;
+
+ assert(r > 0);
+ TAKE_PTR(path_copy);
+ TAKE_PTR(st_copy);
+ return 0;
+}
+
static int config_parse_many_files(
const char* const* conf_files,
char **files,
const void *table,
ConfigParseFlags flags,
void *userdata,
- usec_t *ret_mtime) {
+ Hashmap **ret_stats_by_path) {
- usec_t mtime = 0;
+ _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
+ struct stat st;
char **fn;
int r;
+ if (ret_stats_by_path) {
+ stats_by_path = hashmap_new(&path_hash_ops_free_free);
+ if (!stats_by_path)
+ return -ENOMEM;
+ }
+
/* First read the first found main config file. */
STRV_FOREACH(fn, (char**) conf_files) {
- r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime);
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
if (r < 0)
return r;
- if (r > 0)
- break;
+ if (r == 0)
+ continue;
+
+ if (ret_stats_by_path) {
+ r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
+ if (r < 0)
+ return r;
+ }
+
+ break;
}
/* Then read all the drop-ins. */
STRV_FOREACH(fn, files) {
- r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime);
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &st);
if (r < 0)
return r;
+ if (r == 0)
+ continue;
+
+ if (ret_stats_by_path) {
+ r = hashmap_put_stats_by_path(&stats_by_path, *fn, &st);
+ if (r < 0)
+ return r;
+ }
}
- if (ret_mtime)
- *ret_mtime = mtime;
+ if (ret_stats_by_path)
+ *ret_stats_by_path = TAKE_PTR(stats_by_path);
return 0;
}
const void *table,
ConfigParseFlags flags,
void *userdata,
- usec_t *ret_mtime) {
+ Hashmap **ret_stats_by_path) {
_cleanup_strv_free_ char **files = NULL;
int r;
return config_parse_many_files(STRV_MAKE_CONST(conf_file),
files, sections, lookup, table, flags, userdata,
- ret_mtime);
+ ret_stats_by_path);
}
/* Parse each config file in the directories specified as strv. */
const void *table,
ConfigParseFlags flags,
void *userdata,
- usec_t *ret_mtime) {
+ Hashmap **ret_stats_by_path) {
_cleanup_strv_free_ char **dropin_dirs = NULL;
_cleanup_strv_free_ char **files = NULL;
if (r < 0)
return r;
- return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_mtime);
+ return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
}
#define DEFINE_PARSER(type, vartype, conv_func) \