]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: improve -a to report loopdevs < 512 bytes
authorKarel Zak <kzak@redhat.com>
Tue, 12 Jun 2012 13:41:47 +0000 (15:41 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 12 Jun 2012 13:41:47 +0000 (15:41 +0200)
 # ll ~/xxx2
  -rw-r--r-- 1 root root 500 Jun 12 14:30 /root/xxx2

 old version:
  # losetup -a

 new version:
  # losetup -a
  /dev/loop0: [2052]:535312 (/root/xxx2)

The new version scans /sys/block/loopN, kernel >= 2.6.37 is required
otherwise fallback to the original not-so-smart /proc/partitions scan.

Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=730266
Signed-off-by: Karel Zak <kzak@redhat.com>
include/loopdev.h
lib/loopdev.c

index 906bee03a098249ccbda2f9f8fa8e0773b6b0f04..143c0d30ff7f9abc806bb676f4d1a02ddbb9499f 100644 (file)
@@ -68,6 +68,7 @@ struct loop_info64 {
 
 struct loopdev_iter {
        FILE            *proc;          /* /proc/partitions */
+       DIR             *sysblock;      /* /sys/block */
        int             ncur;           /* current position */
        int             *minors;        /* ary of minor numbers (when scan whole /dev) */
        int             nminors;        /* number of items in *minors */
index c0f701896f650092e17fbd8d3df44ae4f43d6fee..8e57067358836345ea673c302301ee381acc011c 100644 (file)
@@ -37,6 +37,7 @@
 #include "pathnames.h"
 #include "loopdev.h"
 #include "canonicalize.h"
+#include "at.h"
 
 #define CONFIG_LOOPDEV_DEBUG
 
@@ -64,8 +65,12 @@ loopdev_debug(const char *mesg, ...)
 # define DBG(m,x) do { ; } while(0)
 #endif
 
-
+/*
+ * see loopcxt_init()
+ */
 #define loopcxt_ioctl_enabled(_lc)     (!((_lc)->flags & LOOPDEV_FL_NOIOCTL))
+#define loopcxt_sysfs_available(_lc)   (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \
+                                        && !loopcxt_ioctl_enabled(_lc)
 
 /*
  * @lc: context
@@ -337,8 +342,11 @@ int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
        free(iter->minors);
        if (iter->proc)
                fclose(iter->proc);
+       if (iter->sysblock)
+               closedir(iter->sysblock);
        iter->minors = NULL;
        iter->proc = NULL;
+       iter->sysblock = NULL;
        iter->done = 1;
        return 0;
 }
@@ -447,6 +455,85 @@ static int loop_scandir(const char *dirname, int **ary, int hasprefix)
        return count;
 }
 
+/*
+ * Set the next *used* loop device according to /proc/partitions.
+ *
+ * Loop devices smaller than 512 bytes are invisible for this function.
+ */
+static int loopcxt_next_from_proc(struct loopdev_cxt *lc)
+{
+       struct loopdev_iter *iter = &lc->iter;
+       char buf[BUFSIZ];
+
+       DBG(lc, loopdev_debug("iter: scan /proc/partitions"));
+
+       if (!iter->proc)
+               iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
+       if (!iter->proc)
+               return 1;
+
+       while (fgets(buf, sizeof(buf), iter->proc)) {
+               unsigned int m;
+               char name[128];
+
+
+               if (sscanf(buf, " %u %*s %*s %128[^\n ]",
+                          &m, name) != 2 || m != LOOPDEV_MAJOR)
+                       continue;
+
+               DBG(lc, loopdev_debug("iter: check %s", name));
+
+               if (loopiter_set_device(lc, name) == 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Set the next *used* loop device according to
+ * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required).
+ *
+ * This is preferred method.
+ */
+static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc)
+{
+       struct loopdev_iter *iter = &lc->iter;
+       struct dirent *d;
+       int fd;
+
+       DBG(lc, loopdev_debug("iter: scan /sys/block"));
+
+       if (!iter->sysblock)
+               iter->sysblock = opendir(_PATH_SYS_BLOCK);
+
+       if (!iter->sysblock)
+               return 1;
+
+       fd = dirfd(iter->sysblock);
+
+       while ((d = readdir(iter->sysblock))) {
+               char name[256];
+               struct stat st;
+
+               DBG(lc, loopdev_debug("iter: check %s", d->d_name));
+
+               if (strcmp(d->d_name, ".") == 0
+                   || strcmp(d->d_name, "..") == 0
+                   || strncmp(d->d_name, "loop", 4) != 0)
+                       continue;
+
+               snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name);
+               if (fstat_at(fd, _PATH_SYS_BLOCK, name, &st, 0) != 0)
+                       continue;
+
+               if (loopiter_set_device(lc, d->d_name) == 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
 /*
  * @lc: context, has to initialized by loopcxt_init_iterator()
  *
@@ -470,23 +557,14 @@ int loopcxt_next(struct loopdev_cxt *lc)
        /* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
         */
        if (iter->flags & LOOPITER_FL_USED) {
-               char buf[BUFSIZ];
-
-               if (!iter->proc)
-                       iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
-
-               while (iter->proc && fgets(buf, sizeof(buf), iter->proc)) {
-                       unsigned int m;
-                       char name[128];
-
-                       if (sscanf(buf, " %u %*s %*s %128[^\n ]",
-                                  &m, name) != 2 || m != LOOPDEV_MAJOR)
-                               continue;
-
-                       if (loopiter_set_device(lc, name) == 0)
-                               return 0;
-               }
+               int rc;
 
+               if (loopcxt_sysfs_available(lc))
+                       rc = loopcxt_next_from_sysfs(lc);
+               else
+                       rc = loopcxt_next_from_proc(lc);
+               if (rc == 0)
+                       return 0;
                goto done;
        }