From 05768ae36b4af0c18b4837fa6041fd66a05f5e36 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Aug 2022 11:55:14 +0200 Subject: [PATCH] shutdown: rework log_umount_blockers() a bit Let's go directly from opening /proc/ to opening /proc/$PID/fd/ instead of indirectly via opening /proc/$PID/ first. Saves a syscall. Also, add error logging about all unexpected errors. Finally, drop redundant denylist for /proc/, /sys/, /dev/ prefix checking, should be redundant, given the ealier check against the 'mnt' prefix. --- src/shutdown/umount.c | 60 ++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 7ddeb67e977fe..e650b821700df 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -529,11 +529,12 @@ static bool nonunmountable_path(const char *path) { } static void log_umount_blockers(const char *mnt) { + _cleanup_free_ char *blockers = NULL; + int r; + _cleanup_closedir_ DIR *dir = opendir("/proc"); if (!dir) - return (void) log_warning_errno(errno, "opendir(/proc) failed: %m"); - - _cleanup_free_ char *blockers = NULL; + return (void) log_warning_errno(errno, "Failed to open /proc/: %m"); FOREACH_DIRENT_ALL(de, dir, break) { if (!IN_SET(de->d_type, DT_DIR, DT_UNKNOWN)) @@ -543,37 +544,50 @@ static void log_umount_blockers(const char *mnt) { if (parse_pid(de->d_name, &pid) < 0) continue; - _cleanup_closedir_ DIR *pid_dir = xopendirat(dirfd(dir), de->d_name, 0); - if (!pid_dir) - continue; + _cleanup_free_ char *fdp = path_join(de->d_name, "fd"); + if (!fdp) + return (void) log_oom(); - _cleanup_closedir_ DIR *fd_dir = xopendirat(dirfd(pid_dir), "fd", 0); - if (!fd_dir) + _cleanup_closedir_ DIR *fd_dir = xopendirat(dirfd(dir), fdp, 0); + if (!fd_dir) { + if (errno != ENOENT) /* process gone by now? */ + log_debug_errno(errno, "Failed to open /proc/%s/, ignoring: %m",fdp); continue; + } + bool culprit = false; FOREACH_DIRENT(fd_de, fd_dir, break) { - _cleanup_free_ char *open_file = NULL, *comm = NULL; - - if (readlinkat_malloc(dirfd(fd_dir), fd_de->d_name, &open_file) < 0) - continue; + _cleanup_free_ char *open_file = NULL; - if (!path_startswith(open_file, mnt)) + r = readlinkat_malloc(dirfd(fd_dir), fd_de->d_name, &open_file); + if (r < 0) { + if (r != -ENOENT) /* fd closed by now */ + log_debug_errno(r, "Failed to read link /proc/%s/%s, ignoring: %m", fdp, fd_de->d_name); continue; + } - if (PATH_STARTSWITH_SET(open_file, "/dev", "/sys", "/proc")) - continue; + if (path_startswith(open_file, mnt)) { + culprit = true; + break; + } + } - if (get_process_comm(pid, &comm) < 0) - continue; + if (!culprit) + continue; - if (!strextend_with_separator(&blockers, ", ", comm)) - return (void) log_oom(); + _cleanup_free_ char *comm = NULL; + r = get_process_comm(pid, &comm); + if (r < 0) { + if (r != -ESRCH) /* process gone by now */ + log_debug_errno(r, "Failed to read process name of PID " PID_FMT ": %m", pid); + continue; + } - if (!strextend(&blockers, "(", de->d_name, ")")) - return (void) log_oom(); + if (!strextend_with_separator(&blockers, ", ", comm)) + return (void) log_oom(); - break; - } + if (!strextend(&blockers, "(", de->d_name, ")")) + return (void) log_oom(); } if (blockers)