#include <blkid.h>
#include <uuid/uuid.h>
+#include "libbcachefs.h"
#include "libbcachefs/bcachefs_ioctl.h"
#include "linux/sort.h"
#include "tools-util.h"
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) {
}
/* 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);
}
/* Returns blocksize, in bytes: */
-unsigned get_blocksize(const char *path, int fd)
+unsigned get_blocksize(int fd)
{
struct stat statbuf = xfstat(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");
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)
void ranges_sort_merge(ranges *r)
{
- struct range *t, *i;
ranges tmp = { 0 };
sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
/* Merge contiguous ranges: */
darray_for_each(*r, i) {
- t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
+ struct range *t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
if (t && t->end >= i->start)
t->end = max(t->end, i->end);
void ranges_roundup(ranges *r, unsigned block_size)
{
- struct range *i;
-
darray_for_each(*r, i) {
i->start = round_down(i->start, block_size);
i->end = round_up(i->end, block_size);
void ranges_rounddown(ranges *r, unsigned block_size)
{
- struct range *i;
-
darray_for_each(*r, i) {
i->start = round_up(i->start, block_size);
i->end = round_down(i->end, block_size);
{
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;
}
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 (kstrtoull_symbolic(offset_s, 10, &offset_v))
+ die("invalid bpos.offset %s", offset_s);
- if (!(field = strsep(&s, ":")) ||
- kstrtoull(field, 10, &inode_v))
- die("invalid bpos %s", buf);
+ if (snapshot_s &&
+ kstrtouint_symbolic(snapshot_s, 10, &snapshot_v))
+ die("invalid bpos.snapshot %s", snapshot_s);
- if ((field = strsep(&s, ":")) &&
- kstrtoull(field, 10, &offset_v))
- die("invalid bpos %s", buf);
+ 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 (!(field = strsep(&s, ":")))
+ die("invalid bbpos %s", buf);
+
+ ret.btree = read_string_list_or_die(field, __bch2_btree_ids, "btree id");
+
+ if (!s)
+ die("invalid bbpos %s", buf);
- if (s)
- die("invalid bpos %s", buf);
+ ret.pos = bpos_parse(s);
+ return ret;
+}
+
+darray_str get_or_split_cmdline_devs(int argc, char *argv[])
+{
+ darray_str ret = {};
- return (struct bpos) { .inode = inode_v, .offset = offset_v };
+ 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;
}