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