blob: 03067f6c5f0c0c41a491f7ff26f7ea1306157bea [file] [log] [blame]
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);
+ }
}