From 0dcfa3b8270f38edacee1c62f308129c36073d0c Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 24 Mar 2008 15:05:44 -0400 Subject: Walk all block devices looking for btrfs --- utils.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) (limited to 'utils.c') diff --git a/utils.c b/utils.c index 80d1d036..0a067e6b 100644 --- a/utils.c +++ b/utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "kerncompat.h" @@ -37,6 +38,7 @@ #include "crc32c.h" #include "utils.h" #include "volumes.h" +#include "ioctl.h" #ifdef __CHECKER__ #define BLKGETSIZE64 0 @@ -522,3 +524,124 @@ int btrfs_make_root_dir(struct btrfs_trans_handle *trans, error: return ret; } + +struct pending_dir { + struct list_head list; + char name[256]; +}; + +int btrfs_register_one_device(char *fname) +{ + struct btrfs_ioctl_vol_args args; + int fd; + int ret; + + fd = open("/dev/btrfs-control", O_RDONLY); + if (fd < 0) + return -EINVAL; + strcpy(args.name, fname); + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); + close(fd); + return ret; +} + +int btrfs_scan_one_dir(char *dirname, int run_ioctl) +{ + DIR *dirp; + struct dirent *dirent; + struct pending_dir *pending; + struct stat st; + int ret; + int fd; + int dirname_len; + int pathlen; + char *fullpath; + struct list_head pending_list; + struct btrfs_fs_devices *tmp_devices; + u64 num_devices; + + INIT_LIST_HEAD(&pending_list); + + pending = malloc(sizeof(*pending)); + if (!pending) + return -ENOMEM; + strcpy(pending->name, dirname); + +again: + dirname_len = strlen(pending->name); + pathlen = 1024; + fullpath = malloc(pathlen); + dirname = pending->name; + + if (!fullpath) { + ret = -ENOMEM; + goto fail; + } + dirp = opendir(dirname); + if (!dirp) { + fprintf(stderr, "Unable to open /sys/block for scanning\n"); + return -ENOENT; + } + while(1) { + dirent = readdir(dirp); + if (!dirent) + break; + if (dirent->d_name[0] == '.') + continue; + if (dirname_len + strlen(dirent->d_name) + 2 > pathlen) { + ret = -EFAULT; + goto fail; + } + snprintf(fullpath, pathlen, "%s/%s", dirname, dirent->d_name); + ret = lstat(fullpath, &st); + if (ret < 0) { + fprintf(stderr, "failed to stat %s\n", fullpath); + continue; + } + if (S_ISLNK(st.st_mode)) + continue; + if (S_ISDIR(st.st_mode)) { + struct pending_dir *next = malloc(sizeof(*next)); + if (!next) { + ret = -ENOMEM; + goto fail; + } + strcpy(next->name, fullpath); + list_add_tail(&next->list, &pending_list); + } + if (!S_ISBLK(st.st_mode)) { + continue; + } + fd = open(fullpath, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "failed to read %s\n", fullpath); + continue; + } + ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices, + &num_devices, + BTRFS_SUPER_INFO_OFFSET); + if (ret == 0 && run_ioctl > 0) { + btrfs_register_one_device(fullpath); + } + close(fd); + } + if (!list_empty(&pending_list)) { + free(pending); + pending = list_entry(pending_list.next, struct pending_dir, + list); + list_del(&pending->list); + closedir(dirp); + goto again; + } + ret = 0; +fail: + free(pending); + closedir(dirp); + return ret; +} + +int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs, + int run_ioctls) +{ + return btrfs_scan_one_dir("/dev", run_ioctls); +} -- cgit v1.2.3