#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) {
}
}
-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)
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);
- }
-
- break;
- }
+ int fd = xopenat(dirfd, path, O_WRONLY);
+ ssize_t wrote, len = strlen(str);
- 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);
buf[len] = '\0';
if (len && buf[len - 1] == '\n')
buf[len - 1] = '\0';
+ if (!strlen(buf)) {
+ free(buf);
+ buf = NULL;
+ }
close(fd);
{
char *buf = read_file_str(dirfd, path);
u64 v;
- if (kstrtou64(buf, 10, &v))
+ if (bch2_strtou64_h(buf, &v))
die("read_file_u64: error parsing %s (got %s)", path, buf);
free(buf);
return v;
}
/* 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);
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);
if (!S_ISBLK(statbuf.st_mode))
- return statbuf.st_blksize >> 9;
+ return statbuf.st_blksize;
unsigned ret;
xioctl(fd, BLKPBSZGET, &ret);
- return ret >> 9;
+ return ret;
}
/* 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 = xopen(dev, O_RDWR|O_EXCL);
-
- 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);
+ 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 = { 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);
}
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);
{
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 *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)
return ret;
}
-bool dev_mounted_rw(char *dev)
+int dev_mounted(char *dev)
{
struct mntent *mnt = dev_to_mount(dev);
- return mnt && !hasmntopt(mnt, "ro");
+ if (!mnt)
+ return 0;
+ if (hasmntopt(mnt, "ro"))
+ return 1;
+ 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 *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 (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 (!(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);
+
+ 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;
}