From: Yu Watanabe Date: Fri, 4 Apr 2025 13:42:24 +0000 (+0900) Subject: udev-watch: dump installed inotify watches on start and stop X-Git-Tag: v258-rc1~904^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=04ae22375adfb995b086be6ae0f57bd4260f221d;p=thirdparty%2Fsystemd.git udev-watch: dump installed inotify watches on start and stop --- diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index c05e475dd62..eddd07854d6 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -965,8 +965,10 @@ static int on_post(sd_event_source *s, void *userdata) { if (r < 0) log_warning_errno(r, "Failed to disable timer event source for cleaning up idle workers, ignoring: %m"); - if (manager->exit) + if (manager->exit) { + udev_watch_dump(); return sd_event_exit(manager->event, 0); + } if (manager->cgroup && set_isempty(manager->synthesize_change_child_event_sources)) /* cleanup possible left-over processes in our cgroup */ diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index a9b06f5eb8b..84a7f542b1f 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -46,6 +46,88 @@ static int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) { return sd_device_new_from_device_id(ret, id); } +void udev_watch_dump(void) { + int r; + + _cleanup_closedir_ DIR *dir = opendir("/run/udev/watch/"); + if (!dir) + return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, + "Failed to open old watches directory '/run/udev/watch/': %m"); + + _cleanup_set_free_ Set *pending_wds = NULL, *verified_wds = NULL; + FOREACH_DIRENT(de, dir, break) { + if (safe_atoi(de->d_name, NULL) >= 0) { + /* This should be wd -> ID symlink */ + + if (set_contains(verified_wds, de->d_name)) + continue; + + r = set_put_strdup(&pending_wds, de->d_name); + if (r < 0) + log_warning_errno(r, "Failed to store pending watch handle %s, ignoring: %m", de->d_name); + continue; + } + + _cleanup_free_ char *wd = NULL; + r = readlinkat_malloc(dirfd(dir), de->d_name, &wd); + if (r < 0) { + log_warning_errno(r, "Found broken inotify watch, failed to read symlink %s, ignoring: %m", de->d_name); + continue; + } + + const char *devnode = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + if (sd_device_new_from_device_id(&dev, de->d_name) >= 0) + (void) sd_device_get_devname(dev, &devnode); + + _cleanup_free_ char *id = NULL; + r = readlinkat_malloc(dirfd(dir), wd, &id); + if (r < 0) { + log_warning_errno(r, "Found broken inotify watch %s on %s (%s), failed to read symlink %s, ignoring: %m", + wd, strna(devnode), de->d_name, wd); + continue; + } + + if (!streq(de->d_name, id)) { + log_warning("Found broken inotify watch %s on %s (%s), broken symlink chain: %s → %s → %s", + wd, strna(devnode), de->d_name, de->d_name, wd, id); + continue; + } + + log_debug("Found inotify watch %s on %s (%s).", wd, strna(devnode), de->d_name); + + free(set_remove(pending_wds, wd)); + + r = set_ensure_put(&verified_wds, &string_hash_ops_free, wd); + if (r < 0) { + log_warning_errno(r, "Failed to store verified watch handle %s, ignoring: %m", wd); + continue; + } + TAKE_PTR(wd); + } + + const char *w; + SET_FOREACH(w, pending_wds) { + _cleanup_free_ char *id = NULL; + r = readlinkat_malloc(dirfd(dir), w, &id); + if (r < 0) { + log_warning_errno(r, "Found broken inotify watch %s, failed to read symlink %s, ignoring: %m", w, w); + continue; + } + + const char *devnode = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + if (sd_device_new_from_device_id(&dev, id) >= 0) + (void) sd_device_get_devname(dev, &devnode); + + _cleanup_free_ char *wd = NULL; + (void) readlinkat_malloc(dirfd(dir), id, &wd); + + log_warning("Found broken inotify watch %s on %s (%s), broken symlink chain: %s → %s → %s", + wd, strna(devnode), id, w, id, wd); + } +} + static int synthesize_change_one(sd_device *dev, sd_device *target) { int r; @@ -290,6 +372,8 @@ int manager_start_inotify(Manager *manager) { if (r < 0) return r; + udev_watch_dump(); + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; r = sd_event_add_io(manager->event, &s, manager->inotify_fd, EPOLLIN, on_inotify, manager); if (r < 0) diff --git a/src/udev/udev-watch.h b/src/udev/udev-watch.h index 8365334e712..fed5f9614c7 100644 --- a/src/udev/udev-watch.h +++ b/src/udev/udev-watch.h @@ -5,6 +5,8 @@ typedef struct Manager Manager; +void udev_watch_dump(void); + int manager_init_inotify(Manager *manager, int fd); int manager_start_inotify(Manager *manager);