From 7874d580ff965bebbe19ea157353749d9f007b39 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 11 Sep 2016 16:52:52 +0200 Subject: [PATCH] libfstools: gather mountpoints from /proc/self/mountinfo This allows identifying /dev/root by its major:minor number which are part of /proc/self/mountinfo but aren't contained in /proc/mounts. Also fix jffs2reset when using an ext4 overlay by adding it to the list of filesystems allowed if the root_only parameter of find_mount_point is set. Signed-off-by: Daniel Golle --- libfstools/find.c | 144 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 120 insertions(+), 24 deletions(-) diff --git a/libfstools/find.c b/libfstools/find.c index 72a2b4c..52bc51f 100644 --- a/libfstools/find.c +++ b/libfstools/find.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "libfstools.h" @@ -76,40 +77,135 @@ find_mount(char *mp) return point; } +/* + * Match filesystem type against a bunch of valid types + * + * jffs2reset may ask if the filesystem type is actually ready for use + * with overlayfs before wiping it... + */ +static int fs_rootfs_only(char *fstype) +{ + if (strncmp(fstype, "ext4", 4) && + strncmp(fstype, "f2fs", 4) && + strncmp(fstype, "jffs2", 5) && + strncmp(fstype, "ubifs", 5)) { + ULOG_ERR("block is mounted with wrong fs\n"); + return 1; + } + return 0; +} + +/* + * Check if a given device is mounted and return its mountpoint + */ char* find_mount_point(char *block, int root_only) { - FILE *fp = fopen("/proc/mounts", "r"); + FILE *fp = fopen("/proc/self/mountinfo", "r"); static char line[256]; int len = strlen(block); - char *point = NULL; + char *point = NULL, *pos, *tmp, *cpoint, *devname, *fstype; + struct stat s; + int rstat; + unsigned int minor, major; - if(!fp) + if (!fp) return NULL; + rstat = stat(block, &s); + while (fgets(line, sizeof(line), fp)) { - if (!strncmp(line, block, len)) { - char *p = &line[len + 1]; - char *t = strstr(p, " "); - - if (!t) { - fclose(fp); - return NULL; - } - - *t = '\0'; - t++; - - if (root_only && - strncmp(t, "f2fs", 4) && - strncmp(t, "jffs2", 5) && - strncmp(t, "ubifs", 5)) { - fclose(fp); - ULOG_ERR("block is mounted with wrong fs\n"); - return NULL; - } - point = p; + /* skip first two columns */ + pos = strchr(line, ' '); + if (!pos) + continue; + + pos = strchr(pos + 1, ' '); + if (!pos) + continue; + + /* extract block device major:minor */ + tmp = ++pos; + pos = strchr(pos, ':'); + if (!pos) + continue; + + *pos = '\0'; + major = atoi(tmp); + + tmp = ++pos; + pos = strchr(pos, ' '); + if (!pos) + continue; + + *pos = '\0'; + minor = atoi(tmp); + + /* skip another column */ + pos = strchr(pos + 1, ' '); + if (!pos) + continue; + + /* get mountpoint */ + tmp = ++pos; + pos = strchr(pos, ' '); + if (!pos) + continue; + + *pos = '\0'; + cpoint = tmp; + + /* skip another two columns */ + pos = strchr(pos + 1, ' '); + if (!pos) + continue; + + pos = strchr(pos + 1, ' '); + if (!pos) + continue; + + /* get fstype */ + tmp = ++pos; + pos = strchr(pos, ' '); + if (!pos) + continue; + + *pos = '\0'; + fstype = tmp; + + /* get device name */ + tmp = ++pos; + pos = strchr(pos, ' '); + if (!pos) + continue; + + *pos = '\0'; + devname = tmp; + + /* if device name matches */ + if (!strncmp(block, devname, len)) { + if (root_only && fs_rootfs_only(fstype)) + break; + + /* found, return mountpoint */ + point = strdup(cpoint); + break; + } + + /* last chance: check if major:minor of block device match */ + if (rstat) + continue; + + if (!S_ISBLK(s.st_mode)) + continue; + + if (major == major(s.st_rdev) && + minor == minor(s.st_rdev)) { + if (root_only && fs_rootfs_only(fstype)) + break; + /* found, return mountpoint */ + point = strdup(cpoint); break; } } -- 2.11.0