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