Merge pull request #32933 from YHNdnzj/faccessat-empty-path
fs-util: several cleanups
This commit is contained in:
+18
-19
@@ -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. */
|
||||
}
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user