if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
return -EINVAL;
- /* We refuse to clean the root file system with this
- * call. This is extra paranoia to never cause a really
- * seriously broken system. */
+ /* We refuse to clean the root file system with this call. This is extra paranoia to never cause a
+ * really seriously broken system. */
if (path_equal_or_files_same(path, "/", AT_SYMLINK_NOFOLLOW))
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove entire root file system (\"%s\"), and we can't allow that.",
if (r >= 0)
return r;
+ if (FLAGS_SET(flags, REMOVE_MISSING_OK) && r == -ENOENT)
+ return 0;
+
if (!IN_SET(r, -ENOTTY, -EINVAL, -ENOTDIR))
return r;
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
+ if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT)
+ return 0;
+
if (!IN_SET(errno, ENOTDIR, ELOOP))
return -errno;
- if (!(flags & REMOVE_PHYSICAL)) {
- if (statfs(path, &s) < 0)
- return -errno;
+ if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES))
+ return 0;
- if (is_physical_fs(&s))
- return log_error_errno(SYNTHETIC_ERRNO(EPERM),
- "Attempted to remove files from a disk file system under \"%s\", refusing.",
- path);
- }
+ if (FLAGS_SET(flags, REMOVE_ROOT)) {
+
+ if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
+ if (statfs(path, &s) < 0)
+ return -errno;
+
+ if (is_physical_fs(&s))
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+ "Attempted to remove files from a disk file system under \"%s\", refusing.",
+ path);
+ }
+
+ if (unlink(path) < 0) {
+ if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT)
+ return 0;
- if ((flags & REMOVE_ROOT) && !(flags & REMOVE_ONLY_DIRECTORIES))
- if (unlink(path) < 0 && errno != ENOENT)
return -errno;
+ }
+ }
return 0;
}
r = rm_rf_children(fd, flags, NULL);
- if (flags & REMOVE_ROOT) {
- if (rmdir(path) < 0) {
- if (r == 0 && errno != ENOENT)
- r = -errno;
- }
- }
+ if (FLAGS_SET(flags, REMOVE_ROOT) &&
+ rmdir(path) < 0 &&
+ r >= 0 &&
+ (!FLAGS_SET(flags, REMOVE_MISSING_OK) || errno != ENOENT))
+ r = -errno;
return r;
}
#include "errno-util.h"
typedef enum RemoveFlags {
- REMOVE_ONLY_DIRECTORIES = 1 << 0,
- REMOVE_ROOT = 1 << 1,
- REMOVE_PHYSICAL = 1 << 2, /* if not set, only removes files on tmpfs, never physical file systems */
- REMOVE_SUBVOLUME = 1 << 3,
+ REMOVE_ONLY_DIRECTORIES = 1 << 0, /* Only remove empty directories, no files */
+ REMOVE_ROOT = 1 << 1, /* Remove the specified directory itself too, not just the contents of it */
+ REMOVE_PHYSICAL = 1 << 2, /* If not set, only removes files on tmpfs, never physical file systems */
+ REMOVE_SUBVOLUME = 1 << 3, /* Drop btrfs subvolumes in the tree too */
+ REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */
} RemoveFlags;
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);