]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mount-util: refactor make_mount_point_inode_from_xyz()
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Feb 2025 22:03:46 +0000 (23:03 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 18 Feb 2025 12:49:24 +0000 (13:49 +0100)
This replaces make_mount_point_inode_from_stat() by
make_mount_point_inode_from_mode() and makes it take a single mode_t
rather than a "struct stat". Moreover, at an "atfd" style directory
parameter.

Then port all users over to new feature, and in particular make use of
the directory fd: use chase() to create and pin parent directories first where
needed.

src/shared/mount-util.c
src/shared/mount-util.h
src/sysext/sysext.c
src/test/test-mount-util.c

index d4718251623f4f3ccf2a3bb1b3722de95e119075..3ff15a22141a733e489537eabfc8736e31721030 100644 (file)
@@ -958,10 +958,7 @@ static int mount_in_namespace_legacy(
 
         /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
         mount_tmp = strjoina(mount_slave, "/mount");
-        if (flags & MOUNT_IN_NAMESPACE_IS_IMAGE)
-                r = mkdir_p(mount_tmp, 0700);
-        else
-                r = make_mount_point_inode_from_stat(chased_src_st, mount_tmp, 0700);
+        r = make_mount_point_inode_from_mode(AT_FDCWD, mount_tmp, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700);
         if (r < 0) {
                 log_debug_errno(r, "Failed to create temporary mount point %s: %m", mount_tmp);
                 goto finish;
@@ -1057,12 +1054,15 @@ static int mount_in_namespace_legacy(
 
                 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
 
-                if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) {
-                        if (!(flags & MOUNT_IN_NAMESPACE_IS_IMAGE)) {
-                                (void) mkdir_parents(dest, 0755);
-                                (void) make_mount_point_inode_from_stat(chased_src_st, dest, 0700);
-                        } else
-                                (void) mkdir_p(dest, 0755);
+                _cleanup_close_ int dest_fd = -EBADF;
+                _cleanup_free_ char *dest_fn = NULL;
+                r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to pin parent directory of mount '%s', ignoring: %m", dest);
+                else if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) {
+                        r = make_mount_point_inode_from_mode(dest_fd, dest_fn, (flags & MOUNT_IN_NAMESPACE_IS_IMAGE) ? S_IFDIR : chased_src_st->st_mode, 0700);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to make mount point inode of mount '%s', ignoring: %m", dest);
                 }
 
                 /* Fifth, move the mount to the right place inside */
@@ -1076,7 +1076,7 @@ static int mount_in_namespace_legacy(
                 if (!mount_inside)
                         report_errno_and_exit(errno_pipe_fd[1], log_oom_debug());
 
-                r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest, NULL, MS_MOVE, NULL);
+                r = mount_nofollow_verbose(LOG_DEBUG, mount_inside, dest_fd >= 0 ? FORMAT_PROC_FD_PATH(dest_fd) : dest, /* fstype= */ NULL, MS_MOVE, /* options= */ NULL);
                 if (r < 0)
                         report_errno_and_exit(errno_pipe_fd[1], r);
 
@@ -1247,8 +1247,14 @@ static int mount_in_namespace(
         if (r == 0) {
                 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
 
+                _cleanup_close_ int dest_fd = -EBADF;
+                _cleanup_free_ char *dest_fn = NULL;
+                r = chase(dest, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|((flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY) ? CHASE_MKDIR_0755 : 0), &dest_fn, &dest_fd);
+                if (r < 0)
+                        report_errno_and_exit(errno_pipe_fd[1], r);
+
                 if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
-                        (void) mkdir_parents(dest, 0755);
+                        (void) make_mount_point_inode_from_mode(dest_fd, dest_fn, img ? S_IFDIR : st.st_mode, 0700);
 
                 if (img) {
                         DissectImageFlags f =
@@ -1268,12 +1274,8 @@ static int mount_in_namespace(
                                         /* uid_range= */ UID_INVALID,
                                         /* userns_fd= */ -EBADF,
                                         f);
-                } else {
-                        if (flags & MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY)
-                                (void) make_mount_point_inode_from_stat(&st, dest, 0700);
-
+                } else
                         r = mount_exchange_graceful(new_mount_fd, dest, /* mount_beneath= */ true);
-                }
 
                 report_errno_and_exit(errno_pipe_fd[1], r);
         }
@@ -1698,17 +1700,17 @@ int bind_mount_submounts(
         return ret;
 }
 
-int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) {
-        assert(st);
+int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode) {
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
         assert(dest);
 
-        if (S_ISDIR(st->st_mode))
-                return mkdir_label(dest, mode);
+        if (S_ISDIR(source_mode))
+                return mkdirat_label(dir_fd, dest, target_mode & 07777);
         else
-                return RET_NERRNO(mknod(dest, S_IFREG|(mode & ~0111), 0));
+                return RET_NERRNO(mknodat(dir_fd, dest, S_IFREG|(target_mode & 07666), 0)); /* Mask off X bit */
 }
 
-int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) {
+int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t access_mode) {
         struct stat st;
 
         assert(source);
@@ -1717,7 +1719,7 @@ int make_mount_point_inode_from_path(const char *source, const char *dest, mode_
         if (stat(source, &st) < 0)
                 return -errno;
 
-        return make_mount_point_inode_from_stat(&st, dest, mode);
+        return make_mount_point_inode_from_mode(AT_FDCWD, dest, st.st_mode, access_mode);
 }
 
 int trigger_automount_at(int dir_fd, const char *path) {
index 895fe2b2cdece26b21e3e7d273b0e124aa5d7cd5..fa55c9d32ca15c2c91b1a2be7f7db44e075f8f80 100644 (file)
@@ -178,8 +178,8 @@ int bind_mount_submounts(
                 const char *source,
                 const char *target);
 
-/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */
-int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode);
+/* Creates a mount point (without any parents) based on the source path or mode - i.e., a file or a directory */
+int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source_mode, mode_t target_mode);
 int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode);
 
 int trigger_automount_at(int dir_fd, const char *path);
