summaryrefslogtreecommitdiff
path: root/sys-utils/switch_root.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys-utils/switch_root.c')
-rw-r--r--sys-utils/switch_root.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c
index f26f7dae4..975360f01 100644
--- a/sys-utils/switch_root.c
+++ b/sys-utils/switch_root.c
@@ -23,6 +23,7 @@
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <sys/param.h>
#include <fcntl.h>
#include <stdio.h>
@@ -45,6 +46,10 @@
#define MNT_DETACH 0x00000002 /* Just detach from the tree */
#endif
+#define STATFS_RAMFS_MAGIC 0x858458f6
+#define STATFS_TMPFS_MAGIC 0x01021994
+
+
/* remove all files/directories below dirName -- don't cross mountpoints */
static int recursiveRemove(int fd)
{
@@ -68,6 +73,7 @@ static int recursiveRemove(int fd)
while(1) {
struct dirent *d;
+ int isdir = 0;
errno = 0;
if (!(d = readdir(dir))) {
@@ -80,8 +86,10 @@ static int recursiveRemove(int fd)
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
-
- if (d->d_type == DT_DIR) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN)
+#endif
+ {
struct stat sb;
if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
@@ -90,7 +98,7 @@ static int recursiveRemove(int fd)
}
/* remove subdirectories if device is same as dir */
- if (sb.st_dev == rb.st_dev) {
+ if (S_ISDIR(sb.st_mode) && sb.st_dev == rb.st_dev) {
int cfd;
cfd = openat(dfd, d->d_name, O_RDONLY);
@@ -98,12 +106,12 @@ static int recursiveRemove(int fd)
recursiveRemove(cfd);
close(cfd);
}
+ isdir = 1;
} else
continue;
}
- if (unlinkat(dfd, d->d_name,
- d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
+ if (unlinkat(dfd, d->d_name, isdir ? AT_REMOVEDIR : 0))
warn(_("failed to unlink %s"), d->d_name);
}
@@ -174,12 +182,13 @@ static int switchroot(const char *newroot)
if (cfd >= 0) {
pid = fork();
if (pid <= 0) {
- if (fstat(cfd, &sb) == 0) {
- if (sb.st_dev == makedev(0, 1))
- recursiveRemove(cfd);
- else
- warn(_("old root filesystem is not an initramfs"));
- }
+ struct statfs stfs;
+ if (fstatfs(cfd, &stfs) == 0 &&
+ (stfs.f_type == STATFS_RAMFS_MAGIC ||
+ stfs.f_type == STATFS_TMPFS_MAGIC))
+ recursiveRemove(cfd);
+ else
+ warn(_("old root filesystem is not an initramfs"));
if (pid == 0)
exit(EXIT_SUCCESS);