]> err.no Git - util-linux/commitdiff
switch_root: rewrite to use fstatat() and unlinkat()
authorKarel Zak <kzak@redhat.com>
Tue, 9 Jun 2009 11:24:11 +0000 (13:24 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 22 Jun 2009 19:30:47 +0000 (21:30 +0200)
Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/switch_root.c

index 1520387239e1d8d0ac797f57ae08d474be4a7e8d..3c42c3d11c700a59129d9443a10cf7f83464bb07 100644 (file)
@@ -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)