]> git.sesse.net Git - bcachefs-tools-debian/blob - tools-util.c
cmd_migrate fixes
[bcachefs-tools-debian] / tools-util.c
1 #include <assert.h>
2 #include <ctype.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <linux/fs.h>
7 #include <math.h>
8 #include <stdbool.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <sys/stat.h>
13 #include <sys/sysmacros.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <blkid.h>
18 #include <uuid/uuid.h>
19
20 #include "libbcachefs/bcachefs_ioctl.h"
21 #include "linux/sort.h"
22 #include "tools-util.h"
23 #include "libbcachefs/util.h"
24
25 void die(const char *fmt, ...)
26 {
27         va_list args;
28
29         va_start(args, fmt);
30         vfprintf(stderr, fmt, args);
31         va_end(args);
32         fputc('\n', stderr);
33
34         exit(EXIT_FAILURE);
35 }
36
37 char *mprintf(const char *fmt, ...)
38 {
39         va_list args;
40         char *str;
41         int ret;
42
43         va_start(args, fmt);
44         ret = vasprintf(&str, fmt, args);
45         va_end(args);
46
47         if (ret < 0)
48                 die("insufficient memory");
49
50         return str;
51 }
52
53 void *xcalloc(size_t count, size_t size)
54 {
55         void *p = calloc(count, size);
56
57         if (!p)
58                 die("insufficient memory");
59
60         return p;
61 }
62
63 void *xmalloc(size_t size)
64 {
65         void *p = malloc(size);
66
67         if (!p)
68                 die("insufficient memory");
69
70         memset(p, 0, size);
71         return p;
72 }
73
74 void *xrealloc(void *p, size_t size)
75 {
76         p = realloc(p, size);
77         if (!p)
78                 die("insufficient memory");
79
80         return p;
81 }
82
83 void xpread(int fd, void *buf, size_t count, off_t offset)
84 {
85         while (count) {
86                 ssize_t r = pread(fd, buf, count, offset);
87
88                 if (r < 0)
89                         die("read error: %m");
90                 if (!r)
91                         die("pread error: unexpected eof");
92                 count   -= r;
93                 offset  += r;
94         }
95 }
96
97 void xpwrite(int fd, const void *buf, size_t count, off_t offset)
98 {
99         ssize_t r = pwrite(fd, buf, count, offset);
100
101         if (r != count)
102                 die("write error (ret %zi err %m)", r);
103 }
104
105 struct stat xfstatat(int dirfd, const char *path, int flags)
106 {
107         struct stat stat;
108         if (fstatat(dirfd, path, &stat, flags))
109                 die("stat error: %m");
110         return stat;
111 }
112
113 struct stat xfstat(int fd)
114 {
115         struct stat stat;
116         if (fstat(fd, &stat))
117                 die("stat error: %m");
118         return stat;
119 }
120
121 /* Formatting: */
122
123 int printf_pad(unsigned pad, const char * fmt, ...)
124 {
125        va_list args;
126        int ret;
127
128        va_start(args, fmt);
129        ret = vprintf(fmt, args);
130        va_end(args);
131
132        while (ret++ < pad)
133                putchar(' ');
134
135        return ret;
136 }
137
138 struct units_buf __pr_units(s64 _v, enum units units)
139 {
140         struct units_buf ret;
141         char *out = ret.b, *end = out + sizeof(ret.b);
142         u64 v = _v;
143
144         if (_v < 0) {
145                 out += scnprintf(out, end - out, "-");
146                 v = -_v;
147         }
148
149         switch (units) {
150         case BYTES:
151                 snprintf(out, end - out, "%llu", v << 9);
152                 break;
153         case SECTORS:
154                 snprintf(out, end - out, "%llu", v);
155                 break;
156         case HUMAN_READABLE:
157                 v <<= 9;
158
159                 if (v >= 1024) {
160                         int exp = log(v) / log(1024);
161                         snprintf(out, end - out, "%.1f%c",
162                                  v / pow(1024, exp),
163                                  "KMGTPE"[exp-1]);
164                 } else {
165                         snprintf(out, end - out, "%llu", v);
166                 }
167
168                 break;
169         }
170
171         return ret;
172 }
173
174 /* Argument parsing stuff: */
175
176 /* File parsing (i.e. sysfs) */
177
178 char *read_file_str(int dirfd, const char *path)
179 {
180         int fd = xopenat(dirfd, path, O_RDONLY);
181         ssize_t len = xfstat(fd).st_size;
182
183         char *buf = xmalloc(len + 1);
184
185         len = read(fd, buf, len);
186         if (len < 0)
187                 die("read error: %m");
188
189         buf[len] = '\0';
190         if (len && buf[len - 1] == '\n')
191                 buf[len - 1] = '\0';
192
193         close(fd);
194
195         return buf;
196 }
197
198 u64 read_file_u64(int dirfd, const char *path)
199 {
200         char *buf = read_file_str(dirfd, path);
201         u64 v;
202         if (kstrtou64(buf, 10, &v))
203                 die("read_file_u64: error parsing %s (got %s)", path, buf);
204         free(buf);
205         return v;
206 }
207
208 /* String list options: */
209
210 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
211                                 const char *msg)
212 {
213         ssize_t v = bch2_read_string_list(opt, list);
214         if (v < 0)
215                 die("Bad %s %s", msg, opt);
216
217         return v;
218 }
219
220 /* Returns size of file or block device: */
221 u64 get_size(const char *path, int fd)
222 {
223         struct stat statbuf = xfstat(fd);
224
225         if (!S_ISBLK(statbuf.st_mode))
226                 return statbuf.st_size;
227
228         u64 ret;
229         xioctl(fd, BLKGETSIZE64, &ret);
230         return ret;
231 }
232
233 /* Returns blocksize in units of 512 byte sectors: */
234 unsigned get_blocksize(const char *path, int fd)
235 {
236         struct stat statbuf = xfstat(fd);
237
238         if (!S_ISBLK(statbuf.st_mode))
239                 return statbuf.st_blksize >> 9;
240
241         unsigned ret;
242         xioctl(fd, BLKPBSZGET, &ret);
243         return ret >> 9;
244 }
245
246 /* Open a block device, do magic blkid stuff to probe for existing filesystems: */
247 int open_for_format(const char *dev, bool force)
248 {
249         blkid_probe pr;
250         const char *fs_type = NULL, *fs_label = NULL;
251         size_t fs_type_len, fs_label_len;
252
253         int fd = xopen(dev, O_RDWR|O_EXCL);
254
255         if (force)
256                 return fd;
257
258         if (!(pr = blkid_new_probe()))
259                 die("blkid error 1");
260         if (blkid_probe_set_device(pr, fd, 0, 0))
261                 die("blkid error 2");
262         if (blkid_probe_enable_partitions(pr, true))
263                 die("blkid error 3");
264         if (blkid_do_fullprobe(pr) < 0)
265                 die("blkid error 4");
266
267         blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
268         blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
269
270         if (fs_type) {
271                 if (fs_label)
272                         printf("%s contains a %s filesystem labelled '%s'\n",
273                                dev, fs_type, fs_label);
274                 else
275                         printf("%s contains a %s filesystem\n",
276                                dev, fs_type);
277                 fputs("Proceed anyway?", stdout);
278                 if (!ask_yn())
279                         exit(EXIT_FAILURE);
280         }
281
282         blkid_free_probe(pr);
283         return fd;
284 }
285
286 bool ask_yn(void)
287 {
288         const char *short_yes = "yY";
289         char *buf = NULL;
290         size_t buflen = 0;
291         bool ret;
292
293         fputs(" (y,n) ", stdout);
294         fflush(stdout);
295
296         if (getline(&buf, &buflen, stdin) < 0)
297                 die("error reading from standard input");
298
299         ret = strchr(short_yes, buf[0]);
300         free(buf);
301         return ret;
302 }
303
304 static int range_cmp(const void *_l, const void *_r)
305 {
306         const struct range *l = _l, *r = _r;
307
308         if (l->start < r->start)
309                 return -1;
310         if (l->start > r->start)
311                 return  1;
312         return 0;
313 }
314
315 void ranges_sort_merge(ranges *r)
316 {
317         struct range *t, *i;
318         ranges tmp = { NULL };
319
320         sort(&darray_item(*r, 0), darray_size(*r),
321              sizeof(darray_item(*r, 0)), range_cmp, NULL);
322
323         /* Merge contiguous ranges: */
324         darray_foreach(i, *r) {
325                 t = tmp.size ?  &tmp.item[tmp.size - 1] : NULL;
326
327                 if (t && t->end >= i->start)
328                         t->end = max(t->end, i->end);
329                 else
330                         darray_append(tmp, *i);
331         }
332
333         darray_free(*r);
334         *r = tmp;
335 }
336
337 void ranges_roundup(ranges *r, unsigned block_size)
338 {
339         struct range *i;
340
341         darray_foreach(i, *r) {
342                 i->start = round_down(i->start, block_size);
343                 i->end  = round_up(i->end, block_size);
344         }
345 }
346
347 void ranges_rounddown(ranges *r, unsigned block_size)
348 {
349         struct range *i;
350
351         darray_foreach(i, *r) {
352                 i->start = round_up(i->start, block_size);
353                 i->end  = round_down(i->end, block_size);
354                 i->end  = max(i->end, i->start);
355         }
356 }
357
358 struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter)
359 {
360         struct fiemap_extent e;
361
362         BUG_ON(iter->idx > iter->f.fm_mapped_extents);
363
364         if (iter->idx == iter->f.fm_mapped_extents) {
365                 xioctl(iter->fd, FS_IOC_FIEMAP, &iter->f);
366
367                 if (!iter->f.fm_mapped_extents)
368                         return (struct fiemap_extent) { .fe_length = 0 };
369
370                 iter->idx = 0;
371         }
372
373         e = iter->f.fm_extents[iter->idx++];
374         BUG_ON(!e.fe_length);
375
376         iter->f.fm_start = e.fe_logical + e.fe_length;
377
378         return e;
379 }
380
381 const char *strcmp_prefix(const char *a, const char *a_prefix)
382 {
383         while (*a_prefix && *a == *a_prefix) {
384                 a++;
385                 a_prefix++;
386         }
387         return *a_prefix ? NULL : a;
388 }
389
390 unsigned hatoi_validate(const char *s, const char *msg)
391 {
392         u64 v;
393
394         if (bch2_strtoull_h(s, &v))
395                 die("bad %s %s", msg, s);
396
397         v /= 512;
398
399         if (v > USHRT_MAX)
400                 die("%s too large\n", msg);
401
402         if (!v)
403                 die("%s too small\n", msg);
404
405         return v;
406 }
407
408 /* crc32c */
409
410 static u32 crc32c_default(u32 crc, const void *buf, size_t size)
411 {
412         static const u32 crc32c_tab[] = {
413                 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
414                 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
415                 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
416                 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
417                 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
418                 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
419                 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
420                 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
421                 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
422                 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
423                 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
424                 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
425                 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
426                 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
427                 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
428                 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
429                 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
430                 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
431                 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
432                 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
433                 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
434                 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
435                 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
436                 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
437                 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
438                 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
439                 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
440                 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
441                 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
442                 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
443                 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
444                 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
445                 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
446                 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
447                 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
448                 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
449                 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
450                 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
451                 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
452                 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
453                 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
454                 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
455                 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
456                 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
457                 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
458                 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
459                 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
460                 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
461                 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
462                 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
463                 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
464                 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
465                 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
466                 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
467                 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
468                 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
469                 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
470                 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
471                 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
472                 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
473                 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
474                 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
475                 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
476                 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
477         };
478         const u8 *p = buf;
479
480         while (size--)
481                 crc = crc32c_tab[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
482
483         return crc;
484 }
485
486 #include <linux/compiler.h>
487
488 #ifdef __x86_64__
489
490 #ifdef CONFIG_X86_64
491 #define REX_PRE "0x48, "
492 #else
493 #define REX_PRE
494 #endif
495
496 static u32 crc32c_sse42(u32 crc, const void *buf, size_t size)
497 {
498         while (size >= sizeof(long)) {
499                 const unsigned long *d = buf;
500
501                 __asm__ __volatile__(
502                         ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
503                         :"=S"(crc)
504                         :"0"(crc), "c"(*d)
505                 );
506                 buf     += sizeof(long);
507                 size    -= sizeof(long);
508         }
509
510         while (size) {
511                 const u8 *d = buf;
512
513                 __asm__ __volatile__(
514                         ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
515                         :"=S"(crc)
516                         :"0"(crc), "c"(*d)
517                 );
518                 buf     += 1;
519                 size    -= 1;
520         }
521
522         return crc;
523 }
524
525 static void *resolve_crc32c(void)
526 {
527         __builtin_cpu_init();
528
529 #ifdef __x86_64__
530         if (__builtin_cpu_supports("sse4.2"))
531                 return crc32c_sse42;
532 #endif
533         return crc32c_default;
534 }
535
536 /*
537  * ifunc is buggy and I don't know what breaks it (LTO?)
538  */
539 #ifdef HAVE_WORKING_IFUNC
540
541 u32 crc32c(u32, const void *, size_t)
542         __attribute__((ifunc("resolve_crc32c")));
543
544 #else
545
546 u32 crc32c(u32 crc, const void *buf, size_t size)
547 {
548         static u32 (*real_crc32c)(u32, const void *, size_t);
549
550         if (unlikely(!real_crc32c))
551                 real_crc32c = resolve_crc32c();
552
553         return real_crc32c(crc, buf, size);
554 }
555
556 #endif /* HAVE_WORKING_IFUNC */
557
558 char *dev_to_name(dev_t dev)
559 {
560         char *line = NULL, *name = NULL;
561         size_t n = 0;
562
563         FILE *f = fopen("/proc/partitions", "r");
564         if (!f)
565                 die("error opening /proc/partitions: %m");
566
567         while (getline(&line, &n, f) != -1) {
568                 unsigned ma, mi;
569                 u64 sectors;
570
571                 name = realloc(name, n + 1);
572
573                 if (sscanf(line, " %u %u %llu %s", &ma, &mi, &sectors, name) == 4 &&
574                     ma == major(dev) && mi == minor(dev))
575                         goto found;
576         }
577
578         free(name);
579         name = NULL;
580 found:
581         fclose(f);
582         free(line);
583         return name;
584 }
585
586 char *dev_to_path(dev_t dev)
587 {
588         char *name = dev_to_name(dev);
589         if (!name)
590                 return NULL;
591
592         char *path = mprintf("/dev/%s", name);
593
594         free(name);
595         return path;
596 }
597
598 char *dev_to_mount(char *dev)
599 {
600         char *line = NULL, *ret = NULL;
601         size_t n = 0;
602
603         FILE *f = fopen("/proc/mounts", "r");
604         if (!f)
605                 die("error opening /proc/mounts: %m");
606
607         while (getline(&line, &n, f) != -1) {
608                 char *d, *p = line;
609                 char *devs = strsep(&p, " ");
610                 char *mount = strsep(&p, " ");
611
612                 if (!devs || !mount)
613                         continue;
614
615                 p = devs;
616                 while ((d = strsep(&p, ":")))
617                         if (!strcmp(d, dev)) {
618                                 ret = strdup(mount);
619                                 goto found;
620                         }
621         }
622 found:
623         fclose(f);
624         free(line);
625         return ret;
626 }
627
628 #endif