#include #include #include #include #include #include #include #include #include #include #include #include static inline void closep(int *fd) { if (*fd >= 0) close(*fd); } #define _cleanup_close_ __attribute__((cleanup(closep))) #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) static int get_btrfs_block_device(const char *path, dev_t *dev) { struct btrfs_ioctl_fs_info_args fsi = {}; _cleanup_close_ int fd = -1; uint64_t id; assert(path); assert(dev); fprintf(stderr, "open\n"); fd = open(path, O_DIRECTORY|O_CLOEXEC); if (fd < 0) return -errno; fprintf(stderr, "ioctl\n"); if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0) return -errno; /* We won't do this for btrfs RAID */ if (fsi.num_devices != 1) return 0; for (id = 1; id <= fsi.max_id; id++) { struct btrfs_ioctl_dev_info_args di = { .devid = id, }; struct stat st; fprintf(stderr, "ioctl in loop\n"); if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) { if (errno == ENODEV) continue; return -errno; } fprintf(stderr, "stat in loop: '%s'\n", (char *)di.path); if (stat((char*) di.path, &st) < 0) return -errno; fprintf(stderr, "S_ISBLK in loop\n"); if (!S_ISBLK(st.st_mode)) return -ENODEV; fprintf(stderr, "major in loop\n"); if (major(st.st_rdev) == 0) return -ENODEV; fprintf(stderr, "good in loop\n"); *dev = st.st_rdev; return 1; } return -ENODEV; } static int get_block_device(const char *path, dev_t *dev) { struct stat st; struct statfs sfs; assert(path); assert(dev); fprintf(stderr, "lstat\n"); if (lstat(path, &st)) return -errno; fprintf(stderr, "major\n"); if (major(st.st_dev) != 0) { *dev = st.st_dev; return 1; } fprintf(stderr, "statfs\n"); if (statfs(path, &sfs) < 0) return -errno; if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) return get_btrfs_block_device(path, dev); return 0; } __attribute__((noreturn)) int main() { system("mountpoint -q /proc || mount proc /proc -t proc"); system("mount"); dev_t dev; int res = get_block_device("/", &dev); fprintf(stderr, "%d\n", res); for (;;) {} }