about summary refs log tree commit diff
path: root/shared/systemd/src/basic/fs-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/systemd/src/basic/fs-util.c')
-rw-r--r--shared/systemd/src/basic/fs-util.c120
1 files changed, 72 insertions, 48 deletions
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
index 56385fa2..e30f40fb 100644
--- a/shared/systemd/src/basic/fs-util.c
+++ b/shared/systemd/src/basic/fs-util.c
@@ -4,13 +4,9 @@
 
 #include <errno.h>
 #include <stddef.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
 #include <linux/falloc.h>
 #include <linux/magic.h>
-#include <time.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -20,7 +16,9 @@
 #include "locale-util.h"
 #include "log.h"
 #include "macro.h"
-#include "missing.h"
+#include "missing_fcntl.h"
+#include "missing_fs.h"
+#include "missing_syscall.h"
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -669,6 +667,18 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
 }
 
 #if 0 /* NM_IGNORED */
+int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
+
+        if (inotify_add_watch(fd, pathname, mask) < 0) {
+                if (errno == ENOSPC)
+                        return log_error_errno(errno, "Failed to add a watch for %s: inotify watch limit reached", pathname);
+
+                return log_error_errno(errno, "Failed to add a watch for %s: %m", pathname);
+        }
+
+        return 0;
+}
+
 static bool unsafe_transition(const struct stat *a, const struct stat *b) {
         /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
          * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
@@ -707,7 +717,7 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
                                  n1, path);
 }
 
-int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
+int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
         _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
         _cleanup_close_ int fd = -1;
         unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
@@ -719,10 +729,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
         assert(path);
 
         /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
-        if (FLAGS_SET(flags, CHASE_NONEXISTENT | CHASE_OPEN))
+        if ((flags & CHASE_NONEXISTENT) && ret_fd)
                 return -EINVAL;
 
-        if (FLAGS_SET(flags, CHASE_STEP | CHASE_OPEN))
+        if ((flags & CHASE_STEP) && ret_fd)
                 return -EINVAL;
 
         if (isempty(path))
@@ -741,24 +751,24 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
          * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
          * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
          * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
-         * at a minimum.
+         * to a minimum.
          *
          * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
          * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
          * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
          * specified path.
          *
-         * There are three ways to invoke this function:
+         * There are five ways to invoke this function:
          *
-         * 1. Without CHASE_STEP or CHASE_OPEN: in this case the path is resolved and the normalized path is returned
-         *    in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set 0 is returned if the file
-         *    doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set >= 0 is returned if the destination was
-         *    found, -ENOENT if it doesn't.
+         * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
+         *    returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
+         *    is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
+         *    returned if the destination was found, -ENOENT if it wasn't.
          *
-         * 2. With CHASE_OPEN: in this case the destination is opened after chasing it as O_PATH and this file
+         * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
          *    descriptor is returned as return value. This is useful to open files relative to some root
          *    directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
-         *    fd_reopen() or such) before it can be used for reading/writing. CHASE_OPEN may not be combined with
+         *    fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
          *    CHASE_NONEXISTENT.
          *
          * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
@@ -769,26 +779,26 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
          *
          * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
          *    unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
-         *    CHASE_WARN is also set a warning describing the unsafe transition is emitted.
+         *    CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
          *
-         * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, the path normalization is
-         *    aborted and -EREMOTE is returned. If CHASE_WARN is also set a warning showing the path of the mount point
-         *    is emitted.
-         *
-         * */
+         * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
+         *    is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
+         *    the mount point is emitted.
+         */
 
         /* A root directory of "/" or "" is identical to none */
         if (empty_or_root(original_root))
                 original_root = NULL;
 
-        if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) {
-                /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
+        if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
+                /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
                  * and doesn't care about any of the other special features we provide either. */
                 r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
                 if (r < 0)
                         return -errno;
 
-                return r;
+                *ret_fd = r;
+                return 0;
         }
 
         if (original_root) {
@@ -797,7 +807,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         return r;
 
                 if (flags & CHASE_PREFIX_ROOT) {
-
                         /* We don't support relative paths in combination with a root directory */
                         if (!path_is_absolute(path))
                                 return -EINVAL;
@@ -942,7 +951,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
 
                 if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
                         char *joined;
-
                         _cleanup_free_ char *destination = NULL;
 
                         /* This is a symlink, in this case read the destination. But let's make sure we don't follow
@@ -1028,15 +1036,15 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         return -ENOMEM;
         }
 
-        if (ret)
-                *ret = TAKE_PTR(done);
+        if (ret_path)
+                *ret_path = TAKE_PTR(done);
 
-        if (flags & CHASE_OPEN) {
-                /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
-                 * opening /proc/self/fd/xyz. */
+        if (ret_fd) {
+                /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
+                 * proper fd by opening /proc/self/fd/xyz. */
 
                 assert(fd >= 0);
-                return TAKE_FD(fd);
+                *ret_fd = TAKE_FD(fd);
         }
 
         if (flags & CHASE_STEP)
@@ -1045,14 +1053,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
         return exists;
 
 chased_one:
-        if (ret) {
+        if (ret_path) {
                 char *c;
 
                 c = strjoin(strempty(done), todo);
                 if (!c)
                         return -ENOMEM;
 
-                *ret = c;
+                *ret_path = c;
         }
 
         return 0;
@@ -1081,9 +1089,10 @@ int chase_symlinks_and_open(
                 return r;
         }
 
-        path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
-        if (path_fd < 0)
-                return path_fd;
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
 
         r = fd_reopen(path_fd, open_flags);
         if (r < 0)
@@ -1106,6 +1115,7 @@ int chase_symlinks_and_opendir(
         _cleanup_close_ int path_fd = -1;
         _cleanup_free_ char *p = NULL;
         DIR *d;
+        int r;
 
         if (!ret_dir)
                 return -EINVAL;
@@ -1122,9 +1132,10 @@ int chase_symlinks_and_opendir(
                 return 0;
         }
 
-        path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
-        if (path_fd < 0)
-                return path_fd;
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
 
         xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
         d = opendir(procfs_path);
@@ -1143,10 +1154,12 @@ int chase_symlinks_and_stat(
                 const char *root,
                 unsigned chase_flags,
                 char **ret_path,
-                struct stat *ret_stat) {
+                struct stat *ret_stat,
+                int *ret_fd) {
 
         _cleanup_close_ int path_fd = -1;
         _cleanup_free_ char *p = NULL;
+        int r;
 
         assert(path);
         assert(ret_stat);
@@ -1162,18 +1175,18 @@ int chase_symlinks_and_stat(
                 return 1;
         }
 
-        path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
-        if (path_fd < 0)
-                return path_fd;
+        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
+        if (r < 0)
+                return r;
+        assert(path_fd >= 0);
 
         if (fstat(path_fd, ret_stat) < 0)
                 return -errno;
 
         if (ret_path)
                 *ret_path = TAKE_PTR(p);
-
-        if (chase_flags & CHASE_OPEN)
-                return TAKE_FD(path_fd);
+        if (ret_fd)
+                *ret_fd = TAKE_FD(path_fd);
 
         return 1;
 }
@@ -1307,6 +1320,17 @@ int fsync_directory_of_file(int fd) {
         return 0;
 }
 
+int fsync_full(int fd) {
+        int r, q;
+
+        /* Sync both the file and the directory */
+
+        r = fsync(fd) < 0 ? -errno : 0;
+        q = fsync_directory_of_file(fd);
+
+        return r < 0 ? r : q;
+}
+
 int fsync_path_at(int at_fd, const char *path) {
         _cleanup_close_ int opened_fd = -1;
         int fd;