index 9b1839d43a96bc03ebf701cba12123cd12fc93da..92c60c49ae28b11940c17c8b0c01f64007921a57 100644 (file)
@@ -297,22 +297,28 @@ static int move_submounts(const char *src, const char *dst) {
 
                 assert_se(suffix = path_startswith(m->path, src));
 
+                if (fstat(m->mount_fd, &st) < 0)
+                        return log_error_errno(errno, "Failed to stat %s: %m", m->path);
+
                 t = path_join(dst, suffix);
                 if (!t)
                         return log_oom();
 
-                if (fstat(m->mount_fd, &st) < 0)
-                        return log_error_errno(errno, "Failed to stat %s: %m", m->path);
-
-                r = mkdir_parents(t, 0755);
+                _cleanup_free_ char *fn = NULL;
+                _cleanup_close_ int fd = -EBADF;
+                r = chase(t, /* root= */ NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn, &fd);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to create parent directories of %s: %m", t);
+                        return log_error_errno(r, "Failed to create and pin parent directory of %s: %m", t);
 
-                r = make_mount_point_inode_from_stat(&st, t, 0755);
+                r = make_mount_point_inode_from_mode(fd, fn, st.st_mode, 0755);
                 if (r < 0 && r != -EEXIST)
                         return log_error_errno(r, "Failed to create mountpoint %s: %m", t);
 
-                r = mount_follow_verbose(LOG_ERR, m->path, t, NULL, MS_BIND|MS_REC, NULL);
+                _cleanup_close_ int child_fd = openat(fd, fn, O_PATH|O_CLOEXEC);
+                if (child_fd < 0)
+                        return log_error_errno(errno, "Failed to pin mountpoint %s: %m", t);
+
+                r = mount_follow_verbose(LOG_ERR, m->path, FORMAT_PROC_FD_PATH(child_fd), /* fstype= */ NULL, MS_BIND|MS_REC, /* options= */ NULL);
                 if (r < 0)
                         return r;
 
index 5fb4d23f3e8d2c081e8a913c13c5a00fb9180179..33220abe714e64fd96e28407c37aa66db0c60ac6 100644 (file)
@@ -266,9 +266,9 @@ TEST(make_mount_point_inode) {
         assert_se(rmdir(dst_dir) == 0);
 
         assert_se(stat(src_file, &st) == 0);
-        assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0);
+        assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_file, st.st_mode, 0755) >= 0);
         assert_se(stat(src_dir, &st) == 0);
-        assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0);
+        assert_se(make_mount_point_inode_from_mode(AT_FDCWD, dst_dir, st.st_mode, 0755) >= 0);
 
         assert_se(stat(dst_dir, &st) == 0);
         assert_se(S_ISDIR(st.st_mode));