fd-util: wire up XAT_FDROOT in various really basic fd-util.h calls

This commit is contained in:
Lennart Poettering
2025-12-08 13:30:41 +01:00
parent ef582ab201
commit 5667cbcacf
2 changed files with 50 additions and 12 deletions

View File

@@ -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));
if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0)
const char *fn1;
if (fd1 == XAT_FDROOT) {
fd1 = AT_FDCWD;
fn1 = "/";
} else
fn1 = "";
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);

View File

@@ -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);