rm-rf: add support for recursively removing btrfs subvolumes
authorLennart Poettering <lennart@poettering.net>
Sat, 4 Apr 2015 17:22:00 +0000 (19:22 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 6 Apr 2015 08:57:53 +0000 (10:57 +0200)
src/shared/rm-rf.c
src/shared/rm-rf.h

index eeb2e39..50112e3 100644 (file)
@@ -75,7 +75,8 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
                 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
                         continue;
 
-                if (de->d_type == DT_UNKNOWN || (de->d_type == DT_DIR && root_dev)) {
+                if (de->d_type == DT_UNKNOWN ||
+                    (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
                         if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
                                 if (ret == 0 && errno != ENOENT)
                                         ret = -errno;
@@ -114,6 +115,30 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
                                 continue;
                         }
 
+                        if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
+                                struct btrfs_ioctl_vol_args args = {};
+
+                                /* This could be a subvolume, try to remove it */
+
+                                strncpy(args.name, de->d_name, sizeof(args.name)-1);
+                                if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0) {
+
+                                        if (errno != ENOTTY && errno != EINVAL) {
+                                                if (ret == 0)
+                                                        ret = -errno;
+
+                                                safe_close(subdir_fd);
+                                                continue;
+                                        }
+
+                                        /* ENOTTY, then it wasn't a btrfs subvolume */
+                                } else {
+                                        /* It was a subvolume, continue. */
+                                        safe_close(subdir_fd);
+                                        continue;
+                                }
+                        }
+
                         /* We pass REMOVE_PHYSICAL here, to avoid
                          * doing the fstatfs() to check the file
                          * system type again for each directory */
index 769bbc8..96579eb 100644 (file)
@@ -27,6 +27,7 @@ typedef enum RemoveFlags {
         REMOVE_ONLY_DIRECTORIES = 1,
         REMOVE_ROOT = 2,
         REMOVE_PHYSICAL = 4, /* if not set, only removes files on tmpfs, never physical file systems */
+        REMOVE_SUBVOLUME = 8,
 } RemoveFlags;
 
 int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);