block: get mountpoints from /proc/self/mountinfo
authorDaniel Golle <daniel@makrotopia.org>
Sun, 24 Jul 2016 13:16:16 +0000 (15:16 +0200)
committerDaniel Golle <daniel@makrotopia.org>
Sun, 24 Jul 2016 15:25:22 +0000 (17:25 +0200)
Instead of using two different implementations reading /proc/mounts
and /proc/self/mountinfo, gather all information on mountpoints from
/proc/self/mountinfo.
While at it, tokenize mountinfo inline instead of using strtok_r
because it's hard to tell whether strtok_r allocated new memory or
merely returns a pointer to the (last) token. This might later on be
relevant once we want to free that memory...
Tokenizing mountinfo using strchr inline works without allocating any
new memory by scanning and re-writing the string returned by gets().
As a result, the returned string needs to be duplicated to be safe for
use even after the fclose().

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
block.c

diff --git a/block.c b/block.c
index e674521cd1b70016674a5d4ed685c8916c7ace9d..33264583c23b91ef32747c5e50c0c7b4fb624283 100644 (file)
--- a/block.c
+++ b/block.c
@@ -587,52 +587,83 @@ static struct blkid_struct_probe* find_block_info(char *uuid, char *label, char
 
 static char* find_mount_point(char *block)
 {
-       FILE *fp = fopen("/proc/mounts", "r");
-       static char line[256], *saveptr;
+       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;
        struct stat s;
+       unsigned int minor, major;
 
-       if(!fp)
+       if (!fp)
+               return NULL;
+
+       if (stat(block, &s))
                return NULL;
 
        while (fgets(line, sizeof(line), fp)) {
-               if (!strncmp(line, block, len)) {
-                       char *p = &line[len + 1];
-                       char *t = strstr(p, " ");
+               pos = strchr(line, ' ');
+               if (!pos)
+                       continue;
 
-                       if (!t) {
-                               fclose(fp);
-                               return NULL;
-                       }
-                       *t = '\0';
-                       point = p;
-                       break;
-               }
-       }
+               pos = strchr(pos + 1, ' ');
+               if (!pos)
+                       continue;
 
-       fclose(fp);
+               tmp = ++pos;
+               pos = strchr(pos, ':');
+               if (!pos)
+                       continue;
 
-       if (point)
-               return point;
+               *pos = '\0';
+               major = atoi(tmp);
+               tmp = ++pos;
+               pos = strchr(pos, ' ');
+               if (!pos)
+                       continue;
 
-       if (stat(block, &s))
-               return NULL;
+               *pos = '\0';
+               minor = atoi(tmp);
+               pos = strchr(pos + 1, ' ');
+               if (!pos)
+                       continue;
+               tmp = ++pos;
 
-       if (!S_ISBLK(s.st_mode))
-               return NULL;
+               pos = strchr(pos, ' ');
+               if (!pos)
+                       continue;
+               *pos = '\0';
+               cpoint = tmp;
 
-       fp = fopen("/proc/self/mountinfo", "r");
-       if(!fp)
-               return NULL;
+               pos = strchr(pos + 1, ' ');
+               if (!pos)
+                       continue;
 
-       while (fgets(line, sizeof(line), fp)) {
-               strtok_r(line, " \t", &saveptr);
-               strtok_r(NULL, " \t", &saveptr);
-               if (atoi(strtok_r(NULL, ":", &saveptr)) == major(s.st_rdev) &&
-                   atoi(strtok_r(NULL, " \t", &saveptr)) == minor(s.st_rdev)) {
-                       strtok_r(NULL, " \t", &saveptr);
-                       point = strtok_r(NULL, " \t", &saveptr);
+               pos = strchr(pos + 1, ' ');
+               if (!pos)
+                       continue;
+
+               pos = strchr(pos + 1, ' ');
+               if (!pos)
+                       continue;
+
+               tmp = ++pos;
+               pos = strchr(pos, ' ');
+               if (!pos)
+                       continue;
+
+               *pos = '\0';
+               devname = tmp;
+               if (!strncmp(block, devname, len)) {
+                       point = strdup(cpoint);
+                       break;
+               }
+
+               if (!S_ISBLK(s.st_mode))
+                       continue;
+
+               if (major == major(s.st_rdev) &&
+                   minor == minor(s.st_rdev)) {
+                       point = strdup(cpoint);
                        break;
                }
        }
@@ -750,6 +781,7 @@ static int mount_device(struct blkid_struct_probe *pr, int hotplug)
        mp = find_mount_point(pr->dev);
        if (mp) {
                ULOG_ERR("%s is already mounted on %s\n", pr->dev, mp);
+               free(mp);
                return -1;
        }
 
@@ -832,6 +864,7 @@ static int umount_device(struct blkid_struct_probe *pr)
                ULOG_INFO("unmounted %s (%s)\n",
                          pr->dev, mp);
 
+       free(mp);
        return err;
 }
 
@@ -857,6 +890,7 @@ static int main_hotplug(int argc, char **argv)
                        ULOG_ERR("umount of %s failed (%d) - %s\n",
                                 mount_point, err, strerror(err));
 
+               free(mount_point);
                return 0;
        } else if (strcmp(action, "add")) {
                ULOG_ERR("Unkown action %s\n", action);