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