| diff -Naur a/libbb/find_root_device.c b/libbb/find_root_device.c |
| --- a/libbb/find_root_device.c 2014-10-27 13:01:18.984487421 -0700 |
| +++ b/libbb/find_root_device.c 2014-10-27 13:36:07.469359713 -0700 |
| @@ -9,6 +9,15 @@ |
| |
| #include "libbb.h" |
| |
| +/* #define DEBUGGING 1 */ |
| + |
| +#ifdef DEBUGGING |
| +#define debug(...) do { printf(__VA_ARGS__); } while (0) |
| +#else |
| +#define debug(...) ((void)0) |
| +#endif |
| + |
| + |
| /* Find block device /dev/XXX which contains specified file |
| * We handle /dev/dir/dir/dir too, at a cost of ~80 more bytes code */ |
| |
| @@ -63,6 +72,46 @@ |
| return retpath; |
| } |
| |
| +#define PROC_MOUNTINFO "/proc/self/mountinfo" |
| +/* A major of zero indicates a non-device mount. Use the kernel's show_mountinfo(), |
| + * exposed through /proc/self/mountinfo to lookup the device reference. */ |
| +static char *find_device_in_mountinfo(struct arena *ap) |
| +{ |
| + char line[1024]; |
| + char *linePtr; |
| + char *retpath = NULL; |
| + |
| + FILE *fp = fopen_for_read(PROC_MOUNTINFO); |
| + if (!fp) |
| + return NULL; |
| + |
| + debug("Looking for device %u:%u\n", major(ap->dev), minor(ap->dev)); |
| + while (fgets(line, sizeof(line), fp)) { |
| + int mnt_id, parent_mnt_id; |
| + unsigned int major, minor; |
| + char mnt_typename[1024], mnt_devname[1024]; |
| + |
| + linePtr = line; |
| + if (sscanf(linePtr, "%i %i %u:%u", &mnt_id, &parent_mnt_id, &major, &minor) != 4) { |
| + debug("Couldn't parse line: '%s'\n", line); |
| + } else if ((linePtr = strstr(linePtr, " - ")) == NULL) { |
| + debug("Couldn't find ' - ': '%s'\n", line); |
| + } else if (sscanf(linePtr, " - %s %s ", mnt_typename, mnt_devname) != 2) { |
| + debug("Couldn't parse line: '%s'\n", line); |
| + } else if ((major(ap->dev) != major) || (minor(ap->dev) != minor)) { |
| + debug("Non-matching device %u:%u --> %s\n", major, minor, mnt_devname); |
| + } else { |
| + debug("Found a match %u:%u --> %s\n", major, minor, mnt_devname); |
| + retpath = xstrdup(mnt_devname); |
| + break; |
| + } |
| + } |
| + |
| + fclose(fp); |
| + |
| + return retpath; |
| +} |
| + |
| char* FAST_FUNC find_block_device(const char *path) |
| { |
| struct arena a; |
| @@ -70,6 +119,10 @@ |
| if (stat(path, &a.st) != 0) |
| return NULL; |
| a.dev = S_ISBLK(a.st.st_mode) ? a.st.st_rdev : a.st.st_dev; |
| - strcpy(a.devpath, "/dev"); |
| - return find_block_device_in_dir(&a); |
| + if (major(a.dev) != 0) { |
| + strcpy(a.devpath, "/dev"); |
| + return find_block_device_in_dir(&a); |
| + } else { |
| + return find_device_in_mountinfo(&a); |
| + } |
| } |