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