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