11 #include <sys/ioctl.h>
13 #include <sys/types.h>
17 #include <uuid/uuid.h>
19 #include "ccan/crc/crc.h"
21 #include "bcachefs_ioctl.h"
22 #include "linux/sort.h"
23 #include "tools-util.h"
26 void die(const char *fmt, ...)
31 vfprintf(stderr, fmt, args);
38 char *mprintf(const char *fmt, ...)
45 ret = vasprintf(&str, fmt, args);
49 die("insufficient memory");
54 void *xcalloc(size_t count, size_t size)
56 void *p = calloc(count, size);
59 die("insufficient memory");
64 void *xmalloc(size_t size)
66 void *p = malloc(size);
69 die("insufficient memory");
75 void xpread(int fd, void *buf, size_t count, off_t offset)
77 ssize_t r = pread(fd, buf, count, offset);
80 die("read error (ret %zi)", r);
83 void xpwrite(int fd, const void *buf, size_t count, off_t offset)
85 ssize_t r = pwrite(fd, buf, count, offset);
88 die("write error (ret %zi err %m)", r);
91 struct stat xfstatat(int dirfd, const char *path, int flags)
94 if (fstatat(dirfd, path, &stat, flags))
95 die("stat error: %m");
99 struct stat xfstat(int fd)
102 if (fstat(fd, &stat))
103 die("stat error: %m");
109 struct units_buf __pr_units(u64 v, enum units units)
111 struct units_buf ret;
115 snprintf(ret.b, sizeof(ret.b), "%llu", v << 9);
118 snprintf(ret.b, sizeof(ret.b), "%llu", v);
124 int exp = log(v) / log(1024);
125 snprintf(ret.b, sizeof(ret.b), "%.1f%c",
129 snprintf(ret.b, sizeof(ret.b), "%llu", v);
138 /* Argument parsing stuff: */
140 /* File parsing (i.e. sysfs) */
142 char *read_file_str(int dirfd, const char *path)
144 int fd = xopenat(dirfd, path, O_RDONLY);
145 ssize_t len = xfstat(fd).st_size;
147 char *buf = xmalloc(len + 1);
149 len = read(fd, buf, len);
151 die("read error: %m");
154 if (len && buf[len - 1] == '\n')
162 u64 read_file_u64(int dirfd, const char *path)
164 char *buf = read_file_str(dirfd, path);
166 if (kstrtou64(buf, 10, &v))
167 die("read_file_u64: error parsing %s (got %s)", path, buf);
172 /* String list options: */
174 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
177 ssize_t v = bch2_read_string_list(opt, list);
179 die("Bad %s %s", msg, opt);
184 /* Returns size of file or block device: */
185 u64 get_size(const char *path, int fd)
187 struct stat statbuf = xfstat(fd);
189 if (!S_ISBLK(statbuf.st_mode))
190 return statbuf.st_size;
193 xioctl(fd, BLKGETSIZE64, &ret);
197 /* Returns blocksize in units of 512 byte sectors: */
198 unsigned get_blocksize(const char *path, int fd)
200 struct stat statbuf = xfstat(fd);
202 if (!S_ISBLK(statbuf.st_mode))
203 return statbuf.st_blksize >> 9;
206 xioctl(fd, BLKPBSZGET, &ret);
210 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
211 int open_for_format(const char *dev, bool force)
214 const char *fs_type = NULL, *fs_label = NULL;
215 size_t fs_type_len, fs_label_len;
217 int fd = xopen(dev, O_RDWR|O_EXCL);
222 if (!(pr = blkid_new_probe()))
223 die("blkid error 1");
224 if (blkid_probe_set_device(pr, fd, 0, 0))
225 die("blkid error 2");
226 if (blkid_probe_enable_partitions(pr, true))
227 die("blkid error 3");
228 if (blkid_do_fullprobe(pr) < 0)
229 die("blkid error 4");
231 blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
232 blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
236 printf("%s contains a %s filesystem labelled '%s'\n",
237 dev, fs_type, fs_label);
239 printf("%s contains a %s filesystem\n",
241 fputs("Proceed anyway?", stdout);
246 blkid_free_probe(pr);
250 /* Global control device: */
251 int bcachectl_open(void)
253 return xopen("/dev/bcachefs-ctl", O_RDWR);
256 /* Filesystem handles (ioctl, sysfs dir): */
258 #define SYSFS_BASE "/sys/fs/bcachefs/"
260 struct bcache_handle bcache_fs_open(const char *path)
262 struct bcache_handle ret;
265 if (!uuid_parse(path, tmp)) {
266 /* It's a UUID, look it up in sysfs: */
267 char *sysfs = mprintf("%s%s", SYSFS_BASE, path);
268 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
270 char *minor = read_file_str(ret.sysfs_fd, "minor");
271 char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
272 ret.ioctl_fd = xopen(ctl, O_RDWR);
279 ret.ioctl_fd = xopen(path, O_RDONLY);
281 struct bch_ioctl_query_uuid uuid;
282 xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid);
285 uuid_unparse(uuid.uuid.b, uuid_str);
287 char *sysfs = mprintf("%s%s", SYSFS_BASE, uuid_str);
288 ret.sysfs_fd = xopen(sysfs, O_RDONLY);
297 const char *short_yes = "yY";
302 fputs(" (y,n) ", stdout);
305 if (getline(&buf, &buflen, stdin) < 0)
306 die("error reading from standard input");
308 ret = strchr(short_yes, buf[0]);
313 static int range_cmp(const void *_l, const void *_r)
315 const struct range *l = _l, *r = _r;
317 if (l->start < r->start)
319 if (l->start > r->start)
324 void ranges_sort_merge(ranges *r)
327 ranges tmp = { NULL };
329 sort(&darray_item(*r, 0), darray_size(*r),
330 sizeof(darray_item(*r, 0)), range_cmp, NULL);
332 /* Merge contiguous ranges: */
333 darray_foreach(i, *r) {
334 t = tmp.size ? &tmp.item[tmp.size - 1] : NULL;
336 if (t && t->end >= i->start)
337 t->end = max(t->end, i->end);
339 darray_append(tmp, *i);
346 void ranges_roundup(ranges *r, unsigned block_size)
350 darray_foreach(i, *r) {
351 i->start = round_down(i->start, block_size);
352 i->end = round_up(i->end, block_size);
356 void ranges_rounddown(ranges *r, unsigned block_size)
360 darray_foreach(i, *r) {
361 i->start = round_up(i->start, block_size);
362 i->end = round_down(i->end, block_size);
363 i->end = max(i->end, i->start);
367 struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
369 struct fiemap_extent e;
371 BUG_ON(iter->idx > iter->f.fm_mapped_extents);
373 if (iter->idx == iter->f.fm_mapped_extents) {
374 xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
376 if (!iter->f.fm_mapped_extents)
377 return (struct fiemap_extent) { .fe_length = 0 };
382 e = iter->f.fm_extents[iter->idx++];
383 BUG_ON(!e.fe_length);
385 iter->f.fm_start = e.fe_logical + e.fe_length;
390 const char *strcmp_prefix(const char *a, const char *a_prefix)
392 while (*a_prefix && *a == *a_prefix) {
396 return *a_prefix ? NULL : a;
399 unsigned hatoi_validate(const char *s, const char *msg)
403 if (bch2_strtoull_h(s, &v))
404 die("bad %s %s", msg, s);
407 die("%s must be a power of two", msg);
412 die("%s too large\n", msg);
415 die("%s too small\n", msg);