kpartx: find_loop_by_file: use sysfs
authorMartin Wilck <mwilck@suse.com>
Mon, 15 May 2017 15:37:21 +0000 (17:37 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 17 May 2017 21:45:21 +0000 (23:45 +0200)
Rather then searching through all of /dev, look up loop devices
in /sys/devices/virtual/block. This is cleaner and more robust
(/dev/loop$Xp$Y symlinks may confuse kpartx).

Signed-off-by: Martin Wilck <mwilck@suse.com>
kpartx/lopart.c

index 44f0c27..0521d7d 100644 (file)
@@ -68,25 +68,46 @@ char *find_loop_by_file(const char *filename)
 {
        DIR *dir;
        struct dirent *dent;
-       char dev[64], *found = NULL;
+       char dev[64], *found = NULL, *p;
        int fd;
        struct stat statbuf;
        struct loop_info loopinfo;
+       const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
+       char path[PATH_MAX];
 
-       dir = opendir("/dev");
+       dir = opendir(VIRT_BLOCK);
        if (!dir)
                return NULL;
 
        while ((dent = readdir(dir)) != NULL) {
                if (strncmp(dent->d_name,"loop",4))
                        continue;
-               if (!strcmp(dent->d_name, "loop-control"))
+
+               if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK,
+                            dent->d_name) >= PATH_MAX)
                        continue;
-               sprintf(dev, "/dev/%s", dent->d_name);
 
-               fd = open (dev, O_RDONLY);
+               fd = open(path, O_RDONLY);
                if (fd < 0)
-                       break;
+                       continue;
+
+               if (read(fd, dev, sizeof(dev)) <= 0) {
+                       close(fd);
+                       continue;
+               }
+
+               close(fd);
+
+               dev[sizeof(dev)-1] = '\0';
+               p = strchr(dev, '\n');
+               if (p != NULL)
+                       *p = '\0';
+               if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX)
+                       continue;
+
+               fd = open (path, O_RDONLY);
+               if (fd < 0)
+                       continue;
 
                if (fstat (fd, &statbuf) != 0 ||
                    !S_ISBLK(statbuf.st_mode)) {
@@ -99,13 +120,12 @@ char *find_loop_by_file(const char *filename)
                        continue;
                }
 
+               close (fd);
+
                if (0 == strcmp(filename, loopinfo.lo_name)) {
-                       close (fd);
-                       found = xstrdup(dev);
+                       found = realpath(path, NULL);
                        break;
                }
-
-               close (fd);
        }
        closedir(dir);
        return found;