+char *dev_to_name(dev_t dev)
+{
+ char *line = NULL, *name = NULL;
+ size_t n = 0;
+
+ FILE *f = fopen("/proc/partitions", "r");
+ if (!f)
+ die("error opening /proc/partitions: %m");
+
+ while (getline(&line, &n, f) != -1) {
+ unsigned ma, mi;
+ u64 sectors;
+
+ name = realloc(name, n + 1);
+
+ if (sscanf(line, " %u %u %llu %s", &ma, &mi, §ors, name) == 4 &&
+ ma == major(dev) && mi == minor(dev))
+ goto found;
+ }
+
+ free(name);
+ name = NULL;
+found:
+ fclose(f);
+ free(line);
+ return name;
+}
+
+char *dev_to_path(dev_t dev)
+{
+ char *name = dev_to_name(dev);
+ if (!name)
+ return NULL;
+
+ char *path = mprintf("/dev/%s", name);
+
+ free(name);
+ return path;
+}
+
+struct mntent *dev_to_mount(char *dev)
+{
+ struct mntent *mnt, *ret = NULL;
+ FILE *f = setmntent("/proc/mounts", "r");
+ if (!f)
+ die("error opening /proc/mounts: %m");
+
+ struct stat d1 = xstat(dev);
+
+ while ((mnt = getmntent(f))) {
+ char *d, *p = mnt->mnt_fsname;
+
+ while ((d = strsep(&p, ":"))) {
+ struct stat d2;
+
+ if (stat(d, &d2))
+ continue;
+
+ if (S_ISBLK(d1.st_mode) != S_ISBLK(d2.st_mode))
+ continue;
+
+ if (S_ISBLK(d1.st_mode)) {
+ if (d1.st_rdev != d2.st_rdev)
+ continue;
+ } else {
+ if (d1.st_dev != d2.st_dev ||
+ d1.st_ino != d2.st_ino)
+ continue;
+ }
+
+ ret = mnt;
+ goto found;
+ }
+ }
+found:
+ fclose(f);
+ return ret;
+}
+
+int dev_mounted(char *dev)
+{
+ struct mntent *mnt = dev_to_mount(dev);
+
+ if (!mnt)
+ return 0;
+ if (hasmntopt(mnt, "ro"))
+ return 1;
+ return 2;
+}
+
+struct bpos bpos_parse(char *buf)
+{
+ char *s = buf, *field;
+ u64 inode_v = 0, offset_v = 0;
+
+ if (!(field = strsep(&s, ":")) ||
+ kstrtoull(field, 10, &inode_v))
+ die("invalid bpos %s", buf);
+
+ if ((field = strsep(&s, ":")) &&
+ kstrtoull(field, 10, &offset_v))
+ die("invalid bpos %s", buf);
+
+ if (s)
+ die("invalid bpos %s", buf);
+
+ return (struct bpos) { .inode = inode_v, .offset = offset_v };
+}