Merge pull request #32933 from YHNdnzj/faccessat-empty-path

fs-util: several cleanups
This commit is contained in:
Yu Watanabe
2024-06-12 18:35:13 +09:00
committed by GitHub
6 changed files with 69 additions and 55 deletions
+18 -19
View File
@@ -617,16 +617,8 @@ int fd_get_path(int fd, char **ret) {
return safe_getcwd(ret);
r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
if (r == -ENOENT) {
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
* things debuggable and distinguish the two. */
if (proc_mounted() == 0)
return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot
* environment. */
return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
}
if (r == -ENOENT)
return proc_fd_enoent_errno();
return r;
}
@@ -823,8 +815,6 @@ finish:
}
int fd_reopen(int fd, int flags) {
int r;
assert(fd >= 0 || fd == AT_FDCWD);
assert(!FLAGS_SET(flags, O_CREAT));
@@ -860,13 +850,7 @@ int fd_reopen(int fd, int flags) {
if (errno != ENOENT)
return -errno;
r = proc_mounted();
if (r == 0)
return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
* not valid, otherwise let's propagate the original
* error */
return proc_fd_enoent_errno();
}
return new_fd;
@@ -1136,3 +1120,18 @@ char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid,
assert_se(snprintf_ok(buf, PROC_PID_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", pid == 0 ? getpid_cached() : pid, fd));
return buf;
}
int proc_fd_enoent_errno(void) {
int r;
/* When ENOENT is returned during the use of FORMAT_PROC_FD_PATH, it can mean two things:
* that the fd does not exist or that /proc/ is not mounted.
* Let's make things debuggable and figure out the most appropriate errno. */
r = proc_mounted();
if (r == 0)
return -ENOSYS; /* /proc/ is not available or not set up properly, we're most likely
in some chroot environment. */
return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
not valid, otherwise let's propagate the original ENOENT. */
}
+2
View File
@@ -161,6 +161,8 @@ char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid,
#define FORMAT_PROC_PID_FD_PATH(pid, fd) \
format_proc_pid_fd_path((char[PROC_PID_FD_PATH_MAX]) {}, (pid), (fd))
int proc_fd_enoent_errno(void);
const char *accmode_to_string(int flags);
/* Like ASSERT_PTR, but for fds */
+28 -20
View File
@@ -313,10 +313,7 @@ int fchmod_opath(int fd, mode_t m) {
if (errno != ENOENT)
return -errno;
if (proc_mounted() == 0)
return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
return -ENOENT;
return proc_fd_enoent_errno();
}
return 0;
@@ -339,10 +336,7 @@ int futimens_opath(int fd, const struct timespec ts[2]) {
if (errno != ENOENT)
return -errno;
if (proc_mounted() == 0)
return -ENOSYS;
return -ENOENT;
return proc_fd_enoent_errno();
}
return 0;
@@ -633,17 +627,18 @@ static int tmp_dir_internal(const char *def, const char **ret) {
return 0;
}
k = is_dir(def, true);
k = is_dir(def, /* follow = */ true);
if (k == 0)
k = -ENOTDIR;
if (k < 0)
return r < 0 ? r : k;
return RET_GATHER(r, k);
*ret = def;
return 0;
}
int var_tmp_dir(const char **ret) {
assert(ret);
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
* even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
@@ -654,6 +649,7 @@ int var_tmp_dir(const char **ret) {
}
int tmp_dir(const char **ret) {
assert(ret);
/* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
* backed by an in-memory file system: /tmp. */
@@ -662,6 +658,8 @@ int tmp_dir(const char **ret) {
}
int unlink_or_warn(const char *filename) {
assert(filename);
if (unlink(filename) < 0 && errno != ENOENT)
/* If the file doesn't exist and the fs simply was read-only (in which
* case unlink() returns EROFS even if the file doesn't exist), don't
@@ -673,26 +671,31 @@ int unlink_or_warn(const char *filename) {
}
int access_fd(int fd, int mode) {
assert(fd >= 0);
/* Like access() but operates on an already open fd */
if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0)
return 0;
if (errno != EINVAL)
return -errno;
/* Support for AT_EMPTY_PATH is added rather late (kernel 5.8), so fall back to going through /proc/
* if unavailable. */
if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
if (errno != ENOENT)
return -errno;
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's
* make things debuggable and distinguish the two. */
if (proc_mounted() == 0)
return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot
* environment. */
return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
return proc_fd_enoent_errno();
}
return 0;
}
void unlink_tempfilep(char (*p)[]) {
assert(p);
/* If the file is created with mkstemp(), it will (almost always)
* change the suffix. Treat this as a sign that the file was
* successfully created. We ignore both the rare case where the
@@ -706,6 +709,8 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
struct stat st;
off_t l, bs;
assert(fd >= 0 || fd == AT_FDCWD);
assert(name);
assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
/* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
@@ -1245,7 +1250,7 @@ int xopenat_lock_full(
}
int link_fd(int fd, int newdirfd, const char *newpath) {
int r;
int r, k;
assert(fd >= 0);
assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
@@ -1258,8 +1263,11 @@ int link_fd(int fd, int newdirfd, const char *newpath) {
/* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
* more recent kernel, but does not require /proc/ mounted) */
if (proc_mounted() != 0)
k = proc_mounted();
if (k < 0)
return r;
if (k > 0)
return -EBADF;
return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
}
+5 -9
View File
@@ -42,7 +42,10 @@ bool inotify_event_next(
}
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
int wd, r;
int wd;
assert(fd >= 0);
assert(what >= 0);
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
@@ -50,14 +53,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
if (errno != ENOENT)
return -errno;
/* Didn't work with ENOENT? If so, then either /proc/ isn't mounted, or the fd is bad */
r = proc_mounted();
if (r == 0)
return -ENOSYS;
if (r > 0)
return -EBADF;
return -ENOENT; /* OK, no clue, let's propagate the original error */
return proc_fd_enoent_errno();
}
return wd;
+10 -5
View File
@@ -596,11 +596,14 @@ int dev_is_devtmpfs(void) {
return false;
}
int mount_fd(const char *source,
int target_fd,
const char *filesystemtype,
unsigned long mountflags,
const void *data) {
static int mount_fd(
const char *source,
int target_fd,
const char *filesystemtype,
unsigned long mountflags,
const void *data) {
assert(target_fd >= 0);
if (mount(source, FORMAT_PROC_FD_PATH(target_fd), filesystemtype, mountflags, data) < 0) {
if (errno != ENOENT)
@@ -626,6 +629,8 @@ int mount_nofollow(
_cleanup_close_ int fd = -EBADF;
assert(target);
/* In almost all cases we want to manipulate the mount table without following symlinks, hence
* mount_nofollow() is usually the way to go. The only exceptions are environments where /proc/ is
* not available yet, since we need /proc/self/fd/ for this logic to work. i.e. during the early
+6 -2
View File
@@ -63,8 +63,12 @@ const char* fstype_norecovery_option(const char *fstype);
int dev_is_devtmpfs(void);
int mount_fd(const char *source, int target_fd, const char *filesystemtype, unsigned long mountflags, const void *data);
int mount_nofollow(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
int mount_nofollow(
const char *source,
const char *target,
const char *filesystemtype,
unsigned long mountflags,
const void *data);
const char *mount_propagation_flag_to_string(unsigned long flags);
int mount_propagation_flag_from_string(const char *name, unsigned long *ret);