diff options
Diffstat (limited to 'sys-utils/switch_root.c')
| -rw-r--r-- | sys-utils/switch_root.c | 31 |
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); |
