aboutsummaryrefslogtreecommitdiffstats
path: root/extlinux/main.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-02-08 10:15:50 -0800
committerH. Peter Anvin <hpa@zytor.com>2012-02-08 10:18:36 -0800
commit07f7e9b8005ee8c1879589d9b606c157f28f9f25 (patch)
tree5eb2713ae02ce3ac32940ac1a58a908ec78923b8 /extlinux/main.c
parentf49425356d7a6a9885eda269ee6261a425328ade (diff)
downloadsyslinux-07f7e9b8005ee8c1879589d9b606c157f28f9f25.tar.gz
syslinux-07f7e9b8005ee8c1879589d9b606c157f28f9f25.tar.xz
syslinux-07f7e9b8005ee8c1879589d9b606c157f28f9f25.zip
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@zytor.com>
Diffstat (limited to 'extlinux/main.c')
-rw-r--r--extlinux/main.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/extlinux/main.c b/extlinux/main.c
index af87da2f..5da89e2d 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;
}