]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - tools-util.c
fix list_journal for nochanges
[bcachefs-tools-debian] / tools-util.c
index 98cb350387c601f44a9935aedcce0c2521cf8ea4..5f0b9ba4fd5f7c279763c3f7df9a9da1d0ca0f59 100644 (file)
@@ -17,6 +17,7 @@
 #include <blkid.h>
 #include <uuid/uuid.h>
 
+#include "libbcachefs.h"
 #include "libbcachefs/bcachefs_ioctl.h"
 #include "linux/sort.h"
 #include "tools-util.h"
@@ -50,36 +51,6 @@ char *mprintf(const char *fmt, ...)
        return str;
 }
 
-void *xcalloc(size_t count, size_t size)
-{
-       void *p = calloc(count, size);
-
-       if (!p)
-               die("insufficient memory");
-
-       return p;
-}
-
-void *xmalloc(size_t size)
-{
-       void *p = malloc(size);
-
-       if (!p)
-               die("insufficient memory");
-
-       memset(p, 0, size);
-       return p;
-}
-
-void *xrealloc(void *p, size_t size)
-{
-       p = realloc(p, size);
-       if (!p)
-               die("insufficient memory");
-
-       return p;
-}
-
 void xpread(int fd, void *buf, size_t count, off_t offset)
 {
        while (count) {
@@ -94,12 +65,12 @@ void xpread(int fd, void *buf, size_t count, off_t offset)
        }
 }
 
-void xpwrite(int fd, const void *buf, size_t count, off_t offset)
+void xpwrite(int fd, const void *buf, size_t count, off_t offset, const char *msg)
 {
        ssize_t r = pwrite(fd, buf, count, offset);
 
        if (r != count)
-               die("write error (ret %zi err %m)", r);
+               die("error writing %s (ret %zi err %m)", msg, r);
 }
 
 struct stat xfstatat(int dirfd, const char *path, int flags)
@@ -126,63 +97,19 @@ struct stat xstat(const char *path)
        return statbuf;
 }
 
-/* Formatting: */
-
-int printf_pad(unsigned pad, const char * fmt, ...)
-{
-       va_list args;
-       int ret;
-
-       va_start(args, fmt);
-       ret = vprintf(fmt, args);
-       va_end(args);
-
-       while (ret++ < pad)
-              putchar(' ');
-
-       return ret;
-}
+/* File parsing (i.e. sysfs) */
 
-struct units_buf __pr_units(s64 _v, enum units units)
+void write_file_str(int dirfd, const char *path, const char *str)
 {
-       struct units_buf ret;
-       char *out = ret.b, *end = out + sizeof(ret.b);
-       u64 v = _v;
-
-       if (_v < 0) {
-               out += scnprintf(out, end - out, "-");
-               v = -_v;
-       }
-
-       switch (units) {
-       case BYTES:
-               snprintf(out, end - out, "%llu", v << 9);
-               break;
-       case SECTORS:
-               snprintf(out, end - out, "%llu", v);
-               break;
-       case HUMAN_READABLE:
-               v <<= 9;
-
-               if (v >= 1024) {
-                       int exp = log(v) / log(1024);
-                       snprintf(out, end - out, "%.1f%c",
-                                v / pow(1024, exp),
-                                "KMGTPE"[exp-1]);
-               } else {
-                       snprintf(out, end - out, "%llu", v);
-               }
+       int fd = xopenat(dirfd, path, O_WRONLY);
+       ssize_t wrote, len = strlen(str);
 
-               break;
-       }
-
-       return ret;
+       wrote = write(fd, str, len);
+       if (wrote != len)
+               die("read error: %m");
+       close(fd);
 }
 
