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