summaryrefslogtreecommitdiffstats
path: root/sys-utils/switch_root.c
diff options
context:
space:
mode:
authorPeter Jones2009-06-19 21:21:58 +0200
committerKarel Zak2009-06-22 21:38:12 +0200
commit82476a9080f1ce8d1d8701f1b2c879c1e5b7523c (patch)
tree1eb9a4ee4936b8aa11bc20808e62acd7eee6ed31 /sys-utils/switch_root.c
parentswitch_root: add man page (diff)
downloadkernel-qcow2-util-linux-82476a9080f1ce8d1d8701f1b2c879c1e5b7523c.tar.gz
kernel-qcow2-util-linux-82476a9080f1ce8d1d8701f1b2c879c1e5b7523c.tar.xz
kernel-qcow2-util-linux-82476a9080f1ce8d1d8701f1b2c879c1e5b7523c.zip
switch_root: use file descriptor instead of path for recursiveRemove()
This makes recursiveRemove() use fdopendir() instead of taking a path, so we're always sure about which namespace we're starting from. Signed-off-by: Peter Jones <pjones@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/switch_root.c')
-rw-r--r--sys-utils/switch_root.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c
index 8daacb1d0..75725e707 100644
--- a/sys-utils/switch_root.c
+++ b/sys-utils/switch_root.c
@@ -39,22 +39,23 @@
#endif
/* remove all files/directories below dirName -- don't cross mountpoints */
-static int recursiveRemove(char *dirName)
+static int recursiveRemove(int fd)
{
struct stat rb;
DIR *dir;
int rc = -1;
int dfd;
- if (!(dir = opendir(dirName))) {
- warn("failed to open %s", dirName);
+ if (!(dir = fdopendir(fd))) {
+ warn("failed to open directory");
goto done;
}
+ /* fdopendir() precludes us from continuing to use the input fd */
dfd = dirfd(dir);
if (fstat(dfd, &rb)) {
- warn("failed to stat %s", dirName);
+ warn("failed to stat directory");
goto done;
}
@@ -64,7 +65,7 @@ static int recursiveRemove(char *dirName)
errno = 0;
if (!(d = readdir(dir))) {
if (errno) {
- warn("failed to read %s", dirName);
+ warn("failed to read directory");
goto done;
}
break; /* end of directory */
@@ -77,24 +78,26 @@ static int recursiveRemove(char *dirName)
struct stat sb;
if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
- warn("failed to stat %s/%s", dirName, d->d_name);
+ warn("failed to stat %s", d->d_name);
continue;
}
/* remove subdirectories if device is same as dir */
if (sb.st_dev == rb.st_dev) {
- char subdir[ strlen(dirName) +
- strlen(d->d_name) + 2 ];
+ int cfd;
- sprintf(subdir, "%s/%s", dirName, d->d_name);
- recursiveRemove(subdir);
+ cfd = openat(dfd, d->d_name, O_RDONLY);
+ if (cfd >= 0) {
+ recursiveRemove(cfd);
+ close(cfd);
+ }
} else
continue;
}
if (unlinkat(dfd, d->d_name,
d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
- warn("failed to unlink %s/%s", dirName, d->d_name);
+ warn("failed to unlink %s", d->d_name);
}
rc = 0; /* success */
@@ -110,6 +113,7 @@ static int switchroot(const char *newroot)
/* Don't try to unmount the old "/", there's no way to do it. */
const char *umounts[] = { "/dev", "/proc", "/sys", NULL };
int i;
+ int cfd;
for (i = 0; umounts[i] != NULL; i++) {
char newmount[PATH_MAX];
@@ -129,7 +133,11 @@ static int switchroot(const char *newroot)
return -1;
}
- recursiveRemove("/");
+ cfd = open("/", O_RDONLY);
+ if (cfd >= 0) {
+ recursiveRemove(cfd);
+ close(cfd);
+ }
if (mount(newroot, "/", NULL, MS_MOVE, NULL) < 0) {
warn("failed to mount moving %s to /", newroot);