[syslinux:master] extlinux: use sysfs to find the device node if need be

syslinux-bot for H. Peter Anvin hpa at zytor.com
Wed Feb 8 16:03:06 PST 2012


Commit-ID:  07f7e9b8005ee8c1879589d9b606c157f28f9f25
Gitweb:     http://www.syslinux.org/commit/07f7e9b8005ee8c1879589d9b606c157f28f9f25
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Wed, 8 Feb 2012 10:15:50 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Wed, 8 Feb 2012 10:18:36 -0800

extlinux: use sysfs to find the device node if need be

If neither /proc/mounts nor /etc/mtab contains a functional pointer to
the device node for the installer, try to see if we can find the
device node by looking for a symlink in /sys/dev/block.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>

---
 extlinux/main.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/extlinux/main.c b/extlinux/main.c
index af87da2..5da89e2 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -873,6 +873,54 @@ static const char *find_device(const char *mtab_file, dev_t dev)
 }
 #endif
 
+/*
+ * On newer Linux kernels we can use sysfs to get a backwards mapping
+ * from device names to standard filenames
+ */
+static const char *find_device_sysfs(dev_t dev)
+{
+    char sysname[64];
+    char linkname[PATH_MAX];
+    ssize_t llen;
+    char *p, *q;
+    char *buf = NULL;
+    struct stat st;
+
+    snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
+	     major(dev), minor(dev));
+
+    llen = readlink(sysname, linkname, sizeof linkname);
+    if (llen < 0 || llen >= sizeof linkname)
+	goto err;
+
+    linkname[llen] = '\0';
+
+    p = strrchr(linkname, '/');
+    p = p ? p+1 : linkname;	/* Leave basename */
+
+    buf = q = malloc(strlen(p) + 6);
+    if (!buf)
+	goto err;
+
+    memcpy(q, "/dev/", 5);
+    q += 5;
+
+    while (*p) {
+	*q++ = (*p == '!') ? '/' : *p;
+	p++;
+    }
+
+    *q = '\0';
+
+    if (!stat(buf, &st) && st.st_dev == dev)
+	return buf;		/* Found it! */
+
+err:
+    if (buf)
+	free(buf);
+    return NULL;
+}
+
 static const char *get_devname(const char *path)
 {
     const char *devname = NULL;
@@ -887,21 +935,26 @@ static const char *get_devname(const char *path)
 	fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
 	return devname;
     }
+
 #ifdef __KLIBC__
 
-    /* klibc doesn't have getmntent and friends; instead, just create
-       a new device with the appropriate device type */
-    snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
-	     major(st.st_dev), minor(st.st_dev));
+    devname = find_device_sysfs(st.st_dev);
 
-    if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
-	fprintf(stderr, "%s: cannot create device %s\n", program, devname);
-	return devname;
+    if (!devname) {
+	/* klibc doesn't have getmntent and friends; instead, just create
+	   a new device with the appropriate device type */
+	snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
+		 major(st.st_dev), minor(st.st_dev));
+
+	if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
+	    fprintf(stderr, "%s: cannot create device %s\n", program, devname);
+	    return devname;
+	}
+	
+	atexit(device_cleanup);	/* unlink the device node on exit */
+	devname = devname_buf;
     }
 
-    atexit(device_cleanup);	/* unlink the device node on exit */
-    devname = devname_buf;
-
 #else
 
     devname = find_device("/proc/mounts", st.st_dev);
@@ -910,11 +963,14 @@ static const char *get_devname(const char *path)
         devname = find_device("/etc/mtab", st.st_dev);
     }
     if (!devname) {
+	devname = find_device_sysfs(st.st_dev);
+
 	fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
 	return devname;
     }
 
     fprintf(stderr, "%s is device %s\n", path, devname);
+
 #endif
     return devname;
 }


More information about the Syslinux-commits mailing list