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