losetup: improve -a to report loopdevs < 512 bytes

# 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>
This commit is contained in:
Karel Zak 2012-06-12 15:41:47 +02:00
parent 3554545636
commit e4062c72d1
2 changed files with 96 additions and 17 deletions

View 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;
}