]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
btrfs-util: Move subvolume creation to basic/btrfs.h
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 14 Aug 2023 13:15:08 +0000 (15:15 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 14 Aug 2023 16:46:08 +0000 (18:46 +0200)
Also make btrfs_subvol_make() an openat style function.

12 files changed:
src/basic/btrfs.c [new file with mode: 0644]
src/basic/btrfs.h [new file with mode: 0644]
src/basic/meson.build
src/home/homework-directory.c
src/home/homework-luks.c
src/import/import-tar.c
src/import/pull-tar.c
src/shared/btrfs-util.c
src/shared/btrfs-util.h
src/shared/label-util.c
src/test/test-btrfs.c
src/tmpfiles/tmpfiles.c

diff --git a/src/basic/btrfs.c b/src/basic/btrfs.c
new file mode 100644 (file)
index 0000000..a13fec4
--- /dev/null
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/btrfs.h>
+#include <sys/ioctl.h>
+
+#include "btrfs.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "path-util.h"
+
+int btrfs_validate_subvolume_name(const char *name) {
+
+        if (!filename_is_valid(name))
+                return -EINVAL;
+
+        if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
+                return -E2BIG;
+
+        return 0;
+}
+
+static int extract_subvolume_name(const char *path, char **ret) {
+        _cleanup_free_ char *fn = NULL;
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        r = path_extract_filename(path, &fn);
+        if (r < 0)
+                return r;
+
+        r = btrfs_validate_subvolume_name(fn);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(fn);
+        return 0;
+}
+
+int btrfs_subvol_make(int dir_fd, const char *path) {
+        struct btrfs_ioctl_vol_args args = {};
+        _cleanup_free_ char *subvolume = NULL;
+        _cleanup_close_ int fd = -EBADF;
+        int r;
+
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(!isempty(path));
+
+        r = extract_subvolume_name(path, &subvolume);
+        if (r < 0)
+                return r;
+
+        r = path_extract_directory(path, NULL);
+        if (r >= 0) {
+                fd = open_parent_at(dir_fd, path, O_RDONLY|O_CLOEXEC|O_CLOEXEC, 0);
+                if (fd < 0)
+                        return fd;
+
+                dir_fd = fd;
+        }
+
+        strncpy(args.name, subvolume, sizeof(args.name)-1);
+
+        return RET_NERRNO(ioctl(dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args));
+}
+
+int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode) {
+        mode_t old, combined;
+        int r;
+
+        assert(path);
+
+        /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
+        old = umask(~mode);
+        combined = old | ~mode;
+        if (combined != ~mode)
+                umask(combined);
+        r = btrfs_subvol_make(dir_fd, path);
+        umask(old);
+
+        if (r >= 0)
+                return 1; /* subvol worked */
+        if (r != -ENOTTY)
+                return r;
+
+        if (mkdirat(dir_fd, path, mode) < 0)
+                return -errno;
+
+        return 0; /* plain directory */
+}
diff --git a/src/basic/btrfs.h b/src/basic/btrfs.h
new file mode 100644 (file)
index 0000000..38be9d2
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+
+int btrfs_validate_subvolume_name(const char *name);
+
+int btrfs_subvol_make(int dir_fd, const char *path);
+
+int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode);
index f6e6b6ace519bf3cce9763060151122eeeb81397..77ce2cf26219be83006b9d1fc087d4082851f914 100644 (file)
@@ -8,6 +8,7 @@ basic_sources = files(
         'argv-util.c',
         'arphrd-util.c',
         'audit-util.c',
+        'btrfs.c',
         'build.c',
         'bus-label.c',
         'cap-list.c',
index 575ac525512086c4c288ac0f3777d91334361853..4ec5f3dde105524e120e91bf7fe20711e19e0e43 100644 (file)
@@ -131,7 +131,7 @@ int home_create_directory_or_subvolume(UserRecord *h, HomeSetup *setup, UserReco
 
         case USER_SUBVOLUME:
                 WITH_UMASK(0077)
-                        r = btrfs_subvol_make(d);
+                        r = btrfs_subvol_make(AT_FDCWD, d);
 
                 if (r >= 0) {
                         log_info("Subvolume created.");
index e41920ce9c681e6a528ffb78957b1baa1377aa1d..23a29d58113ffc7bea7604dbda80cb2a8cc76b44 100644 (file)
@@ -2383,7 +2383,7 @@ int home_create_luks(
                 return log_oom();
 
         /* Prefer using a btrfs subvolume if we can, fall back to directory otherwise */
-        r = btrfs_subvol_make_fallback(subdir, 0700);
+        r = btrfs_subvol_make_fallback(AT_FDCWD, subdir, 0700);
         if (r < 0)
                 return log_error_errno(r, "Failed to create user directory in mounted image file: %m");
 
index dff6d3276ab2a382beed15d037dff609173c0c75..ff32ae4e5920ea8559b9112ac7fcc89119686e07 100644 (file)
@@ -225,7 +225,7 @@ static int tar_import_fork_tar(TarImport *i) {
                 (void) rm_rf(d, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
 
         if (i->flags & IMPORT_BTRFS_SUBVOL)
-                r = btrfs_subvol_make_fallback(d, 0755);
+                r = btrfs_subvol_make_fallback(AT_FDCWD, d, 0755);
         else
                 r = RET_NERRNO(mkdir(d, 0755));
         if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
index e474dffa72ec6bbb453c5fe7bc76c6d33d41a772..f9c82daec0e1df5c1478660ad7c214171484c011 100644 (file)
@@ -516,7 +516,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
                 (void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
 
         if (i->flags & PULL_BTRFS_SUBVOL)
-                r = btrfs_subvol_make_fallback(where, 0755);
+                r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
         else
                 r = RET_NERRNO(mkdir(where, 0755));
         if (r == -EEXIST && (i->flags & PULL_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
index d6479929c1d3f63429c4ef812ec6dd36428c53e3..d91c69b624147e33ba46438ea1d2d35364a1b581 100644 (file)
  * device nodes (that reference drivers) rather than fds to normal
  * files or directories. */
 
-static int validate_subvolume_name(const char *name) {
-
-        if (!filename_is_valid(name))
-                return -EINVAL;
-
-        if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
-                return -E2BIG;
-
-        return 0;
-}
-
-static int extract_subvolume_name(const char *path, char **ret) {
-        _cleanup_free_ char *fn = NULL;
-        int r;
-
-        assert(path);
-        assert(ret);
-
-        r = path_extract_filename(path, &fn);
-        if (r < 0)
-                return r;
-
-        r = validate_subvolume_name(fn);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(fn);
-        return 0;
-}
-
 int btrfs_is_subvol_at(int dir_fd, const char *path) {
         struct stat st;
 
@@ -88,71 +58,6 @@ int btrfs_is_subvol_at(int dir_fd, const char *path) {
         return is_fs_type_at(dir_fd, path, BTRFS_SUPER_MAGIC);
 }
 
-int btrfs_subvol_make_fd(int fd, const char *subvolume) {
-        struct btrfs_ioctl_vol_args args = {};
-        _cleanup_close_ int real_fd = -EBADF;
-        int r;
-
-        assert(subvolume);
-
-        r = validate_subvolume_name(subvolume);
-        if (r < 0)
-                return r;
-
-        /* If an O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal
-         * with O_PATH. */
-        fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY, O_PATH|O_DIRECTORY, &real_fd);
-        if (fd < 0)
-                return fd;
-
-        strncpy(args.name, subvolume, sizeof(args.name)-1);
-
-        return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args));
-}
-
-int btrfs_subvol_make(const char *path) {
-        _cleanup_free_ char *subvolume = NULL;
-        _cleanup_close_ int fd = -EBADF;
-        int r;
-
-        assert(path);
-
-        r = extract_subvolume_name(path, &subvolume);
-        if (r < 0)
-                return r;
-
-        fd = open_parent(path, O_CLOEXEC, 0);
-        if (fd < 0)
-                return fd;
-
-        return btrfs_subvol_make_fd(fd, subvolume);
-}
-
-int btrfs_subvol_make_fallback(const char *path, mode_t mode) {
-        mode_t old, combined;
-        int r;
-
-        assert(path);
-
-        /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
-        old = umask(~mode);
-        combined = old | ~mode;
-        if (combined != ~mode)
-                umask(combined);
-        r = btrfs_subvol_make(path);
-        umask(old);
-
-        if (r >= 0)
-                return 1; /* subvol worked */
-        if (r != -ENOTTY)
-                return r;
-
-        if (mkdir(path, mode) < 0)
-                return -errno;
-
-        return 0; /* plain directory */
-}
-
 int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b) {
         _cleanup_close_ int fd = -EBADF;
         uint64_t flags, nflags;
@@ -1131,7 +1036,7 @@ int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags)
         if (fd < 0)
                 return fd;
 
-        r = validate_subvolume_name(subvolume);
+        r = btrfs_validate_subvolume_name(subvolume);
         if (r < 0)
                 return r;
 
@@ -1551,7 +1456,7 @@ int btrfs_subvol_snapshot_at_full(
         if (new_fd < 0)
                 return new_fd;
 
-        r = validate_subvolume_name(subvolume);
+        r = btrfs_validate_subvolume_name(subvolume);
         if (r < 0)
                 return r;
 
@@ -1565,7 +1470,7 @@ int btrfs_subvol_snapshot_at_full(
                 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
                         return -EISDIR;
 
-                r = btrfs_subvol_make_fd(new_fd, subvolume);
+                r = btrfs_subvol_make(new_fd, subvolume);
                 if (r < 0) {
                         if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
                                 /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
index c972cc07446e83774dfcf1f42ed888cab66938a3..22ff0c111535ac8bd57ac202010a5fabeebeab1a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "sd-id128.h"
 
+#include "btrfs.h"
 #include "copy.h"
 #include "time-util.h"
 
@@ -70,11 +71,6 @@ int btrfs_quota_scan_start(int fd);
 int btrfs_quota_scan_wait(int fd);
 int btrfs_quota_scan_ongoing(int fd);
 
-int btrfs_subvol_make(const char *path);
-int btrfs_subvol_make_fd(int fd, const char *subvolume);
-
-int btrfs_subvol_make_fallback(const char *path, mode_t);
-
 int btrfs_subvol_snapshot_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
 static inline int btrfs_subvol_snapshot_at(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags) {
         return btrfs_subvol_snapshot_at_full(dir_fdf, from, dir_fdt, to, flags, NULL, NULL, NULL);
index 3316c9ed37b5384265caaffac4ee62493d4316ed..7262da2b1f13a12772d12d46d6405dcd35c0e935 100644 (file)
@@ -108,7 +108,7 @@ int btrfs_subvol_make_label(const char *path) {
         if (r < 0)
                 return r;
 
-        r = btrfs_subvol_make(path);
+        r = btrfs_subvol_make(AT_FDCWD, path);
         mac_selinux_create_file_clear();
 
         if (r < 0)
index ba09563058e16300ab4afe24271ecc22eb6edde6..5980727c857529fa8912640e8626da42b5c3d639 100644 (file)
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
                 safe_close(fd);
         }
 
-        r = btrfs_subvol_make("/xxxtest");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxtest");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
@@ -97,33 +97,33 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
-        r = btrfs_subvol_make("/xxxrectest");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
-        r = btrfs_subvol_make("/xxxrectest/xxxrectest2");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest2");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
-        r = btrfs_subvol_make("/xxxrectest/xxxrectest3");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
-        r = btrfs_subvol_make("/xxxrectest/xxxrectest3/sub");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/xxxrectest3/sub");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
         if (mkdir("/xxxrectest/dir", 0755) < 0)
                 log_error_errno(errno, "Failed to make directory: %m");
 
-        r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
         if (mkdir("/xxxrectest/dir/xxxrectest4/dir", 0755) < 0)
                 log_error_errno(errno, "Failed to make directory: %m");
 
-        r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
@@ -142,7 +142,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to recursively remove subvolume: %m");
 
-        r = btrfs_subvol_make("/xxxquotatest");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
@@ -150,7 +150,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to set up auto qgroup: %m");
 
-        r = btrfs_subvol_make("/xxxquotatest/beneath");
+        r = btrfs_subvol_make(AT_FDCWD, "/xxxquotatest/beneath");
         if (r < 0)
                 log_error_errno(r, "Failed to make subvolume: %m");
 
index e765db4895da4fc03e4c4f739ca98f9781eda2e9..bff09376dc074d93865342aa26dbd620c2f42e7f 100644 (file)
@@ -1932,7 +1932,7 @@ static int create_directory_or_subvolume(
                         subvol = false;
                 else {
                         WITH_UMASK((~mode) & 0777)
-                                r = btrfs_subvol_make_fd(pfd, bn);
+                                r = btrfs_subvol_make(pfd, bn);
                 }
         } else
                 r = 0;