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