From: Karel Zak Date: Tue, 12 Jan 2021 10:43:31 +0000 (+0100) Subject: lib/loopdev: make is_loopdev() more robust X-Git-Tag: v2.37-rc1~188 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fbc2fe824dd3450df122d8416da8689f82fb0b4c;p=thirdparty%2Futil-linux.git 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 --- diff --git a/lib/loopdev.c b/lib/loopdev.c index 2b909084e7..b946acf319 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; + + 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); + } - errno = ENODEV; - return 0; + if (rc == 0) + errno = ENODEV; + return rc; } /*