libfstools: gather mountpoints from /proc/self/mountinfo
[project/fstools.git] / libfstools / find.c
index 4c69d735d7af18d908d11ccbf520c02d7d0d9402..52bc51f130d0db9120659a79706d098cd0b4ea7f 100644 (file)
@@ -14,6 +14,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
 
 #include "libfstools.h"
 
@@ -76,39 +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 mtd_only)
+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 (mtd_only &&
-                           strncmp(t, "jffs2", 5) &&
-                           strncmp(t, "ubifs", 5)) {
-                               fclose(fp);
-                               fprintf(stderr, "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;
                }
        }
@@ -126,7 +223,7 @@ find_filesystem(char *fs)
        int ret = -1;
 
        if (!fp) {
-               fprintf(stderr, "opening /proc/filesystems failed: %s\n", strerror(errno));
+               ULOG_ERR("opening /proc/filesystems failed: %s\n", strerror(errno));
                goto out;
        }