From 82476a9080f1ce8d1d8701f1b2c879c1e5b7523c Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 19 Jun 2009 15:21:58 -0400 Subject: 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 Signed-off-by: Karel Zak --- sys-utils/switch_root.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'sys-utils/switch_root.c') 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); -- cgit v1.2.3-55-g7522