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