diff options
Diffstat (limited to 'c_src/libbcachefs.c')
-rw-r--r-- | c_src/libbcachefs.c | 122 |
1 files changed, 98 insertions, 24 deletions
diff --git a/c_src/libbcachefs.c b/c_src/libbcachefs.c index 75cab72c..ea5629e4 100644 --- a/c_src/libbcachefs.c +++ b/c_src/libbcachefs.c @@ -411,43 +411,107 @@ void bcache_fs_close(struct bchfs_handle fs) close(fs.sysfs_fd); } -struct bchfs_handle bcache_fs_open(const char *path) +static int bcache_fs_open_by_uuid(const char *uuid_str, struct bchfs_handle *fs) { - struct bchfs_handle ret; + if (uuid_parse(uuid_str, fs->uuid.b)) + return -1; - if (!uuid_parse(path, ret.uuid.b)) { - /* It's a UUID, look it up in sysfs: */ - char *sysfs = mprintf(SYSFS_BASE "%s", path); - ret.sysfs_fd = xopen(sysfs, O_RDONLY); + char *sysfs = mprintf(SYSFS_BASE "%s", uuid_str); + fs->sysfs_fd = open(sysfs, O_RDONLY); + free(sysfs); - char *minor = read_file_str(ret.sysfs_fd, "minor"); - char *ctl = mprintf("/dev/bcachefs%s-ctl", minor); - ret.ioctl_fd = xopen(ctl, O_RDWR); + if (fs->sysfs_fd < 0) + return -errno; - free(sysfs); - free(minor); - free(ctl); - } else { - /* It's a path: */ - ret.ioctl_fd = open(path, O_RDONLY); - if (ret.ioctl_fd < 0) - die("Error opening filesystem at %s: %m", path); + char *minor = read_file_str(fs->sysfs_fd, "minor"); + char *ctl = mprintf("/dev/bcachefs%s-ctl", minor); + fs->ioctl_fd = open(ctl, O_RDWR); + free(minor); + free(ctl); + + return fs->ioctl_fd < 0 ? -errno : 0; +} + +int bcache_fs_open_fallible(const char *path, struct bchfs_handle *fs) +{ + memset(fs, 0, sizeof(*fs)); + fs->dev_idx = -1; - struct bch_ioctl_query_uuid uuid; - if (ioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid) < 0) - die("error opening %s: not a bcachefs filesystem", path); + if (!uuid_parse(path, fs->uuid.b)) + return bcache_fs_open_by_uuid(path, fs); - ret.uuid = uuid.uuid; + /* It's a path: */ + int path_fd = open(path, O_RDONLY); + if (path_fd < 0) + return -errno; + + struct bch_ioctl_query_uuid uuid; + if (!ioctl(path_fd, BCH_IOCTL_QUERY_UUID, &uuid)) { + /* It's a path to the mounted filesystem: */ + fs->ioctl_fd = path_fd; + + fs->uuid = uuid.uuid; char uuid_str[40]; uuid_unparse(uuid.uuid.b, uuid_str); char *sysfs = mprintf(SYSFS_BASE "%s", uuid_str); - ret.sysfs_fd = xopen(sysfs, O_RDONLY); + fs->sysfs_fd = xopen(sysfs, O_RDONLY); free(sysfs); + return 0; } - return ret; + struct bch_opts opts = bch2_opts_empty(); + char buf[1024], *uuid_str; + + struct stat stat = xstat(path); + close(path_fd); + + if (S_ISBLK(stat.st_mode)) { + char *sysfs = mprintf("/sys/dev/block/%u:%u/bcachefs", + major(stat.st_rdev), + minor(stat.st_rdev)); + + ssize_t len = readlink(sysfs, buf, sizeof(buf)); + free(sysfs); + + if (len <= 0) + goto read_super; + + char *p = strrchr(buf, '/'); + if (!p || sscanf(p + 1, "dev-%u", &fs->dev_idx) != 1) + die("error parsing sysfs"); + + *p = '\0'; + p = strrchr(buf, '/'); + uuid_str = p + 1; + } else { +read_super: + opt_set(opts, noexcl, true); + opt_set(opts, nochanges, true); + + struct bch_sb_handle sb; + int ret = bch2_read_super(path, &opts, &sb); + if (ret) + die("Error opening %s: %s", path, strerror(-ret)); + + fs->dev_idx = sb.sb->dev_idx; + uuid_str = buf; + uuid_unparse(sb.sb->user_uuid.b, uuid_str); + + bch2_free_super(&sb); + } + + return bcache_fs_open_by_uuid(uuid_str, fs); +} + +struct bchfs_handle bcache_fs_open(const char *path) +{ + struct bchfs_handle fs; + int ret = bcache_fs_open_fallible(path, &fs); + if (ret) + die("Error opening filesystem at %s: %s", path, strerror(-ret)); + return fs; } /* @@ -523,7 +587,7 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd) if (e.type) continue; - if (e.p.data_type == U8_MAX) + if (e.ret || e.p.data_type == U8_MAX) break; printf("\33[2K\r"); @@ -733,6 +797,8 @@ dev_names bchu_fs_get_devices(struct bchfs_handle fs) if (r > 0) { sysfs_block_buf[r] = '\0'; n.dev = strdup(basename(sysfs_block_buf)); + } else { + n.dev = mprintf("(offline dev %u)", n.idx); } free(block_attr); @@ -752,3 +818,11 @@ dev_names bchu_fs_get_devices(struct bchfs_handle fs) return devs; } + +struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx) +{ + darray_for_each(*dev_names, dev) + if (dev->idx == idx) + return dev; + return NULL; +} |