From: Yu Watanabe Date: Wed, 13 Jul 2022 12:58:15 +0000 (+0900) Subject: udev: save stats of all udev rules file X-Git-Tag: v252-rc1~589^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=acfbd71ccc3c316c335accfb872937cbf9d3dde3;p=thirdparty%2Fsystemd.git udev: save stats of all udev rules file The mtime of directory is not updated when an existing rule file is changed. Hence, paths_check_timestamp() is not reliable. --- diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 9a888eec219..765ccec5016 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -445,7 +445,7 @@ int config_parse( return 1; } -static int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st) { +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; diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 15616adf3b5..bd57575af12 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -122,6 +122,7 @@ int config_get_stats_by_path( bool check_dropins, Hashmap **ret); +int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const struct stat *st); bool stats_by_path_equal(Hashmap *a, Hashmap *b); typedef struct ConfigSection { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index b977338c385..eaa3578489b 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "architecture.h" #include "conf-files.h" +#include "conf-parser.h" #include "def.h" #include "device-private.h" #include "device-util.h" @@ -177,10 +178,10 @@ struct UdevRuleFile { }; struct UdevRules { - usec_t dirs_ts_usec; ResolveNameTiming resolve_name_timing; Hashmap *known_users; Hashmap *known_groups; + Hashmap *stats_by_path; UdevRuleFile *current_file; LIST_HEAD(UdevRuleFile, rule_files); }; @@ -315,6 +316,7 @@ UdevRules *udev_rules_free(UdevRules *rules) { hashmap_free_free_key(rules->known_users); hashmap_free_free_key(rules->known_groups); + hashmap_free(rules->stats_by_path); return mfree(rules); } @@ -1176,6 +1178,7 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { UdevRuleFile *rule_file; bool ignore_line = false; unsigned line_nr = 0; + struct stat st; int r; f = fopen(filename, "re"); @@ -1183,16 +1186,23 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { if (errno == ENOENT) return 0; - return -errno; + return log_warning_errno(errno, "Failed to open %s, ignoring: %m", filename); } - (void) fd_warn_permissions(filename, fileno(f)); + if (fstat(fileno(f), &st) < 0) + return log_warning_errno(errno, "Failed to stat %s, ignoring: %m", filename); - if (null_or_empty_fd(fileno(f))) { + if (null_or_empty(&st)) { log_debug("Skipping empty file: %s", filename); return 0; } + r = hashmap_put_stats_by_path(&rules->stats_by_path, filename, &st); + if (r < 0) + return log_warning_errno(errno, "Failed to save stat for %s, ignoring: %m", filename); + + (void) fd_warn_permissions(filename, fileno(f)); + log_debug("Reading rules file: %s", filename); name = strdup(filename); @@ -1296,8 +1306,6 @@ int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing if (!rules) return -ENOMEM; - (void) udev_rules_check_timestamp(rules); - r = conf_files_list_strv(&files, ".rules", NULL, 0, RULES_DIRS); if (r < 0) return log_debug_errno(r, "Failed to enumerate rules files: %m"); @@ -1312,11 +1320,25 @@ int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing return 0; } -bool udev_rules_check_timestamp(UdevRules *rules) { +bool udev_rules_should_reload(UdevRules *rules) { + _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL; + int r; + if (!rules) - return false; + return true; + + r = config_get_stats_by_path(".rules", NULL, 0, RULES_DIRS, /* check_dropins = */ false, &stats_by_path); + if (r < 0) { + log_warning_errno(r, "Failed to get stats of udev rules, ignoring: %m"); + return true; + } + + if (!stats_by_path_equal(rules->stats_by_path, stats_by_path)) { + log_debug("Udev rules need reloading"); + return true; + } - return paths_check_timestamp(RULES_DIRS, &rules->dirs_ts_usec, true); + return false; } static bool token_match_string(UdevRuleToken *token, const char *str) { diff --git a/src/udev/udev-rules.h b/src/udev/udev-rules.h index d11297da857..704f690b676 100644 --- a/src/udev/udev-rules.h +++ b/src/udev/udev-rules.h @@ -22,7 +22,7 @@ int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing UdevRules *udev_rules_free(UdevRules *rules); DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free); -bool udev_rules_check_timestamp(UdevRules *rules); +bool udev_rules_should_reload(UdevRules *rules); int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event, usec_t timeout_usec, int timeout_signal, diff --git a/src/udev/udevd.c b/src/udev/udevd.c index d154cf4b73f..a457ebcc9a3 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -949,7 +949,7 @@ static int event_queue_start(Manager *manager) { /* check for changed config, every 3 seconds at most */ if (manager->last_usec == 0 || usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) { - if (udev_rules_check_timestamp(manager->rules) || + if (udev_rules_should_reload(manager->rules) || udev_builtin_validate()) manager_reload(manager);