From: Lennart Poettering Date: Mon, 8 Dec 2025 12:30:41 +0000 (+0100) Subject: fd-util: wire up XAT_FDROOT in various really basic fd-util.h calls X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5667cbcacff3c415e16079ff29e4bada4a6882ea;p=thirdparty%2Fsystemd.git fd-util: wire up XAT_FDROOT in various really basic fd-util.h calls --- diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index e08ad7d3242..f80ce0ae470 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -572,10 +572,12 @@ bool fdname_is_valid(const char *s) { int fd_get_path(int fd, char **ret) { int r; - assert(fd >= 0 || fd == AT_FDCWD); + assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT)); if (fd == AT_FDCWD) return safe_getcwd(ret); + if (fd == XAT_FDROOT) + return strdup_to(ret, "/"); r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret); if (r == -ENOENT) @@ -770,7 +772,7 @@ finish: } int fd_reopen(int fd, int flags) { - assert(fd >= 0 || fd == AT_FDCWD); + assert(fd >= 0 || IN_SET(fd, AT_FDCWD, XAT_FDROOT)); assert(!FLAGS_SET(flags, O_CREAT)); /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to @@ -782,6 +784,8 @@ int fd_reopen(int fd, int flags) { * * If AT_FDCWD is specified as file descriptor gets an fd to the current cwd. * + * If XAT_FDROOT is specified as fd get an fd to the root directory. + * * If the specified file descriptor refers to a symlink via O_PATH, then this function cannot be used * to follow that symlink. Because we cannot have non-O_PATH fds to symlinks reopening it without * O_PATH will always result in -ELOOP. Or in other words: if you have an O_PATH fd to a symlink you @@ -795,6 +799,9 @@ int fd_reopen(int fd, int flags) { * the same way as the non-O_DIRECTORY case. */ return -ELOOP; + if (fd == XAT_FDROOT) + return RET_NERRNO(open("/", flags | O_DIRECTORY)); + if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD) /* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole * magic /proc/ directory, and make ourselves independent of that being mounted. */ @@ -1025,19 +1032,36 @@ int fd_get_diskseq(int fd, uint64_t *ret) { return 0; } +static bool is_literal_root(const char *p) { + if (!p) + return false; + + /* Check if string consists of at least one '/', and possibly more, but nothing else */ + size_t n = strspn(p, "/"); + return n >= 1 && p[n] == 0; +} + int path_is_root_at(int dir_fd, const char *path) { - assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT)); + + if (dir_fd == XAT_FDROOT && isempty(path)) + return true; + + if (IN_SET(dir_fd, XAT_FDROOT, AT_FDCWD) && is_literal_root(path)) + return true; _cleanup_close_ int fd = -EBADF; if (!isempty(path)) { - fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC); + fd = xopenat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC); + if (fd == -ENOTDIR) + return false; /* the root dir must be a dir */ if (fd < 0) - return errno == ENOTDIR ? false : -errno; + return fd; dir_fd = fd; } - _cleanup_close_ int root_fd = openat(AT_FDCWD, "/", O_PATH|O_DIRECTORY|O_CLOEXEC); + _cleanup_close_ int root_fd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); if (root_fd < 0) return -errno; @@ -1055,13 +1079,27 @@ int path_is_root_at(int dir_fd, const char *path) { int fds_are_same_mount(int fd1, int fd2) { struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */ - assert(fd1 >= 0); - assert(fd2 >= 0); + assert(fd1 >= 0 || IN_SET(fd1, AT_FDCWD, XAT_FDROOT)); + assert(fd2 >= 0 || IN_SET(fd2, AT_FDCWD, XAT_FDROOT)); + + const char *fn1; + if (fd1 == XAT_FDROOT) { + fd1 = AT_FDCWD; + fn1 = "/"; + } else + fn1 = ""; - if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0) + if (statx(fd1, fn1, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0) return -errno; - if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0) + const char *fn2; + if (fd2 == XAT_FDROOT) { + fd2 = AT_FDCWD; + fn2 = "/"; + } else + fn2 = ""; + + if (statx(fd2, fn2, AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0) return -errno; return statx_inode_same(&sx1, &sx2) && statx_mount_same(&sx1, &sx2); diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 2663ff8aac3..707445d73d8 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -173,10 +173,10 @@ static inline int path_is_root(const char *path) { return path_is_root_at(AT_FDCWD, path); } static inline int dir_fd_is_root(int dir_fd) { - return path_is_root_at(dir_fd, NULL); + return dir_fd == XAT_FDROOT ? true : path_is_root_at(dir_fd, NULL); } static inline int dir_fd_is_root_or_cwd(int dir_fd) { - return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL); + return IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT) ? true : path_is_root_at(dir_fd, NULL); } int fds_are_same_mount(int fd1, int fd2);