[systemd-commits] 9 commits - Makefile.am TODO src/boot src/core src/import src/journal src/login src/nspawn src/shared src/test src/tmpfiles
Lennart Poettering
lennart at kemper.freedesktop.org
Mon Apr 6 02:28:35 PDT 2015
Makefile.am | 7 +
TODO | 6
src/boot/bootctl.c | 3
src/core/execute.c | 5
src/core/machine-id-setup.c | 2
src/core/manager.c | 3
src/import/aufs-util.c | 5
src/import/export-tar.c | 2
src/import/import-raw.c | 7 -
src/import/import-tar.c | 10 -
src/import/pull-common.c | 9 -
src/import/pull-dkr.c | 4
src/import/pull-raw.c | 7 -
src/import/pull-tar.c | 4
src/journal/journald-server.c | 3
src/journal/test-journal-init.c | 3
src/journal/test-journal-interleaving.c | 8 -
src/journal/test-journal-stream.c | 10 -
src/journal/test-journal-verify.c | 3
src/journal/test-journal.c | 6
src/login/logind-user.c | 5
src/nspawn/nspawn.c | 5
src/shared/btrfs-ctree.h | 6
src/shared/btrfs-util.c | 163 +++++++++++++++++++----
src/shared/btrfs-util.h | 4
src/shared/machine-image.c | 11 +
src/shared/missing.h | 8 +
src/shared/path-util.c | 89 +++++++-----
src/shared/path-util.h | 1
src/shared/rm-rf.c | 224 ++++++++++++++++++++++++++++++++
src/shared/rm-rf.h | 34 ++++
src/shared/switch-root.c | 5
src/shared/util.c | 199 ----------------------------
src/shared/util.h | 9 -
src/test/test-btrfs.c | 48 ++++++
src/test/test-conf-files.c | 4
src/test/test-copy.c | 9 -
src/test/test-execute.c | 3
src/test/test-hostname.c | 1
src/test/test-path-lookup.c | 3
src/test/test-path-util.c | 3
src/test/test-path.c | 12 +
src/test/test-util.c | 7 -
src/tmpfiles/tmpfiles.c | 3
44 files changed, 618 insertions(+), 345 deletions(-)
New commits:
commit d9e2daaf3d8649650cf9784b4fe9d9de4507da0c
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Apr 6 10:57:17 2015 +0200
btrfs: support recursively removing btrfs snapshots
diff --git a/Makefile.am b/Makefile.am
index 4973d84..d9dff94 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -771,8 +771,6 @@ libsystemd_shared_la_SOURCES = \
src/shared/device-nodes.h \
src/shared/util.c \
src/shared/util.h \
- src/shared/rm-rf.c \
- src/shared/rm-rf.h \
src/shared/virt.c \
src/shared/virt.h \
src/shared/architecture.c \
@@ -980,6 +978,8 @@ libsystemd_label_la_SOURCES = \
src/shared/btrfs-util.c \
src/shared/btrfs-util.h \
src/shared/btrfs-ctree.h \
+ src/shared/rm-rf.c \
+ src/shared/rm-rf.h \
src/shared/machine-image.c \
src/shared/machine-image.h \
src/shared/machine-pool.c \
@@ -1660,6 +1660,7 @@ test_util_SOURCES = \
src/test/test-util.c
test_util_LDADD = \
+ libsystemd-label.la \
libsystemd-shared.la
test_path_lookup_SOURCES = \
@@ -1668,6 +1669,7 @@ test_path_lookup_SOURCES = \
test_path_lookup_LDADD = \
-lm \
libsystemd-units.la \
+ libsystemd-label.la \
libsystemd-shared.la
test_uid_range_SOURCES = \
@@ -1967,6 +1969,7 @@ test_path_util_SOURCES = \
src/test/test-path-util.c
test_path_util_LDADD = \
+ libsystemd-label.la \
libsystemd-shared.la
test_path_SOURCES = \
@@ -2026,6 +2029,7 @@ test_conf_files_SOURCES = \
src/test/test-conf-files.c
test_conf_files_LDADD = \
+ libsystemd-label.la \
libsystemd-shared.la
test_bus_policy_SOURCES = \
@@ -2501,6 +2505,7 @@ bootctl_CFLAGS = \
$(BLKID_CFLAGS)
bootctl_LDADD = \
+ libsystemd-label.la \
libsystemd-shared.la \
libsystemd-internal.la \
$(BLKID_LIBS)
diff --git a/src/import/export-tar.c b/src/import/export-tar.c
index c27bab4..c2fd656 100644
--- a/src/import/export-tar.c
+++ b/src/import/export-tar.c
@@ -77,7 +77,7 @@ TarExport *tar_export_unref(TarExport *e) {
}
if (e->temp_path) {
- (void) btrfs_subvol_remove(e->temp_path);
+ (void) btrfs_subvol_remove(e->temp_path, false);
free(e->temp_path);
}
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 3a31513..ad8f806 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -241,10 +241,8 @@ static int raw_import_finish(RawImport *i) {
return r;
}
- if (i->force_local) {
- (void) btrfs_subvol_remove(i->final_path);
- (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL);
- }
+ if (i->force_local)
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
if (r < 0)
diff --git a/src/import/import-tar.c b/src/import/import-tar.c
index c5346ca..6ec5504 100644
--- a/src/import/import-tar.c
+++ b/src/import/import-tar.c
@@ -87,8 +87,7 @@ TarImport* tar_import_unref(TarImport *i) {
}
if (i->temp_path) {
- (void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
@@ -197,10 +196,8 @@ static int tar_import_finish(TarImport *i) {
return r;
}
- if (i->force_local) {
- (void) btrfs_subvol_remove(i->final_path);
- (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL);
- }
+ if (i->force_local)
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
if (r < 0)
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index d4cebe2..ee0c064 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -124,10 +124,8 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
p = strjoina(image_root, "/", local);
- if (force_local) {
- (void) btrfs_subvol_remove(p);
- (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
- }
+ if (force_local)
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = btrfs_subvol_snapshot(final, p, false, false);
if (r == -ENOTTY) {
diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c
index a1e6fe8..402ddac 100644
--- a/src/import/pull-dkr.c
+++ b/src/import/pull-dkr.c
@@ -111,8 +111,7 @@ DkrPull* dkr_pull_unref(DkrPull *i) {
sd_event_unref(i->event);
if (i->temp_path) {
- (void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index e10b280..ebbe6a9 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -277,10 +277,8 @@ static int raw_pull_make_local_copy(RawPull *i) {
p = strjoina(i->image_root, "/", i->local, ".raw");
- if (i->force_local) {
- (void) btrfs_subvol_remove(p);
- (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
- }
+ if (i->force_local)
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = tempfn_random(p, &tp);
if (r < 0)
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index 60dc22f..0efa07d 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -88,8 +88,7 @@ TarPull* tar_pull_unref(TarPull *i) {
sd_event_unref(i->event);
if (i->temp_path) {
- (void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 730541a..90c4415 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -4459,7 +4459,7 @@ finish:
if (remove_subvol && arg_directory) {
int k;
- k = btrfs_subvol_remove(arg_directory);
+ k = btrfs_subvol_remove(arg_directory, true);
if (k < 0)
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
}
diff --git a/src/shared/btrfs-ctree.h b/src/shared/btrfs-ctree.h
index 8b6f1ab..d3ae573 100644
--- a/src/shared/btrfs-ctree.h
+++ b/src/shared/btrfs-ctree.h
@@ -90,3 +90,9 @@ struct btrfs_qgroup_limit_item {
le64_t rsv_rfer;
le64_t rsv_excl;
} _packed_;
+
+struct btrfs_root_ref {
+ le64_t dirid;
+ le64_t sequence;
+ le16_t name_len;
+} _packed_;
diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c
index a95cb83..fc795cb 100644
--- a/src/shared/btrfs-util.c
+++ b/src/shared/btrfs-util.c
@@ -124,14 +124,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, bool read_only, b
r = copy_directory_fd(old_fd, new_path, true);
if (r < 0) {
- btrfs_subvol_remove(new_path);
+ btrfs_subvol_remove(new_path, false);
return r;
}
if (read_only) {
r = btrfs_subvol_set_read_only(new_path, true);
if (r < 0) {
- btrfs_subvol_remove(new_path);
+ btrfs_subvol_remove(new_path, false);
return r;
}
}
@@ -211,30 +211,6 @@ int btrfs_subvol_make_label(const char *path) {
return mac_smack_fix(path, false, false);
}
-int btrfs_subvol_remove(const char *path) {
- struct btrfs_ioctl_vol_args args = {};
- _cleanup_close_ int fd = -1;
- const char *subvolume;
- int r;
-
- assert(path);
-
- r = extract_subvolume_name(path, &subvolume);
- if (r < 0)
- return r;
-
- fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (fd < 0)
- return fd;
-
- strncpy(args.name, subvolume, sizeof(args.name)-1);
-
- if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
- return -errno;
-
- return 0;
-}
-
int btrfs_subvol_set_read_only_fd(int fd, bool b) {
uint64_t flags, nflags;
struct stat st;
@@ -798,3 +774,138 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
return btrfs_resize_loopback_fd(fd, new_size, grow_only);
}
+
+static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
+ struct btrfs_ioctl_search_args args = {
+ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
+
+ .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
+ .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
+
+ .key.min_type = BTRFS_ROOT_BACKREF_KEY,
+ .key.max_type = BTRFS_ROOT_BACKREF_KEY,
+
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+
+ struct btrfs_ioctl_vol_args vol_args = {};
+ _cleanup_close_ int subvol_fd = -1;
+ int r;
+
+ assert(fd >= 0);
+ assert(subvolume);
+
+ /* First, try to remove the subvolume. If it happens to be
+ * already empty, this will just work. */
+ strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
+ return 0;
+ if (!recursive || errno != ENOTEMPTY)
+ return -errno;
+
+ /* OK, the subvolume is not empty, let's look for child
+ * subvolumes, and remove them, first */
+ subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (subvol_fd < 0)
+ return -errno;
+
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
+ if (r < 0)
+ return r;
+ }
+
+ args.key.min_offset = args.key.max_offset = subvol_id;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ _cleanup_free_ char *p = NULL;
+ const struct btrfs_root_ref *ref;
+ struct btrfs_ioctl_ino_lookup_args ino_args;
+
+ btrfs_ioctl_search_args_set(&args, sh);
+
+ if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ continue;
+ if (sh->offset != subvol_id)
+ continue;
+
+ ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+
+ p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
+ if (!p)
+ return -ENOMEM;
+
+ zero(ino_args);
+ ino_args.treeid = subvol_id;
+ ino_args.objectid = ref->dirid;
+
+ if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
+ return -errno;
+
+ if (isempty(ino_args.name))
+ /* Subvolume is in the top-level
+ * directory of the subvolume. */
+ r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive);
+ else {
+ _cleanup_close_ int child_fd = -1;
+
+ /* Subvolume is somewhere further down,
+ * hence we need to open the
+ * containing directory first */
+
+ child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (child_fd < 0)
+ return -errno;
+
+ r = subvol_remove_children(child_fd, p, sh->objectid, recursive);
+ }
+ if (r < 0)
+ return r;
+ }
+
+ /* Increase search key by one, to read the next item, if we can. */
+ if (!btrfs_ioctl_search_args_inc(&args))
+ break;
+ }
+
+ /* OK, the child subvolumes should all be gone now, let's try
+ * again to remove the subvolume */
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_subvol_remove(const char *path, bool recursive) {
+ _cleanup_close_ int fd = -1;
+ const char *subvolume;
+ int r;
+
+ assert(path);
+
+ r = extract_subvolume_name(path, &subvolume);
+ if (r < 0)
+ return r;
+
+ fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return fd;
+
+ return subvol_remove_children(fd, subvolume, 0, recursive);
+}
+
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) {
+ return subvol_remove_children(fd, subvolume, 0, recursive);
+}
diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h
index 9685723..06ecc11 100644
--- a/src/shared/btrfs-util.h
+++ b/src/shared/btrfs-util.h
@@ -47,7 +47,6 @@ int btrfs_is_snapshot(int fd);
int btrfs_subvol_make(const char *path);
int btrfs_subvol_make_label(const char *path);
-int btrfs_subvol_remove(const char *path);
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, bool read_only, bool fallback_copy);
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy);
@@ -76,3 +75,6 @@ int btrfs_quota_limit(const char *path, uint64_t referenced_max);
int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+
+int btrfs_subvol_remove(const char *path, bool recursive);
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index f166e94..fb72123 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -358,7 +358,7 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- return btrfs_subvol_remove(i->path);
+ return btrfs_subvol_remove(i->path, true);
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
diff --git a/src/shared/missing.h b/src/shared/missing.h
index ca670ce..67006fb 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -428,6 +428,10 @@ struct btrfs_ioctl_clone_range_args {
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
+#ifndef BTRFS_LAST_FREE_OBJECTID
+#define BTRFS_LAST_FREE_OBJECTID -256ULL
+#endif
+
#ifndef BTRFS_ROOT_TREE_OBJECTID
#define BTRFS_ROOT_TREE_OBJECTID 1
#endif
@@ -452,6 +456,10 @@ struct btrfs_ioctl_clone_range_args {
#define BTRFS_QGROUP_LIMIT_KEY 244
#endif
+#ifndef BTRFS_ROOT_BACKREF_KEY
+#define BTRFS_ROOT_BACKREF_KEY 144
+#endif
+
#ifndef BTRFS_SUPER_MAGIC
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c
index 50112e3..a89e8af 100644
--- a/src/shared/rm-rf.c
+++ b/src/shared/rm-rf.c
@@ -21,6 +21,7 @@
#include "util.h"
#include "path-util.h"
+#include "btrfs-util.h"
#include "rm-rf.h"
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
@@ -116,22 +117,22 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
}
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) {
+ r = btrfs_subvol_remove_fd(fd, de->d_name, true);
+ if (r < 0) {
+ if (r != -ENOTTY && r != -EINVAL) {
if (ret == 0)
- ret = -errno;
+ ret = r;
safe_close(subdir_fd);
continue;
}
- /* ENOTTY, then it wasn't a btrfs subvolume */
+ /* ENOTTY, then it wasn't a
+ * btrfs subvolume, continue
+ * below. */
} else {
/* It was a subvolume, continue. */
safe_close(subdir_fd);
@@ -175,6 +176,18 @@ int rm_rf(const char *path, RemoveFlags flags) {
return -EPERM;
}
+ if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
+ /* Try to remove as subvolume first */
+ r = btrfs_subvol_remove(path, true);
+ if (r >= 0)
+ return r;
+
+ if (r != -ENOTTY && r != -EINVAL)
+ return r;
+
+ /* Not btrfs or not a subvolume */
+ }
+
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
@@ -201,8 +214,8 @@ int rm_rf(const char *path, RemoveFlags flags) {
r = rm_rf_children(fd, flags, NULL);
if (flags & REMOVE_ROOT) {
- if (rmdir(path) < 0 && errno != ENOENT) {
- if (r == 0)
+ if (rmdir(path) < 0) {
+ if (r == 0 && errno != ENOENT)
r = -errno;
}
}
diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c
index 9e6538e..373ce43 100644
--- a/src/test/test-btrfs.c
+++ b/src/test/test-btrfs.c
@@ -27,8 +27,7 @@
#include "btrfs-util.h"
int main(int argc, char *argv[]) {
- int r;
- int fd;
+ int r, fd;
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
@@ -81,15 +80,15 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/xxxtest");
+ r = btrfs_subvol_remove("/xxxtest", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest2");
+ r = btrfs_subvol_remove("/xxxtest2", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest3");
+ r = btrfs_subvol_remove("/xxxtest3", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
@@ -97,9 +96,46 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/etc2");
+ r = btrfs_subvol_remove("/etc2", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
+ r = btrfs_subvol_make("/xxxrectest");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/xxxrectest2");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/xxxrectest3");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/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");
+ 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");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ if (mkdir("/xxxrectest/mnt", 0755) < 0)
+ log_error_errno(errno, "Failed to make directory: %m");
+
+ r = btrfs_subvol_remove("/xxxrectest", true);
+ if (r < 0)
+ log_error_errno(r, "Failed to recursively remove subvolume: %m");
+
return 0;
}
diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c
index c7e5de8..dd50c51 100644
--- a/src/test/test-hostname.c
+++ b/src/test/test-hostname.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include "hostname-setup.h"
#include "util.h"
commit 41d1ed059bbc863c73161f39594de2eb7b338886
Author: Lennart Poettering <lennart at poettering.net>
Date: Sun Apr 5 11:28:04 2015 +0200
machined: drop btrfs subvolumes when removing container images
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index c5808af..f166e94 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -363,11 +363,13 @@ int image_remove(Image *i) {
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
-
- /* fall through */
+ return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
case IMAGE_RAW:
- return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL);
+ if (unlink(i->path) < 0)
+ return -errno;
+
+ return 0;
default:
return -EOPNOTSUPP;
commit e792e890fe8343b922542f52af09e058f8fa85ab
Author: Lennart Poettering <lennart at poettering.net>
Date: Sun Apr 5 11:26:58 2015 +0200
path-util: don't eat up ENOENT in path_is_mount_point()
There's no reason to eat up ENOENT, it should be OK to simply report the
error back.
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 8487d26..a01475a 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -496,8 +496,6 @@ int fd_is_mount_point(int fd) {
* mount point), otherwise fallback to the
* traditional stat() logic */
nosupp = true;
- else if (errno == ENOENT)
- return 0;
else
return -errno;
}
@@ -537,12 +535,8 @@ int fd_is_mount_point(int fd) {
fallback:
r = fstatat(fd, "", &a, AT_EMPTY_PATH);
- if (r < 0) {
- if (errno == ENOENT)
- return 0;
-
+ if (r < 0)
return -errno;
- }
r = fstatat(fd, "..", &b, 0);
if (r < 0)
@@ -559,18 +553,15 @@ fallback:
int path_is_mount_point(const char *t, bool allow_symlink) {
_cleanup_close_ int fd = -1;
+
assert(t);
if (path_equal(t, "/"))
return 1;
fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH));
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
-
+ if (fd < 0)
return -errno;
- }
return fd_is_mount_point(fd);
}
commit 05d990efd7dda29835cfe9e4c03d5864b055b58b
Author: Lennart Poettering <lennart at poettering.net>
Date: Sun Apr 5 11:12:16 2015 +0200
path-util: make sure fd_is_mount_point() returns true for root directory
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index e485c8e..8487d26 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -471,12 +471,14 @@ char* path_join(const char *root, const char *path, const char *rest) {
}
int fd_is_mount_point(int fd) {
- union file_handle_union h = FILE_HANDLE_INIT;
+ union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
bool nosupp = false;
struct stat a, b;
int r;
+ assert(fd >= 0);
+
/* We are not actually interested in the file handles, but
* name_to_handle_at() also passes us the mount ID, hence use
* it but throw the handle away */
@@ -500,8 +502,7 @@ int fd_is_mount_point(int fd) {
return -errno;
}
- h.handle.handle_bytes = MAX_HANDLE_SZ;
- r = name_to_handle_at(fd, "..", &h.handle, &mount_id_parent, 0);
+ r = name_to_handle_at(fd, "..", &h_parent.handle, &mount_id_parent, 0);
if (r < 0) {
if (errno == EOPNOTSUPP) {
if (nosupp)
@@ -520,8 +521,19 @@ int fd_is_mount_point(int fd) {
* directory we are interested in can't? If so, it
* must be a mount point. */
return 1;
- else
+ else {
+ /* If the file handle for the directory we are
+ * interested in and its parent are identical, we
+ * assume this is the root directory, which is a mount
+ * point. */
+
+ if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
+ h.handle.handle_type == h_parent.handle.handle_type &&
+ memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
+ return 1;
+
return mount_id != mount_id_parent;
+ }
fallback:
r = fstatat(fd, "", &a, AT_EMPTY_PATH);
@@ -536,6 +548,12 @@ fallback:
if (r < 0)
return -errno;
+ /* A directory with same device and inode as its parent? Must
+ * be the root directory */
+ if (a.st_dev == b.st_dev &&
+ a.st_ino == b.st_ino)
+ return 1;
+
return a.st_dev != b.st_dev;
}
commit 9e9b663aae201c24ba4f673cf77ee6bebe4edaa6
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Apr 4 19:22:00 2015 +0200
rm-rf: add support for recursively removing btrfs subvolumes
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c
index eeb2e39..50112e3 100644
--- a/src/shared/rm-rf.c
+++ b/src/shared/rm-rf.c
@@ -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 */
diff --git a/src/shared/rm-rf.h b/src/shared/rm-rf.h
index 769bbc8..96579eb 100644
--- a/src/shared/rm-rf.h
+++ b/src/shared/rm-rf.h
@@ -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);
commit 8f06b239f2a41310582f9d1932778afbc0c9c9f6
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Apr 4 19:20:56 2015 +0200
path-util: if parent can do name_to_handle() but relevant dir not, it's a mount point
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 6a984fc..e485c8e 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -515,7 +515,12 @@ int fd_is_mount_point(int fd) {
return 1;
} else
return -errno;
- } else
+ } else if (nosupp)
+ /* The parent can do name_to_handle_at() but the
+ * directory we are interested in can't? If so, it
+ * must be a mount point. */
+ return 1;
+ else
return mount_id != mount_id_parent;
fallback:
commit f25afeb6ab515cf890eff58c0b53cf35b2be0e05
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Apr 4 14:42:39 2015 +0200
rm-rf: never cross mount points
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 53c0079..6a984fc 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -470,30 +470,17 @@ char* path_join(const char *root, const char *path, const char *rest) {
NULL);
}
-int path_is_mount_point(const char *t, bool allow_symlink) {
-
+int fd_is_mount_point(int fd) {
union file_handle_union h = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
+ bool nosupp = false;
struct stat a, b;
int r;
- _cleanup_close_ int fd = -1;
- bool nosupp = false;
/* We are not actually interested in the file handles, but
* name_to_handle_at() also passes us the mount ID, hence use
* it but throw the handle away */
- if (path_equal(t, "/"))
- return 1;
-
- fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH));
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
-
- return -errno;
- }
-
r = name_to_handle_at(fd, "", &h.handle, &mount_id, AT_EMPTY_PATH);
if (r < 0) {
if (errno == ENOSYS)
@@ -502,7 +489,9 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
goto fallback;
else if (errno == EOPNOTSUPP)
/* This kernel or file system does not support
- * name_to_handle_at(), hence fallback to the
+ * name_to_handle_at(), hence let's see if the
+ * upper fs supports it (in which case it is a
+ * mount point), otherwise fallback to the
* traditional stat() logic */
nosupp = true;
else if (errno == ENOENT)
@@ -511,29 +500,26 @@ int path_is_mount_point(const char *t, bool allow_symlink) {
return -errno;
}
-
h.handle.handle_bytes = MAX_HANDLE_SZ;
r = name_to_handle_at(fd, "..", &h.handle, &mount_id_parent, 0);
- if (r < 0)
- if (errno == EOPNOTSUPP)
+ if (r < 0) {
+ if (errno == EOPNOTSUPP) {
if (nosupp)
/* Neither parent nor child do name_to_handle_at()?
We have no choice but to fall back. */
goto fallback;
else
- /* The parent can't do name_to_handle_at() but
- * the directory we are interested in can?
- * Or the other way around?
+ /* The parent can't do name_to_handle_at() but the
+ * directory we are interested in can?
* If so, it must be a mount point. */
return 1;
- else
+ } else
return -errno;
- else
+ } else
return mount_id != mount_id_parent;
fallback:
r = fstatat(fd, "", &a, AT_EMPTY_PATH);
-
if (r < 0) {
if (errno == ENOENT)
return 0;
@@ -541,7 +527,6 @@ fallback:
return -errno;
}
-
r = fstatat(fd, "..", &b, 0);
if (r < 0)
return -errno;
@@ -549,6 +534,24 @@ fallback:
return a.st_dev != b.st_dev;
}
+int path_is_mount_point(const char *t, bool allow_symlink) {
+ _cleanup_close_ int fd = -1;
+ assert(t);
+
+ if (path_equal(t, "/"))
+ return 1;
+
+ fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH));
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ return -errno;
+ }
+
+ return fd_is_mount_point(fd);
+}
+
int path_is_read_only_fs(const char *path) {
struct statvfs st;
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index ca81b49..5548ce4 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -53,6 +53,7 @@ char** path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
+int fd_is_mount_point(int fd);
int path_is_mount_point(const char *path, bool allow_symlink);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c
index 99d12b1..eeb2e39 100644
--- a/src/shared/rm-rf.c
+++ b/src/shared/rm-rf.c
@@ -89,7 +89,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
if (is_dir) {
int subdir_fd;
- /* if root_dev is set, remove subdirectories only, if device is same as dir */
+ /* if root_dev is set, remove subdirectories only if device is same */
if (root_dev && st.st_dev != root_dev->st_dev)
continue;
@@ -100,6 +100,20 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
continue;
}
+ /* Stop at mount points */
+ r = fd_is_mount_point(subdir_fd);
+ if (r < 0) {
+ if (ret == 0 && r != -ENOENT)
+ ret = r;
+
+ safe_close(subdir_fd);
+ continue;
+ }
+ if (r) {
+ 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 */
@@ -162,7 +176,6 @@ int rm_rf(const char *path, RemoveFlags flags) {
r = rm_rf_children(fd, flags, NULL);
if (flags & REMOVE_ROOT) {
-
if (rmdir(path) < 0 && errno != ENOENT) {
if (r == 0)
r = -errno;
commit c6878637502b1717a110a9a7e8bba32a8583fcdf
Author: Lennart Poettering <lennart at poettering.net>
Date: Sat Apr 4 11:52:57 2015 +0200
util: rework rm_rf() logic
- Move to its own file rm-rf.c
- Change parameters into a single flags parameter
- Remove "honour sticky" logic, it's unused these days
diff --git a/Makefile.am b/Makefile.am
index 1b64b62..4973d84 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -771,6 +771,8 @@ libsystemd_shared_la_SOURCES = \
src/shared/device-nodes.h \
src/shared/util.c \
src/shared/util.h \
+ src/shared/rm-rf.c \
+ src/shared/rm-rf.h \
src/shared/virt.c \
src/shared/virt.h \
src/shared/architecture.c \
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index bc14051..001cfa7 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -41,6 +41,7 @@
#include "efivars.h"
#include "build.h"
#include "util.h"
+#include "rm-rf.h"
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
struct statfs sfs;
@@ -1095,7 +1096,7 @@ static int remove_binaries(const char *esp_path) {
return -ENOMEM;
}
- r = rm_rf(p, false, false, false);
+ r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
free(p);
q = remove_boot_efi(esp_path);
diff --git a/src/core/execute.c b/src/core/execute.c
index 02df51b..768a32b 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -49,6 +49,7 @@
#include <sys/apparmor.h>
#endif
+#include "rm-rf.h"
#include "execute.h"
#include "strv.h"
#include "macro.h"
@@ -2020,7 +2021,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p
/* We execute this synchronously, since we need to be
* sure this is gone when we start the service
* next. */
- rm_rf(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT);
}
return 0;
@@ -2846,7 +2847,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
static void *remove_tmpdir_thread(void *p) {
_cleanup_free_ char *path = p;
- rm_rf_dangerous(path, false, true, false);
+ (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
return NULL;
}
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 7505dcb..2ffb2a7 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -313,7 +313,7 @@ int machine_id_commit(const char *root) {
if (r < 0)
return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
- r = is_fd_on_temporary_fs(fd);
+ r = fd_is_temporary_fs(fd);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
if (r == 0) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 1afd359..73417ab 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -52,6 +52,7 @@
#include "locale-setup.h"
#include "unit-name.h"
#include "missing.h"
+#include "rm-rf.h"
#include "path-lookup.h"
#include "special.h"
#include "exit-status.h"
@@ -2881,7 +2882,7 @@ static void remove_generator_dir(Manager *m, char **generator) {
return;
strv_remove(m->lookup_paths.unit_path, *generator);
- rm_rf(*generator, false, true, false);
+ (void) rm_rf(*generator, REMOVE_ROOT);
free(*generator);
*generator = NULL;
diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c
index c1301cd..18c42b8 100644
--- a/src/import/aufs-util.c
+++ b/src/import/aufs-util.c
@@ -22,6 +22,7 @@
#include <ftw.h>
#include "util.h"
+#include "rm-rf.h"
#include "aufs-util.h"
static int nftw_cb(
@@ -43,7 +44,7 @@ static int nftw_cb(
return FTW_CONTINUE;
log_debug("Removing whiteout indicator %s.", fpath);
- r = rm_rf_dangerous(fpath, false, true, false);
+ r = rm_rf(fpath, REMOVE_ROOT|REMOVE_PHYSICAL);
if (r < 0)
return FTW_STOP;
@@ -53,7 +54,7 @@ static int nftw_cb(
strcpy(mempcpy(p, fpath, ftwbuf->base), original);
log_debug("Removing deleted file %s.", p);
- r = rm_rf_dangerous(p, false, true, false);
+ r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
if (r < 0)
return FTW_STOP;
}
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 7d1ac2a..3a31513 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -28,6 +28,7 @@
#include "btrfs-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "ratelimit.h"
#include "machine-pool.h"
#include "qcow2-util.h"
@@ -242,7 +243,7 @@ static int raw_import_finish(RawImport *i) {
if (i->force_local) {
(void) btrfs_subvol_remove(i->final_path);
- (void) rm_rf_dangerous(i->final_path, false, true, false);
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
diff --git a/src/import/import-tar.c b/src/import/import-tar.c
index ef2345c..c5346ca 100644
--- a/src/import/import-tar.c
+++ b/src/import/import-tar.c
@@ -28,6 +28,7 @@
#include "btrfs-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "ratelimit.h"
#include "machine-pool.h"
#include "qcow2-util.h"
@@ -87,7 +88,7 @@ TarImport* tar_import_unref(TarImport *i) {
if (i->temp_path) {
(void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf_dangerous(i->temp_path, false, true, false);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
free(i->temp_path);
}
@@ -198,7 +199,7 @@ static int tar_import_finish(TarImport *i) {
if (i->force_local) {
(void) btrfs_subvol_remove(i->final_path);
- (void) rm_rf_dangerous(i->final_path, false, true, false);
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index 94dd54b..d4cebe2 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -24,6 +24,7 @@
#include "util.h"
#include "strv.h"
#include "copy.h"
+#include "rm-rf.h"
#include "btrfs-util.h"
#include "capability.h"
#include "pull-job.h"
@@ -125,7 +126,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
if (force_local) {
(void) btrfs_subvol_remove(p);
- (void) rm_rf_dangerous(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
}
r = btrfs_subvol_snapshot(final, p, false, false);
@@ -418,7 +419,7 @@ finish:
unlink(sig_file_path);
if (gpg_home_created)
- rm_rf_dangerous(gpg_home, false, true, false);
+ (void) rm_rf(gpg_home, REMOVE_ROOT|REMOVE_PHYSICAL);
return r;
}
diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c
index 1a7dc31..a1e6fe8 100644
--- a/src/import/pull-dkr.c
+++ b/src/import/pull-dkr.c
@@ -28,6 +28,7 @@
#include "btrfs-util.h"
#include "utf8.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "path-util.h"
#include "import-util.h"
#include "curl-util.h"
@@ -111,7 +112,7 @@ DkrPull* dkr_pull_unref(DkrPull *i) {
if (i->temp_path) {
(void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf_dangerous(i->temp_path, false, true, false);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
free(i->temp_path);
}
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index c0c6d57..e10b280 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -31,6 +31,7 @@
#include "util.h"
#include "macro.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "path-util.h"
#include "import-util.h"
#include "import-common.h"
@@ -278,7 +279,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
if (i->force_local) {
(void) btrfs_subvol_remove(p);
- (void) rm_rf_dangerous(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
}
r = tempfn_random(p, &tp);
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index 58cafdd..60dc22f 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -30,6 +30,7 @@
#include "util.h"
#include "macro.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "path-util.h"
#include "import-util.h"
#include "import-common.h"
@@ -88,7 +89,7 @@ TarPull* tar_pull_unref(TarPull *i) {
if (i->temp_path) {
(void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf_dangerous(i->temp_path, false, true, false);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL);
free(i->temp_path);
}
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 2488884..78d5b22 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -31,6 +31,7 @@
#include "sd-messages.h"
#include "sd-daemon.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "hashmap.h"
#include "journal-file.h"
#include "socket-util.h"
@@ -1088,7 +1089,7 @@ finish:
s->runtime_journal = NULL;
if (r >= 0)
- rm_rf("/run/log/journal", false, true, false);
+ (void) rm_rf("/run/log/journal", REMOVE_ROOT);
sd_journal_close(j);
diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c
index 11fb150..e6599f3 100644
--- a/src/journal/test-journal-init.c
+++ b/src/journal/test-journal-init.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "util.h"
+#include "rm-rf.h"
int main(int argc, char *argv[]) {
sd_journal *j;
@@ -58,7 +59,7 @@ int main(int argc, char *argv[]) {
assert_se(j == NULL);
}
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 3e61417..c2fc123 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -23,12 +23,12 @@
#include <unistd.h>
#include <fcntl.h>
-#include "systemd/sd-journal.h"
-
+#include "sd-journal.h"
#include "journal-file.h"
#include "journal-vacuum.h"
#include "util.h"
#include "log.h"
+#include "rm-rf.h"
/* This program tests skipping around in a multi-file journal.
*/
@@ -190,7 +190,7 @@ static void test_skip(void (*setup)(void)) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
puts("------------------------------------------------------------");
@@ -275,7 +275,7 @@ static void test_sequence_numbers(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
}
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index b8caeb3..e1146c6 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -22,13 +22,13 @@
#include <unistd.h>
#include <fcntl.h>
-#include "systemd/sd-journal.h"
-
-#include "journal-file.h"
-#include "journal-internal.h"
+#include "sd-journal.h"
#include "util.h"
#include "log.h"
#include "macro.h"
+#include "rm-rf.h"
+#include "journal-file.h"
+#include "journal-internal.h"
#define N_ENTRIES 200
@@ -180,7 +180,7 @@ int main(int argc, char *argv[]) {
SD_JOURNAL_FOREACH_UNIQUE(j, data, l)
printf("%.*s\n", (int) l, (const char*) data);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index de9cd9c..8008f74 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -25,6 +25,7 @@
#include "util.h"
#include "log.h"
+#include "rm-rf.h"
#include "journal-file.h"
#include "journal-verify.h"
@@ -144,7 +145,7 @@ int main(int argc, char *argv[]) {
log_info("Exiting...");
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index f7cc75b..caaab25 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -22,8 +22,8 @@
#include <fcntl.h>
#include <unistd.h>
-
#include "log.h"
+#include "rm-rf.h"
#include "journal-file.h"
#include "journal-authenticate.h"
#include "journal-vacuum.h"
@@ -118,7 +118,7 @@ static void test_non_empty(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
puts("------------------------------------------------------------");
@@ -157,7 +157,7 @@ static void test_empty(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
journal_file_close(f1);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 294c1e7..cba9cb6 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -26,6 +26,7 @@
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "hashmap.h"
#include "fileio.h"
#include "path-util.h"
@@ -521,7 +522,7 @@ static int user_remove_runtime_path(User *u) {
if (!u->runtime_path)
return 0;
- r = rm_rf(u->runtime_path, false, false, false);
+ r = rm_rf(u->runtime_path, 0);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
@@ -532,7 +533,7 @@ static int user_remove_runtime_path(User *u) {
if (r < 0 && errno != EINVAL && errno != ENOENT)
log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
- r = rm_rf(u->runtime_path, false, true, false);
+ r = rm_rf(u->runtime_path, REMOVE_ROOT);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 7e56cf2..730541a 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -59,6 +59,7 @@
#include "log.h"
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "macro.h"
#include "missing.h"
#include "cgroup-util.h"
@@ -4467,7 +4468,7 @@ finish:
const char *p;
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
- (void) rm_rf(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT);
}
free(arg_directory);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index edf986d..c5808af 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -28,6 +28,7 @@
#include "path-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "machine-image.h"
static const char image_search_path[] =
@@ -366,7 +367,7 @@ int image_remove(Image *i) {
/* fall through */
case IMAGE_RAW:
- return rm_rf_dangerous(i->path, false, true, false);
+ return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL);
default:
return -EOPNOTSUPP;
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c
new file mode 100644
index 0000000..99d12b1
--- /dev/null
+++ b/src/shared/rm-rf.c
@@ -0,0 +1,173 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+
+int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
+ _cleanup_closedir_ DIR *d = NULL;
+ int ret = 0, r;
+
+ assert(fd >= 0);
+
+ /* This returns the first error we run into, but nevertheless
+ * tries to go on. This closes the passed fd. */
+
+ if (!(flags & REMOVE_PHYSICAL)) {
+
+ r = fd_is_temporary_fs(fd);
+ if (r < 0) {
+ safe_close(fd);
+ return r;
+ }
+
+ if (!r) {
+ /* We refuse to clean physical file systems
+ * with this call, unless explicitly
+ * requested. This is extra paranoia just to
+ * be sure we never ever remove non-state
+ * data */
+
+ log_error("Attempted to remove disk file system, and we can't allow that.");
+ safe_close(fd);
+ return -EPERM;
+ }
+ }
+
+ d = fdopendir(fd);
+ if (!d) {
+ safe_close(fd);
+ return errno == ENOENT ? 0 : -errno;
+ }
+
+ for (;;) {
+ struct dirent *de;
+ bool is_dir;
+ struct stat st;
+
+ errno = 0;
+ de = readdir(d);
+ if (!de) {
+ if (errno != 0 && ret == 0)
+ ret = -errno;
+ return ret;
+ }
+
+ if (streq(de->d_name, ".") || streq(de->d_name, ".."))
+ continue;
+
+ if (de->d_type == DT_UNKNOWN || (de->d_type == DT_DIR && root_dev)) {
+ if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
+
+ is_dir = S_ISDIR(st.st_mode);
+ } else
+ is_dir = de->d_type == DT_DIR;
+
+ if (is_dir) {
+ int subdir_fd;
+
+ /* if root_dev is set, remove subdirectories only, if device is same as dir */
+ if (root_dev && st.st_dev != root_dev->st_dev)
+ continue;
+
+ subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
+
+ /* We pass REMOVE_PHYSICAL here, to avoid
+ * doing the fstatfs() to check the file
+ * system type again for each directory */
+ r = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev);
+ if (r < 0 && ret == 0)
+ ret = r;
+
+ if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+
+ } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
+
+ if (unlinkat(fd, de->d_name, 0) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+ }
+ }
+}
+
+int rm_rf(const char *path, RemoveFlags flags) {
+ int fd, r;
+ struct statfs s;
+
+ assert(path);
+
+ /* 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(path, "/")) {
+ log_error("Attempted to remove entire root file system, and we can't allow that.");
+ return -EPERM;
+ }
+
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (fd < 0) {
+
+ if (errno != ENOTDIR && errno != ELOOP)
+ return -errno;
+
+ if (!(flags & REMOVE_PHYSICAL)) {
+ if (statfs(path, &s) < 0)
+ return -errno;
+
+ if (!is_temporary_fs(&s)) {
+ log_error("Attempted to remove disk file system, and we can't allow that.");
+ return -EPERM;
+ }
+ }
+
+ 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 && errno != ENOENT) {
+ if (r == 0)
+ r = -errno;
+ }
+ }
+
+ return r;
+}
diff --git a/src/shared/rm-rf.h b/src/shared/rm-rf.h
new file mode 100644
index 0000000..769bbc8
--- /dev/null
+++ b/src/shared/rm-rf.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/stat.h>
+
+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 */
+} RemoveFlags;
+
+int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
+int rm_rf(const char *path, RemoveFlags flags);
diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c
index 813641a..ae3839d 100644
--- a/src/shared/switch-root.c
+++ b/src/shared/switch-root.c
@@ -29,10 +29,11 @@
#include "util.h"
#include "path-util.h"
-#include "switch-root.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "base-filesystem.h"
#include "missing.h"
+#include "switch-root.h"
int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) {
@@ -142,7 +143,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
if (fstat(old_root_fd, &rb) < 0)
log_warning_errno(errno, "Failed to stat old root directory, leaving: %m");
else {
- rm_rf_children(old_root_fd, false, false, &rb);
+ (void) rm_rf_children(old_root_fd, 0, &rb);
old_root_fd = -1;
}
}
diff --git a/src/shared/util.c b/src/shared/util.c
index 605fffc..8b011cc 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2988,101 +2988,14 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
-int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
- _cleanup_closedir_ DIR *d = NULL;
- int ret = 0;
-
- assert(fd >= 0);
-
- /* This returns the first error we run into, but nevertheless
- * tries to go on. This closes the passed fd. */
-
- d = fdopendir(fd);
- if (!d) {
- safe_close(fd);
-
- return errno == ENOENT ? 0 : -errno;
- }
-
- for (;;) {
- struct dirent *de;
- bool is_dir, keep_around;
- struct stat st;
- int r;
-
- errno = 0;
- de = readdir(d);
- if (!de) {
- if (errno != 0 && ret == 0)
- ret = -errno;
- return ret;
- }
-
- if (streq(de->d_name, ".") || streq(de->d_name, ".."))
- continue;
-
- if (de->d_type == DT_UNKNOWN ||
- honour_sticky ||
- (de->d_type == DT_DIR && root_dev)) {
- if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
-
- is_dir = S_ISDIR(st.st_mode);
- keep_around =
- honour_sticky &&
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
- } else {
- is_dir = de->d_type == DT_DIR;
- keep_around = false;
- }
-
- if (is_dir) {
- int subdir_fd;
-
- /* if root_dev is set, remove subdirectories only, if device is same as dir */
- if (root_dev && st.st_dev != root_dev->st_dev)
- continue;
-
- subdir_fd = openat(fd, de->d_name,
- O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (subdir_fd < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
-
- r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev);
- if (r < 0 && ret == 0)
- ret = r;
-
- if (!keep_around)
- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- }
-
- } else if (!only_dirs && !keep_around) {
-
- if (unlinkat(fd, de->d_name, 0) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- }
- }
- }
-}
-
-_pure_ static int is_temporary_fs(struct statfs *s) {
+bool is_temporary_fs(const struct statfs *s) {
assert(s);
return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
-int is_fd_on_temporary_fs(int fd) {
+int fd_is_temporary_fs(int fd) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
@@ -3091,114 +3004,6 @@ int is_fd_on_temporary_fs(int fd) {
return is_temporary_fs(&s);
}
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
- struct statfs s;
-
- assert(fd >= 0);
-
- if (fstatfs(fd, &s) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- /* We refuse to clean disk file systems with this call. This
- * is extra paranoia just to be sure we never ever remove
- * non-state data */
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- safe_close(fd);
- return -EPERM;
- }
-
- return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
-}
-
-static int file_is_priv_sticky(const char *p) {
- struct stat st;
-
- assert(p);
-
- if (lstat(p, &st) < 0)
- return -errno;
-
- return
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
-}
-
-static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
- int fd, r;
- struct statfs s;
-
- assert(path);
-
- /* 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(path, "/")) {
- log_error("Attempted to remove entire root file system, and we can't allow that.");
- return -EPERM;
- }
-
- fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (fd < 0) {
-
- if (errno != ENOTDIR && errno != ELOOP)
- return -errno;
-
- if (!dangerous) {
- if (statfs(path, &s) < 0)
- return -errno;
-
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- return -EPERM;
- }
- }
-
- if (delete_root && !only_dirs)
- if (unlink(path) < 0 && errno != ENOENT)
- return -errno;
-
- return 0;
- }
-
- if (!dangerous) {
- if (fstatfs(fd, &s) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- safe_close(fd);
- return -EPERM;
- }
- }
-
- r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
- if (delete_root) {
-
- if (honour_sticky && file_is_priv_sticky(path) > 0)
- return r;
-
- if (rmdir(path) < 0 && errno != ENOENT) {
- if (r == 0)
- r = -errno;
- }
- }
-
- return r;
-}
-
-int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
- return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
-}
-
-int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
- return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
-}
-
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
assert(path);
diff --git a/src/shared/util.h b/src/shared/util.h
index 124c7c0..8823556 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -41,6 +41,7 @@
#include <locale.h>
#include <mntent.h>
#include <sys/inotify.h>
+#include <sys/statfs.h>
#if SIZEOF_PID_T == 4
# define PID_PRI PRIi32
@@ -461,12 +462,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
-int is_fd_on_temporary_fs(int fd);
-
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
-int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
-int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
-int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
+bool is_temporary_fs(const struct statfs *s) _pure_;
+int fd_is_temporary_fs(int fd);
int pipe_eof(int fd);
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index 894c7f7..01ece02 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -26,7 +26,7 @@
#include "macro.h"
#include "strv.h"
#include "util.h"
-
+#include "rm-rf.h"
static void setup_test_dir(char *tmp_dir, const char *files, ...) {
va_list ap;
@@ -74,7 +74,7 @@ static void test_conf_files_list(bool use_root) {
assert_se(streq_ptr(found_files[1], expect_b));
assert_se(found_files[2] == NULL);
- assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
int main(int argc, char **argv) {
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index 5c96f61..403d85b 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -26,6 +26,7 @@
#include "strv.h"
#include "macro.h"
#include "util.h"
+#include "rm-rf.h"
static void test_copy_file(void) {
_cleanup_free_ char *buf = NULL;
@@ -86,8 +87,8 @@ static void test_copy_tree(void) {
"link2", "dir1/file");
char **p, **link;
- rm_rf_dangerous(copy_dir, false, true, false);
- rm_rf_dangerous(original_dir, false, true, false);
+ (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
STRV_FOREACH(p, files) {
char *f = strjoina(original_dir, *p);
@@ -128,8 +129,8 @@ static void test_copy_tree(void) {
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
- rm_rf_dangerous(copy_dir, false, true, false);
- rm_rf_dangerous(original_dir, false, true, false);
+ (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
}
int main(int argc, char *argv[]) {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 428fd32..c6210aa 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -24,6 +24,7 @@
#include "util.h"
#include "macro.h"
#include "mkdir.h"
+#include "rm-rf.h"
typedef void (*test_function_t)(Manager *m);
@@ -72,7 +73,7 @@ static void test_exec_workingdirectory(Manager *m) {
test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
- rm_rf_dangerous("/tmp/test-exec_workingdirectory", false, true, false);
+ (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_exec_personality(Manager *m) {
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index a951b01..66b0b99 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -24,6 +24,7 @@
#include "path-lookup.h"
#include "log.h"
#include "strv.h"
+#include "rm-rf.h"
static void test_paths(SystemdRunningAs running_as, bool personal) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
@@ -42,7 +43,7 @@ static void test_paths(SystemdRunningAs running_as, bool personal) {
assert_se(strv_contains(lp.unit_path, exists));
assert_se(strv_contains(lp.unit_path, not));
- assert_se(rm_rf_dangerous(template, false, true, false) >= 0);
+ assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void print_generator_paths(SystemdRunningAs running_as) {
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 6396fcb..759515e 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -26,6 +26,7 @@
#include "util.h"
#include "macro.h"
#include "strv.h"
+#include "rm-rf.h"
#define test_path_compare(a, b, result) { \
assert_se(path_compare(a, b) == result); \
@@ -256,7 +257,7 @@ static void test_strv_resolve(void) {
assert_se(streq(search_dirs[1], "/dir2"));
assert_se(streq(search_dirs[2], "/dir2"));
- assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
static void test_path_startswith(void) {
diff --git a/src/test/test-path.c b/src/test/test-path.c
index a3295aa..219b585 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -26,6 +26,7 @@
#include "macro.h"
#include "strv.h"
#include "mkdir.h"
+#include "rm-rf.h"
typedef void (*test_function_t)(Manager *m);
@@ -47,7 +48,12 @@ static int setup_test(Manager **m) {
assert_se(manager_startup(tmp, NULL, NULL) >= 0);
STRV_FOREACH(test_path, tests_path) {
- rm_rf_dangerous(strjoina("/tmp/test-path_", *test_path), false, true, false);
+ _cleanup_free_ char *p = NULL;
+
+ p = strjoin("/tmp/test-path_", *test_path, NULL);
+ assert_se(p);
+
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
}
*m = tmp;
@@ -104,7 +110,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con
}
assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
- rm_rf_dangerous(test_path, false, true, false);
+ (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_path_exists(Manager *m) {
@@ -228,7 +234,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
assert_se((s.st_mode & S_IRWXO) == 0004);
assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
- rm_rf_dangerous(test_path, false, true, false);
+ (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
int main(int argc, char *argv[]) {
diff --git a/src/test/test-util.c b/src/test/test-util.c
index d32ddd3..e9d1522 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -31,6 +31,7 @@
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "strv.h"
#include "def.h"
#include "fileio.h"
@@ -1017,7 +1018,7 @@ static void test_readlink_and_make_absolute(void) {
free(r);
assert_se(unlink(name_alias) >= 0);
- assert_se(rm_rf_dangerous(tempdir, false, true, false) >= 0);
+ assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void test_read_one_char(void) {
@@ -1274,8 +1275,8 @@ static void test_execute_directory(void) {
assert_se(access("it_works2", F_OK) >= 0);
assert_se(access("failed", F_OK) < 0);
- rm_rf_dangerous(template_lo, false, true, false);
- rm_rf_dangerous(template_hi, false, true, false);
+ (void) rm_rf(template_lo, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_unquote_first_word(void) {
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 494fd1a..20972f6 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -52,6 +52,7 @@
#include "specifier.h"
#include "build.h"
#include "copy.h"
+#include "rm-rf.h"
#include "selinux-util.h"
#include "btrfs-util.h"
#include "acl-util.h"
@@ -1359,7 +1360,7 @@ static int remove_item_instance(Item *i, const char *instance) {
/* FIXME: we probably should use dir_cleanup() here
* instead of rm_rf() so that 'x' is honoured. */
log_debug("rm -rf \"%s\"", instance);
- r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
+ r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT : 0) | REMOVE_PHYSICAL);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "rm_rf(%s): %m", instance);
commit 2f653bded321fc2271edcda43d54fcc3e6c20dc9
Author: Lennart Poettering <lennart at poettering.net>
Date: Fri Apr 3 15:10:20 2015 +0200
update TODO
diff --git a/TODO b/TODO
index 40d7d78..6d5dd76 100644
--- a/TODO
+++ b/TODO
@@ -49,6 +49,12 @@ Before 220:
Features:
+* Maybe add support for the equivalent of "ethtool advertise" to .link files?
+ http://lists.freedesktop.org/archives/systemd-devel/2015-April/030112.html
+
+* fstab-generator should generate systemd-fsck-root.service when
+ running in the initrd, and operate on the right device.
+
* the default stop timeout for units is not documented anywhere.
* .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC
More information about the systemd-commits
mailing list