summaryrefslogtreecommitdiffstats
path: root/src/basic/fs-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-06-15 15:57:18 +0200
committerLennart Poettering <lennart@poettering.net>2021-07-08 10:22:34 +0200
commit427c934fdb634cde4d4426a13e7fc91d99f7db64 (patch)
tree2ac4e73a518b83f722831c3ceee03f892db763f6 /src/basic/fs-util.c
parenthostnamed: correct variable with errno in fallback_chassis (diff)
downloadsystemd-427c934fdb634cde4d4426a13e7fc91d99f7db64.tar.xz
systemd-427c934fdb634cde4d4426a13e7fc91d99f7db64.zip
fs-util: make sure fsync_directory_of_file() does something useful on O_PATH fds
When handling O_PATH fds it's safe to use the parent of /proc/self/fd/<fd> for any kind of inode. Hence do so.
Diffstat (limited to 'src/basic/fs-util.c')
-rw-r--r--src/basic/fs-util.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 8f0834fe46..127f709cd9 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -1378,18 +1378,39 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
}
int fsync_directory_of_file(int fd) {
- _cleanup_free_ char *path = NULL;
_cleanup_close_ int dfd = -1;
struct stat st;
int r;
assert(fd >= 0);
- /* We only reasonably can do this for regular files and directories, hence check for that */
+ /* We only reasonably can do this for regular files and directories, or for O_PATH fds, hence check
+ * for the inode type first */
if (fstat(fd, &st) < 0)
return -errno;
- if (S_ISREG(st.st_mode)) {
+ if (S_ISDIR(st.st_mode)) {
+ dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
+ if (dfd < 0)
+ return -errno;
+
+ } else if (!S_ISREG(st.st_mode)) { /* Regular files are OK regardless if O_PATH or not, for all other
+ * types check O_PATH flag */
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
+
+ if (!FLAGS_SET(flags, O_PATH)) /* If O_PATH this refers to the inode in the fs, in which case
+ * we can sensibly do what is requested. Otherwise this refers
+ * to a socket, fifo or device node, where the concept of a
+ * containing directory doesn't make too much sense. */
+ return -ENOTTY;
+ }
+
+ if (dfd < 0) {
+ _cleanup_free_ char *path = NULL;
r = fd_get_path(fd, &path);
if (r < 0) {
@@ -1412,13 +1433,7 @@ int fsync_directory_of_file(int fd) {
dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0);
if (dfd < 0)
return dfd;
-
- } else if (S_ISDIR(st.st_mode)) {
- dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
- if (dfd < 0)
- return -errno;
- } else
- return -ENOTTY;
+ }
if (fsync(dfd) < 0)
return -errno;