-/* Argument parsing stuff: */
-
-/* File parsing (i.e. sysfs) */
-
 char *read_file_str(int dirfd, const char *path)
 {
        int fd = xopenat(dirfd, path, O_RDONLY);
@@ -230,7 +157,7 @@ ssize_t read_string_list_or_die(const char *opt, const char * const list[],
 }
 
 /* Returns size of file or block device: */
-u64 get_size(const char *path, int fd)
+u64 get_size(int fd)
 {
        struct stat statbuf = xfstat(fd);
 
@@ -242,8 +169,8 @@ u64 get_size(const char *path, int fd)
        return ret;
 }
 
-/* Returns blocksize in units of 512 byte sectors: */
-unsigned get_blocksize(const char *path, int fd)
+/* Returns blocksize, in bytes: */
+unsigned get_blocksize(int fd)
 {
        struct stat statbuf = xfstat(fd);
 
@@ -256,24 +183,26 @@ unsigned get_blocksize(const char *path, int fd)
 }
 
 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
-int open_for_format(const char *dev, bool force)
+int open_for_format(struct dev_opts *dev, bool force)
 {
        blkid_probe pr;
        const char *fs_type = NULL, *fs_label = NULL;
        size_t fs_type_len, fs_label_len;
 
-       int fd = open(dev, O_RDWR|O_EXCL);
-       if (fd < 0)
-               die("Error opening device to format %s: %m", dev);
-
-       if (force)
-               return fd;
+       dev->bdev = blkdev_get_by_path(dev->path, BLK_OPEN_READ|BLK_OPEN_WRITE|BLK_OPEN_EXCL,
+                                      dev, NULL);
+       int ret = PTR_ERR_OR_ZERO(dev->bdev);
+       if (ret < 0)
+               die("Error opening device to format %s: %s", dev->path, strerror(-ret));
 
        if (!(pr = blkid_new_probe()))
                die("blkid error 1");
-       if (blkid_probe_set_device(pr, fd, 0, 0))
+       if (blkid_probe_set_device(pr, dev->bdev->bd_buffered_fd, 0, 0))
                die("blkid error 2");
-       if (blkid_probe_enable_partitions(pr, true))
+       if (blkid_probe_enable_partitions(pr, true) ||
+           blkid_probe_enable_superblocks(pr, true) ||
+           blkid_probe_set_superblocks_flags(pr,
+                       BLKID_SUBLKS_LABEL|BLKID_SUBLKS_TYPE|BLKID_SUBLKS_MAGIC))
                die("blkid error 3");
        if (blkid_do_fullprobe(pr) < 0)
                die("blkid error 4");
@@ -284,19 +213,23 @@ int open_for_format(const char *dev, bool force)
        if (fs_type) {
                if (fs_label)
                        printf("%s contains a %s filesystem labelled '%s'\n",
-                              dev, fs_type, fs_label);
+                              dev->path, fs_type, fs_label);
                else
                        printf("%s contains a %s filesystem\n",
-                              dev, fs_type);
-               fputs("Proceed anyway?", stdout);
-               if (!ask_yn())
-                       exit(EXIT_FAILURE);
-               while (blkid_do_probe(pr) == 0)
-                       blkid_do_wipe(pr, 0);
+                              dev->path, fs_type);
+               if (!force) {
+                       fputs("Proceed anyway?", stdout);
+                       if (!ask_yn())
+                               exit(EXIT_FAILURE);
+               }
+               while (blkid_do_probe(pr) == 0) {
+                       if (blkid_do_wipe(pr, 0))
+                               die("Failed to wipe preexisting metadata.");
+               }
        }
 
        blkid_free_probe(pr);
-       return fd;
+       return ret;
 }
 
 bool ask_yn(void)
