btrfs-util.c revision 3f952f92b9f401fbe4c4876541ca145a551df039
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering This file is part of systemd.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Copyright 2014 Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is free software; you can redistribute it and/or modify it
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering under the terms of the GNU Lesser General Public License as published by
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering (at your option) any later version.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is distributed in the hope that it will be useful, but
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Lesser General Public License for more details.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering You should have received a copy of the GNU Lesser General Public License
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering/* WARNING: Be careful with file system ioctls! When we get an fd, we
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * need to make sure it either refers to only a regular file or
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * directory, or that it is located on btrfs, before invoking any
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * btrfs ioctls. The ioctl numbers are reused by some device drivers
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * (such as DRM), and hence might have bad effects when invoked on
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * device nodes (that reference drivers) rather than fds to normal
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * files or directories. */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int validate_subvolume_name(const char *name) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int open_parent(const char *path, int flags) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int extract_subvolume_name(const char *path, const char **subvolume) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* On btrfs subvolumes always have the inode 256 */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = extract_subvolume_name(path, &subvolume);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering strncpy(args.name, subvolume, sizeof(args.name)-1);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint btrfs_subvol_make_label(const char *path) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = mac_selinux_create_file_prepare(path, S_IFDIR);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return mac_smack_fix(path, false, false);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint btrfs_subvol_set_read_only_fd(int fd, bool b) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint btrfs_subvol_set_read_only(const char *path, bool b) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return btrfs_subvol_set_read_only_fd(fd, b);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringint btrfs_subvol_get_read_only_fd(int fd) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Make sure we invoke the ioctl on a regular file, so that no
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * device driver accidentally gets it. */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
875c6e1b48f37a07dfbb80d6653c73f205e94260Lennart Poettering struct btrfs_ioctl_clone_range_args args = {
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poetteringint btrfs_get_block_device_fd(int fd, dev_t *dev) {
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering struct btrfs_ioctl_fs_info_args fsi = {};
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* We won't do this for btrfs RAID */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringint btrfs_get_block_device(const char *path, dev_t *dev) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return btrfs_get_block_device_fd(fd, dev);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringint btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering struct btrfs_ioctl_ino_lookup_args args = {
return -ENOTTY;
return -errno;
if (subvol_fd < 0)
return -errno;
static void btrfs_ioctl_search_args_set(struct btrfs_ioctl_search_args *args, const struct btrfs_ioctl_search_header *h) {
assert(h);
(sh) = (const struct btrfs_ioctl_search_header*) ((uint8_t*) (sh) + sizeof(struct btrfs_ioctl_search_header) + (sh)->len))
bool found = false;
return -errno;
found = true;
goto finish;
if (!found)
return -ENODATA;
return -errno;
found_info = true;
found_limit = true;
goto finish;
return -ENODATA;
if (!found_info) {
if (!found_limit) {
return -errno;
return -EINVAL;
return -errno;
int btrfs_defrag(const char *p) {
if (fd < 0)
return -errno;
return -ENOTTY;
return -errno;
if (fd < 0)
return -errno;
return -ENOTTY;
return -errno;
if (fd < 0)
return -errno;
return -ENODEV;
return -ENOMEM;
if (r == -ENOENT)
return -ENODEV;
return -ENODEV;
if (backing_fd < 0)
return -errno;
return -errno;
return -ENODEV;
return -EINVAL;
return -ENOMEM;
if (loop_fd < 0)
return -errno;
return -EINVAL;
return -errno;
return -errno;
return -errno;
return -errno;
if (fd < 0)
return -errno;
return -EINVAL;
return -EINVAL;
.create = b,
return -errno;
static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
bool made_writable = false;
return -errno;
return -EINVAL;
if (subvol_fd < 0)
return -errno;
if (subvol_id == 0) {
return -errno;
return -errno;
return -ENOMEM;
return -errno;
if (!made_writable) {
made_writable = true;
if (child_fd < 0)
return -errno;
return -errno;
const char *subvolume;
if (fd < 0)
return fd;
static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
return -errno;
if (old_subvol_id == 0) {
return -errno;
return -ENOMEM;
return -errno;
return -ENOMEM;
if (old_child_fd < 0)
return -errno;
if (!np)
return -ENOMEM;
if (new_child_fd < 0)
return -errno;
if (subvolume_fd < 0) {
if (subvolume_fd < 0)
return -errno;
int k = -errno;
r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
const char *subvolume;
return -EISDIR;
if (new_fd < 0)
return new_fd;
if (old_fd < 0)
return -errno;