From fbc2fe824dd3450df122d8416da8689f82fb0b4c Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 12 Jan 2021 11:43:31 +0100 Subject: [PATCH] lib/loopdev: make is_loopdev() more robust It seems the current kernel can create a loop devices with a different major number. For example # losetup /dev/loop12345678 file.img # lsblk /dev/loop12345678 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop12345678 15:811342 0 5M 0 loop We need a way how to verify the device is loopdev also when the device is not associated with any backing file -- in this case there is no "loop" directory in /sys/dev/block//, but we can cannonicalize this sysfs symlink as it points to /sys/devices/virtual/block/loop (see "loop" in the path). Note that without this change losetup is not able to list and delete the loop device. Addresses: https://github.com/karelzak/util-linux/issues/1202 Signed-off-by: Karel Zak --- lib/loopdev.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/loopdev.c b/lib/loopdev.c index 2b909084e..b946acf31 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -41,6 +41,7 @@ #include "canonicalize.h" #include "blkdev.h" #include "debug.h" +#include "fileutils.h" /* * Debug stuff (based on include/debug.h) @@ -634,14 +635,30 @@ done: int is_loopdev(const char *device) { struct stat st; + int rc = 0; - if (device && stat(device, &st) == 0 && - S_ISBLK(st.st_mode) && - major(st.st_rdev) == LOOPDEV_MAJOR) - return 1; + if (!device || stat(device, &st) != 0 || !S_ISBLK(st.st_mode)) + rc = 0; + else if (major(st.st_rdev) == LOOPDEV_MAJOR) + rc = 1; + else { + /* It's possible that kernel creates a device with a different + * major number ... check by /sys it's really loop device. + */ + char name[PATH_MAX], *cn, *p = NULL; - errno = ENODEV; - return 0; + snprintf(name, sizeof(name), _PATH_SYS_DEVBLOCK "/%d:%d", + major(st.st_rdev), minor(st.st_rdev)); + cn = canonicalize_path(name); + if (cn) + p = stripoff_last_component(cn); + rc = p && startswith(p, "loop"); + free(cn); + } + + if (rc == 0) + errno = ENODEV; + return rc; } /*