]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: rework rm_rf() logic
authorLennart Poettering <lennart@poettering.net>
Sat, 4 Apr 2015 09:52:57 +0000 (11:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 6 Apr 2015 08:57:53 +0000 (10:57 +0200)
- Move to its own file rm-rf.c

- Change parameters into a single flags parameter

- Remove "honour sticky" logic, it's unused these days

34 files changed:
Makefile.am
src/boot/bootctl.c
src/core/execute.c
src/core/machine-id-setup.c
src/core/manager.c
src/import/aufs-util.c
src/import/import-raw.c
src/import/import-tar.c
src/import/pull-common.c
src/import/pull-dkr.c
src/import/pull-raw.c
src/import/pull-tar.c
src/journal/journald-server.c
src/journal/test-journal-init.c
src/journal/test-journal-interleaving.c
src/journal/test-journal-stream.c
src/journal/test-journal-verify.c
src/journal/test-journal.c
src/login/logind-user.c
src/nspawn/nspawn.c
src/shared/machine-image.c
src/shared/rm-rf.c [new file with mode: 0644]
src/shared/rm-rf.h [new file with mode: 0644]
src/shared/switch-root.c
src/shared/util.c
src/shared/util.h
src/test/test-conf-files.c
src/test/test-copy.c
src/test/test-execute.c
src/test/test-path-lookup.c
src/test/test-path-util.c
src/test/test-path.c
src/test/test-util.c
src/tmpfiles/tmpfiles.c

index 1b64b6232ea42b8f9dee7a20050927d954ceb536..4973d8418c8e78bf6f0ece513bc96a0ba3bf4415 100644 (file)
@@ -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 \
index bc1405145e5a27670a808409194a30cc27323a27..001cfa76fd7ea8dbacfc0d9f19c4a7cd331675db 100644 (file)
@@ -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);
index 02df51b5bb29f6b0b0b05f83c22c6a5c6813a8f0..768a32b31f7044aae8aea2eb9d12fe0f97d67b08 100644 (file)
@@ -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;
 }
 
index 7505dcbcaa1b97c31c7bab74903b83b523a6a917..2ffb2a7aa6f6d357f47b011d8594063ef53833d9 100644 (file)
@@ -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) {
index 1afd359df256a78787a7672ae3d4300a3a1e6c5e..73417ab1a86825d2ce125e39c8f72a70de734409 100644 (file)
@@ -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;
index c1301cdb4ab50ddeba20b6ad0832cb74d8bd50a4..18c42b8b6d1652db8cc6bcb3c2bf10351db6818d 100644 (file)
@@ -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;
         }
index 7d1ac2afd700749cf6166b70f1d258050ab1ec6b..3a315139e599a68bb3887489c7aa32e5edc8de76 100644 (file)
@@ -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);
index ef2345c7b93a268b8986bd000dc36969a04cb99d..c5346ca2b04e5472b076e884b7db0e01c07ad8a2 100644 (file)
@@ -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);
index 94dd54bd57a0ad914ff6469042be04f7ac46e2ee..d4cebe205efad5b590dc171ffd7a6812849c9b46 100644 (file)
@@ -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;
 }
index 1a7dc310cba82563e9bfe068cc37610e163fa730..a1e6fe8ff71d1eee8b5fb501f7df198684905ce1 100644 (file)
@@ -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);
         }
 
index c0c6d57eadee8d1224f02580dac0b5b0854b3e1b..e10b280b660a79d5fd22dc7b2808386508fae26d 100644 (file)
@@ -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);
index 58cafdd7891d93c3710260ae66402ea12117ef65..60dc22fdfa2bf527ae05510878543a2f51aa834d 100644 (file)
@@ -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);
         }
 
index 2488884634dcbe7bc7541a46edd465326fc64877..78d5b22ae124e984a5721a6e1065d83a50af8668 100644 (file)
@@ -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);
 
index 11fb150fe83744abaa435f9c6b30877408f46d4c..e6599f366d90be1342313287a8da7b41b88b8d9d 100644 (file)
@@ -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;
 }
index 3e6141771c6d0a0e7c7b596ed4484827aae673cb..c2fc123e4207e84b86b8c706c79bb0b65ac33024 100644 (file)
 #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);
         }
 }
 
index b8caeb3d41f0cfab5da6f678307eac26b3088bef..e1146c692d32ee5cb2a61834d5e11c1701fca528 100644 (file)
 #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;
 }
index de9cd9c8b8c8c35e50dadbe4f582089bdf53a416..8008f7455e7e1fffb6ffc8d497b0a2672aaff58d 100644 (file)
@@ -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;
 }
index f7cc75b3d5d948fd8803234a310e39448ace8a37..caaab258c9bb74e2e39e63ff36b2f6c74bed8a76 100644 (file)
@@ -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);
index 294c1e799cdcbf9f00fb1acf2d2dc9be0a0c02cb..cba9cb60aa2dd03d44415b715ea52ae3e2323c23 100644 (file)
@@ -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);
 
index 7e56cf2056c72c03ea0344e7129282d6ebfdfbae..730541af88c99ad40a467d457800cb8f0d192ee1 100644 (file)
@@ -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);
index edf986d4db11801abb0ca47c79b8003793189f3a..c5808af81efe27dfb13cdf6805f9b3b3318a3d25 100644 (file)
@@ -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 (file)
index 0000000..99d12b1
--- /dev/null
@@ -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 (file)
index 0000000..769bbc8
--- /dev/null
@@ -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);
index 813641ad44da59b7c0969c89adc192a40623aceb..ae3839de162c9f4d254c04ce5fe9d274442460ed 100644 (file)
 
 #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;
                 }
         }
index 605fffcb7a711a6a81e5afa9a4703a17115318b8..8b011ccfa1d735d545aebe2770eab0d3888a5895 100644 (file)
@@ -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);
 
index 124c7c06d49348de85c44ad48db61d136ec51535..882355665cf5b62d1dbd820ef54a2f05f3267e00 100644 (file)
@@ -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);
 
index 894c7f742ffb8d3ffc6d17425b86ba673f6b8d70..01ece022c12667d7e4b6f658a0f38fba1495f1bb 100644 (file)
@@ -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) {
index 5c96f610053b6d0dca325ca3458620b9cde5b1a4..403d85bff0fdd35807bb4ff7c69e4a480af0f617 100644 (file)
@@ -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[]) {
index 428fd3260035cf59b102af2d4f0545a0ec0932d7..c6210aaa87b8aadb7fb107b84da3eadbd75817dc 100644 (file)
@@ -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) {
index a951b01b9753764c91d0e21826dd833893947581..66b0b99741ba5427e70d5ad4e4573dc97c95e885 100644 (file)
@@ -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) {
index 6396fcb3980f3eb1348646309cbb7becb1edca53..759515e5648170656bb52aef9c9818f225ea1cbc 100644 (file)
@@ -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) {
index a3295aa997d3997bb565c2fad2da3f6addf48a2a..219b585b7c6de1eb49890265c1600506fdef6fc7 100644 (file)
@@ -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[]) {
index d32ddd3a681f01f0fdb877d80958808db17f4a96..e9d1522a65eb4f9ba373da78a316008d738f51c3 100644 (file)
@@ -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) {
index 494fd1ac212e4e81e030e0b1b7f41610cfc7508e..20972f6310324c19cebf47b889c3bbbf53ba6a63 100644 (file)
@@ -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);