summaryrefslogtreecommitdiffstats
path: root/sys-utils/switch_root.c
diff options
context:
space:
mode:
authorKarel Zak2009-06-09 13:24:11 +0200
committerKarel Zak2009-06-22 21:30:47 +0200
commita6fc8b07f9fff4e055949e2386f8b494201d02ac (patch)
tree284e507b7d193bec200680331632e89b11650493 /sys-utils/switch_root.c
parentswitch_root: fix coding style (diff)
downloadkernel-qcow2-util-linux-a6fc8b07f9fff4e055949e2386f8b494201d02ac.tar.gz
kernel-qcow2-util-linux-a6fc8b07f9fff4e055949e2386f8b494201d02ac.tar.xz
kernel-qcow2-util-linux-a6fc8b07f9fff4e055949e2386f8b494201d02ac.zip
switch_root: rewrite to use fstatat() and unlinkat()
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.c87
1 files changed, 44 insertions, 43 deletions
diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c
index 152038723..3c42c3d11 100644
--- a/sys-utils/switch_root.c
+++ b/sys-utils/switch_root.c
@@ -44,70 +44,71 @@ enum {
};
/* remove all files/directories below dirName -- don't cross mountpoints */
-static int
-recursiveRemove(char * dirName)
+static int recursiveRemove(char *dirName)
{
- struct stat sb,rb;
- DIR * dir;
- struct dirent * d;
- char * strBuf = alloca(strlen(dirName) + 1024);
+ struct stat rb;
+ DIR *dir;
+ int rc = -1;
+ int dfd;
if (!(dir = opendir(dirName))) {
printf("error opening %s: %m\n", dirName);
- return 0;
+ goto done;
}
- if (fstat(dirfd(dir),&rb)) {
+ dfd = dirfd(dir);
+
+ if (fstat(dfd, &rb)) {
printf("unable to stat %s: %m\n", dirName);
- closedir(dir);
- return 0;
+ goto done;
}
- errno = 0;
+ while(1) {
+ struct dirent *d;
- while ((d = readdir(dir))) {
errno = 0;
+ if (!(d = readdir(dir))) {
+ if (errno) {
+ printf("error reading from %s: %m\n", dirName);
+ goto done;
+ }
+ break; /* end of directory */
+ }
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) {
- errno = 0;
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
- }
- strcpy(strBuf, dirName);
- strcat(strBuf, "/");
- strcat(strBuf, d->d_name);
+ if (d->d_type == DT_DIR) {
+ struct stat sb;
- if (lstat(strBuf, &sb)) {
- printf("failed to stat %s: %m\n", strBuf);
- errno = 0;
- continue;
- }
+ if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
+ printf("failed to stat %s/%s: %m\n",
+ dirName, d->d_name);
+ continue;
+ }
- /* only descend into subdirectories if device is same as dir */
- if (S_ISDIR(sb.st_mode)) {
+ /* remove subdirectories if device is same as dir */
if (sb.st_dev == rb.st_dev) {
- recursiveRemove(strBuf);
- if (rmdir(strBuf))
- printf("failed to rmdir %s: %m\n", strBuf);
- }
- errno = 0;
- continue;
- }
- if (unlink(strBuf)) {
- printf("failed to remove %s: %m\n", strBuf);
- errno = 0;
- continue;
+ char subdir[ strlen(dirName) +
+ strlen(d->d_name) + 2 ];
+
+ sprintf(subdir, "%s/%s", dirName, d->d_name);
+ recursiveRemove(subdir);
+ } else
+ continue;
}
- }
- if (errno) {
- closedir(dir);
- printf("error reading from %s: %m\n", dirName);
- return 1;
+ if (unlinkat(dfd, d->d_name,
+ d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
+ printf("failed to unlink %s/%s: %m\n", dirName, d->d_name);
}
- closedir(dir);
- return 0;
+ rc = 0; /* success */
+
+done:
+ if (dir)
+ closedir(dir);
+ return rc;
}
static int switchroot(const char *newroot)