summaryrefslogtreecommitdiff
path: root/src/basic/btrfs-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-08-06 19:32:00 +0200
committerLennart Poettering <lennart@poettering.net>2018-08-08 11:59:39 +0200
commit2e6e61688748473c4230ca49b402aea2bec9b8ab (patch)
treeec550a0636f6349e760f1cd097a1cd80ba130f9b /src/basic/btrfs-util.c
parent713998cfc8c2f08d096edf047bc0707c3e53286d (diff)
downloadsystemd-2e6e61688748473c4230ca49b402aea2bec9b8ab.tar.gz
btrfs-util: unfuck tmpfiles' subvol creation
tmpfiles now passes an O_PATH fd to btrfs_subvol_make_fd() under the assumption it will accept it like mkdirat() does. So far this assumption was wrong, let's correct that. Without that tmpfiles' on btrfs file systems failed systematically...
Diffstat (limited to 'src/basic/btrfs-util.c')
-rw-r--r--src/basic/btrfs-util.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index abd34824e7..376844b7b1 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -118,6 +118,7 @@ int btrfs_is_subvol(const char *path) {
int btrfs_subvol_make_fd(int fd, const char *subvolume) {
struct btrfs_ioctl_vol_args args = {};
+ _cleanup_close_ int real_fd = -1;
int r;
assert(subvolume);
@@ -126,6 +127,20 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume) {
if (r < 0)
return r;
+ r = fcntl(fd, F_GETFL);
+ if (r < 0)
+ return -errno;
+ if (FLAGS_SET(r, O_PATH)) {
+ /* An O_PATH fd was specified, let's convert here to a proper one, as btrfs ioctl's can't deal with
+ * O_PATH. */
+
+ real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (real_fd < 0)
+ return real_fd;
+
+ fd = real_fd;
+ }
+
strncpy(args.name, subvolume, sizeof(args.name)-1);
if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)