summaryrefslogtreecommitdiff
path: root/c_src/cmd_fsck.c
diff options
context:
space:
mode:
Diffstat (limited to 'c_src/cmd_fsck.c')
-rw-r--r--c_src/cmd_fsck.c75
1 files changed, 66 insertions, 9 deletions
diff --git a/c_src/cmd_fsck.c b/c_src/cmd_fsck.c
index b532de56..2ea51ff2 100644
--- a/c_src/cmd_fsck.c
+++ b/c_src/cmd_fsck.c
@@ -90,12 +90,14 @@ static int splice_fd_to_stdinout(int fd)
return close(fd);
}
-static int fsck_online(const char *dev_path)
+static int fsck_online(const char *dev_path, const char *opt_str)
{
int dev_idx;
struct bchfs_handle fs = bchu_fs_open_by_dev(dev_path, &dev_idx);
- struct bch_ioctl_fsck_online fsck = { 0 };
+ struct bch_ioctl_fsck_online fsck = {
+ .opts = (unsigned long) opt_str
+ };
int fsck_fd = ioctl(fs.ioctl_fd, BCH_IOCTL_FSCK_ONLINE, &fsck);
if (fsck_fd < 0)
@@ -160,6 +162,45 @@ static bool should_use_kernel_fsck(darray_str devs)
return ret;
}
+static bool is_blockdev(const char *path)
+{
+ struct stat s;
+ if (stat(path, &s))
+ return true;
+ return S_ISBLK(s.st_mode);
+}
+
+static void loopdev_free(const char *path)
+{
+ char *cmd = mprintf("losetup -d %s", path);
+ system(cmd);
+ free(cmd);
+}
+
+static char *loopdev_alloc(const char *path)
+{
+ char *cmd = mprintf("losetup --show -f %s", path);
+ FILE *f = popen(cmd, "r");
+ free(cmd);
+ if (!f) {
+ fprintf(stderr, "error executing losetup: %m\n");
+ return NULL;
+ }
+
+ char *line = NULL;
+ size_t n = 0;
+ getline(&line, &n, f);
+ int ret = pclose(f);
+ if (ret) {
+ fprintf(stderr, "error executing losetup: %i\n", ret);
+ free(line);
+ return NULL;
+ }
+
+ strim(line);
+ return line;
+}
+
int cmd_fsck(int argc, char *argv[])
{
static const struct option longopts[] = {
@@ -183,7 +224,7 @@ int cmd_fsck(int argc, char *argv[])
append_opt(&opts_str, "read_only");
while ((opt = getopt_long(argc, argv,
- "apynfo:rRkvh",
+ "apynfo:rRkKvh",
longopts, NULL)) != -1)
switch (opt) {
case 'a': /* outdated alias for -p */
@@ -232,7 +273,7 @@ int cmd_fsck(int argc, char *argv[])
darray_for_each(devs, i)
if (dev_mounted(*i)) {
printf("Running fsck online\n");
- return fsck_online(*i);
+ return fsck_online(*i, opts_str.buf);
}
int kernel_probed = kernel;
@@ -243,19 +284,35 @@ int cmd_fsck(int argc, char *argv[])
struct printbuf parse_later = PRINTBUF;
if (kernel_probed) {
+ darray_str loopdevs = {};
+ int fsck_fd = -1;
+
printf("Running in-kernel offline fsck\n");
- struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) +
- sizeof(u64) * devs.nr, 1);
+ struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) + sizeof(u64) * devs.nr, 1);
fsck->opts = (unsigned long)opts_str.buf;
- darray_for_each(devs, i)
- fsck->devs[i - devs.data] = (unsigned long) *i;
+ darray_for_each(devs, i) {
+ if (is_blockdev(*i)) {
+ fsck->devs[i - devs.data] = (unsigned long) *i;
+ } else {
+ char *l = loopdev_alloc(*i);
+ if (!l)
+ goto kernel_fsck_err;
+ darray_push(&loopdevs, l);
+ fsck->devs[i - devs.data] = (unsigned long) l;
+ }
+ }
fsck->nr_devs = devs.nr;
int ctl_fd = bcachectl_open();
- int fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck);
+ fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck);
+kernel_fsck_err:
free(fsck);
+ darray_for_each(loopdevs, i)
+ loopdev_free(*i);
+ darray_exit(&loopdevs);
+
if (fsck_fd < 0 && kernel < 0)
goto userland_fsck;