mirror of
https://github.com/systemd/systemd.git
synced 2025-01-24 06:04:05 +03:00
btrfs-util: Move subvolume creation to basic/btrfs.h
Also make btrfs_subvol_make() an openat style function.
This commit is contained in:
parent
6819924c30
commit
e54c79ccc2
91
src/basic/btrfs.c
Normal file
91
src/basic/btrfs.c
Normal file
@ -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 */
|
||||
}
|
9
src/basic/btrfs.h
Normal file
9
src/basic/btrfs.h
Normal file
@ -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);
|
@ -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',
|
||||
|
@ -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.");
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user