From: Daan De Meyer Date: Mon, 14 Aug 2023 13:15:08 +0000 (+0200) Subject: btrfs-util: Move subvolume creation to basic/btrfs.h X-Git-Tag: v255-rc1~724^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e54c79ccc2e90a375640815b05f28ec22664e44c;p=thirdparty%2Fsystemd.git btrfs-util: Move subvolume creation to basic/btrfs.h Also make btrfs_subvol_make() an openat style function. --- diff --git a/src/basic/btrfs.c b/src/basic/btrfs.c new file mode 100644 index 00000000000..a13fec4873f --- /dev/null +++ b/src/basic/btrfs.c @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#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 index 00000000000..38be9d2b3b1 --- /dev/null +++ b/src/basic/btrfs.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +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); diff --git a/src/basic/meson.build b/src/basic/meson.build index f6e6b6ace51..77ce2cf2621 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -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', diff --git a/src/home/homework-directory.c b/src/home/homework-directory.c index 575ac525512..4ec5f3dde10 100644 --- a/src/home/homework-directory.c +++ b/src/home/homework-directory.c @@ -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."); diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index e41920ce9c6..23a29d58113 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -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"); diff --git a/src/import/import-tar.c b/src/import/import-tar.c index dff6d3276ab..ff32ae4e592 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -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, diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index e474dffa72e..f9c82daec0e 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -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, diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index d6479929c1d..d91c69b6241 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -42,36 +42,6 @@ * 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. */ diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h index c972cc07446..22ff0c11153 100644 --- a/src/shared/btrfs-util.h +++ b/src/shared/btrfs-util.h @@ -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); diff --git a/src/shared/label-util.c b/src/shared/label-util.c index 3316c9ed37b..7262da2b1f1 100644 --- a/src/shared/label-util.c +++ b/src/shared/label-util.c @@ -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) diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index ba09563058e..5980727c857 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -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"); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index e765db4895d..bff09376dc0 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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;