]> err.no Git - util-linux/commitdiff
libmount: optimize blkid_devno_to_devname()
authorKarel Zak <kzak@redhat.com>
Mon, 25 Oct 2010 21:23:48 +0000 (23:23 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 25 Oct 2010 21:23:48 +0000 (23:23 +0200)
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/<maj>:<min> symlink.

Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/blkid/src/devno.c

index 1d389ac6951da7a0696f48ed36bde5452feb37ba..33466048f99bbfbcea71602cd03d3956e310ee98 100644 (file)
@@ -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