/* 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_is_root_at(dir_fd, path) > 0)
+ r = path_is_root_at(dir_fd, path);
+ if (r == -ENOENT) {
+ struct stat st;
+
+ if (fstatat(dir_fd, path, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ r = -errno;
+ else
+ r = 0; /* The entry exists, but is most likely a dangling symlink. */
+ }
+ if (FLAGS_SET(flags, REMOVE_MISSING_OK) && r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether '%s' is the root file system: %m", path);
+ if (r > 0)
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Attempted to remove entire root file system, and we can't allow that.");
test_rm_rf_chmod_inner();
}
+TEST(rm_rf_dangling_symlink) {
+ _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
+ const char *link;
+
+ ASSERT_OK(mkdtemp_malloc("/tmp/test-rm-rf-dangling.XXXXXXX", &d));
+ link = strjoina(d, "/link");
+
+ ASSERT_OK_ERRNO(symlink("missing", link));
+ ASSERT_OK(rm_rf(link, REMOVE_ROOT|REMOVE_PHYSICAL));
+ ASSERT_ERROR_ERRNO(lstat(link, &(struct stat) {}), ENOENT);
+
+ ASSERT_OK_ERRNO(symlink("missing", link));
+ ASSERT_OK(rm_rf(link, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK));
+ ASSERT_ERROR_ERRNO(lstat(link, &(struct stat) {}), ENOENT);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);