@@ -330,31 +263,27 @@ static int range_cmp(const void *_l, const void *_r)
 
 void ranges_sort_merge(ranges *r)
 {
-       struct range *t, *i;
-       ranges tmp = { NULL };
+       ranges tmp = { 0 };
 
-       sort(&darray_item(*r, 0), darray_size(*r),
-            sizeof(darray_item(*r, 0)), range_cmp, NULL);
+       sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
 
        /* Merge contiguous ranges: */
-       darray_foreach(i, *r) {
-               t = tmp.size ?  &tmp.item[tmp.size - 1] : NULL;
+       darray_for_each(*r, i) {
+               struct range *t = tmp.nr ?  &tmp.data[tmp.nr - 1] : NULL;
 
                if (t && t->end >= i->start)
                        t->end = max(t->end, i->end);
                else
-                       darray_append(tmp, *i);
+                       darray_push(&tmp, *i);
        }
 
-       darray_free(*r);
+       darray_exit(r);
        *r = tmp;
 }
 
 void ranges_roundup(ranges *r, unsigned block_size)
 {
-       struct range *i;
-
-       darray_foreach(i, *r) {
+       darray_for_each(*r, i) {
                i->start = round_down(i->start, block_size);
                i->end  = round_up(i->end, block_size);
        }
@@ -362,9 +291,7 @@ void ranges_roundup(ranges *r, unsigned block_size)
 
 void ranges_rounddown(ranges *r, unsigned block_size)
 {
-       struct range *i;
-
-       darray_foreach(i, *r) {
+       darray_for_each(*r, i) {
                i->start = round_up(i->start, block_size);
                i->end  = round_down(i->end, block_size);
                i->end  = max(i->end, i->start);
@@ -375,21 +302,21 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
 {
        struct fiemap_extent e;
 
-       BUG_ON(iter->idx > iter->f.fm_mapped_extents);
+       BUG_ON(iter->idx > iter->f->fm_mapped_extents);
 
-       if (iter->idx == iter->f.fm_mapped_extents) {
-               xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
+       if (iter->idx == iter->f->fm_mapped_extents) {
+               xioctl(iter->fd, FS_IOC_FIEMAP, iter->f);
 
-               if (!iter->f.fm_mapped_extents)
+               if (!iter->f->fm_mapped_extents)
                        return (struct fiemap_extent) { .fe_length = 0 };
 
                iter->idx = 0;
        }
 
-       e = iter->f.fm_extents[iter->idx++];
+       e = iter->f->fm_extents[iter->idx++];
        BUG_ON(!e.fe_length);
 
-       iter->f.fm_start = e.fe_logical + e.fe_length;
+       iter->f->fm_start = e.fe_logical + e.fe_length;
 
        return e;
 }
@@ -403,24 +330,6 @@ char *strcmp_prefix(char *a, const char *a_prefix)
        return *a_prefix ? NULL : a;
 }
 
-unsigned hatoi_validate(const char *s, const char *msg)
-{
-       u64 v;
-
-       if (bch2_strtoull_h(s, &v))
-               die("bad %s %s", msg, s);
-
-       v /= 512;
-
-       if (v > USHRT_MAX)
-               die("%s too large\n", msg);
-
-       if (!v)
-               die("%s too small\n", msg);
-
-       return v;
-}
-
 /* crc32c */
 
 static u32 crc32c_default(u32 crc, const void *buf, size_t size)
@@ -668,21 +577,90 @@ int dev_mounted(char *dev)
        return 2;
 }
 
+static int kstrtoull_symbolic(const char *s, unsigned int base, unsigned long long *res)
+{
+       if (!strcmp(s, "U64_MAX")) {
+               *res = U64_MAX;
+               return 0;
+       }
+
+       if (!strcmp(s, "U32_MAX")) {
+               *res = U32_MAX;
+               return 0;
+       }
+
+       return kstrtoull(s, base, res);
+}
+
+static int kstrtouint_symbolic(const char *s, unsigned int base, unsigned *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull_symbolic(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(unsigned int)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+
 struct bpos bpos_parse(char *buf)
 {
-       char *s = buf, *field;
+       char *orig = strdup(buf);
+       char *s = buf;
+
+       char *inode_s   = strsep(&s, ":");
+       char *offset_s  = strsep(&s, ":");
+       char *snapshot_s = strsep(&s, ":");
+
+       if (!inode_s || !offset_s || s)
+               die("invalid bpos %s", orig);
+       free(orig);
+
        u64 inode_v = 0, offset_v = 0;
+       u32 snapshot_v = 0;
+       if (kstrtoull_symbolic(inode_s, 10, &inode_v))
+               die("invalid bpos.inode %s", inode_s);
 
-       if (!(field = strsep(&s, ":")) ||
-           kstrtoull(field, 10, &inode_v))
-               die("invalid bpos %s", buf);
+       if (kstrtoull_symbolic(offset_s, 10, &offset_v))
+               die("invalid bpos.offset %s", offset_s);
 
-       if ((field = strsep(&s, ":")) &&
-           kstrtoull(field, 10, &offset_v))
-               die("invalid bpos %s", buf);
+       if (snapshot_s &&
+           kstrtouint_symbolic(snapshot_s, 10, &snapshot_v))
+               die("invalid bpos.snapshot %s", snapshot_s);
+
+       return (struct bpos) { .inode = inode_v, .offset = offset_v, .snapshot = snapshot_v };
+}
+
+struct bbpos bbpos_parse(char *buf)
+{
+       char *s = buf, *field;
+       struct bbpos ret;
 
-       if (s)
-               die("invalid bpos %s", buf);
+       if (!(field = strsep(&s, ":")))
+               die("invalid bbpos %s", buf);
 
-       return (struct bpos) { .inode = inode_v, .offset = offset_v };
+       ret.btree = read_string_list_or_die(field, __bch2_btree_ids, "btree id");
+
+       if (!s)
+               die("invalid bbpos %s", buf);
+
+       ret.pos = bpos_parse(s);
+       return ret;
+}
+
+darray_str get_or_split_cmdline_devs(int argc, char *argv[])
+{
+       darray_str ret = {};
+
+       if (argc == 1) {
+               bch2_split_devs(argv[0], &ret);
+       } else {
+               for (unsigned i = 0; i < argc; i++)
+                       darray_push(&ret, strdup(argv[i]));
+       }
+
+       return ret;
 }