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