diff options
author | Daniel Golle <daniel@makrotopia.org> | 2016-09-11 16:52:52 +0200 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2016-09-12 02:50:52 +0200 |
commit | 7874d580ff965bebbe19ea157353749d9f007b39 (patch) | |
tree | 46e49ab2228055b9c98ffb29c36c1b0461e1ef86 | |
parent | fe514c9a20365ba00232c2c981463f43a4a41a7d (diff) | |
download | fstools-7874d580ff965bebbe19ea157353749d9f007b39.tar.gz |
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 <daniel@makrotopia.org>
-rw-r--r-- | libfstools/find.c | 144 |
1 files 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 <errno.h> #include <stdio.h> #include <string.h> +#include <sys/stat.h> #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; } } |