From e4d5b4b3b44bcfe01291c0b0d32e8ba2f68efc4e Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 25 Oct 2010 23:23:48 +0200 Subject: [PATCH] libmount: optimize blkid_devno_to_devname() The brutal force /dev directory scanning should be used as a fallback solution only. Currently, almost all systems use udev and we can read the name from /sys/block/: symlink. Signed-off-by: Karel Zak --- shlibs/blkid/src/devno.c | 88 +++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/shlibs/blkid/src/devno.c b/shlibs/blkid/src/devno.c index 1d389ac6..33466048 100644 --- a/shlibs/blkid/src/devno.c +++ b/shlibs/blkid/src/devno.c @@ -225,17 +225,18 @@ static const char *devdirs[] = { "/devices", "/devfs", "/dev", NULL }; * @short_description: mix of various utils for low-level and high-level API */ -/** - * blkid_devno_to_devname: - * @devno: device number - * - * This function finds the pathname to a block device with a given - * device number. - * - * Returns: a pointer to allocated memory to the pathname on success, - * and NULL on failure. - */ -char *blkid_devno_to_devname(dev_t devno) +/* returns basename and keeps dirname in the @path */ +static char *stripoff_last_component(char *path) +{ + char *p = strrchr(path, '/'); + + if (!p) + return NULL; + *p = '\0'; + return ++p; +} + +static char *scandev_devno_to_devname(dev_t devno) { struct dir_list *list = NULL, *new_list = NULL; char *devname = NULL; @@ -270,6 +271,59 @@ char *blkid_devno_to_devname(dev_t devno) free_dirlist(&list); free_dirlist(&new_list); + return devname; +} + +static char *sysfs_devno_to_devname(dev_t dev) +{ + char path[PATH_MAX]; + char linkpath[PATH_MAX]; + struct stat st; + char *name; + int rc; + + rc = snprintf(path, sizeof(path), "/sys/dev/block/%d:%d", + major(dev), minor(dev)); + if (rc < 0 || rc + 1 > sizeof(path)) + return NULL; + + rc = readlink(path, linkpath, sizeof(linkpath) - 1); + if (rc < 0) + return NULL; + linkpath[rc] = '\0'; + + name = stripoff_last_component(linkpath); /* basename */ + if (!name) + return NULL; + + rc = snprintf(path, sizeof(path), "/dev/%s", name); + if (rc < 0 || rc + 1 > sizeof(path)) + return NULL; + + if (!stat(path, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev) + return strdup(path); + + return NULL; +} + +/** + * blkid_devno_to_devname: + * @devno: device number + * + * This function finds the pathname to a block device with a given + * device number. + * + * Returns: a pointer to allocated memory to the pathname on success, + * and NULL on failure. + */ +char *blkid_devno_to_devname(dev_t devno) +{ + char *devname = NULL; + + devname = sysfs_devno_to_devname(devno); + if (!devname) + devname = scandev_devno_to_devname(devno); + if (!devname) { DBG(DEBUG_DEVNO, printf("blkid: couldn't find devno 0x%04lx\n", @@ -279,22 +333,10 @@ char *blkid_devno_to_devname(dev_t devno) printf("found devno 0x%04llx as %s\n", (long long)devno, devname)); } - return devname; } -/* returns basename and keeps dirname in the @path */ -static char *stripoff_last_component(char *path) -{ - char *p = strrchr(path, '/'); - - if (!p) - return NULL; - *p = '\0'; - return ++p; -} - /** * blkid_devno_to_wholedisk: * @dev: device number -- 2.39.5