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