]> git.sesse.net Git - bcachefs-tools-debian/blob - util.c
Redo lots of stuff
[bcachefs-tools-debian] / util.c
1 #include <alloca.h>
2 #include <ctype.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <linux/fs.h>
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14
15 #include <blkid.h>
16 #include <uuid/uuid.h>
17
18 #include "ccan/crc/crc.h"
19
20 #include "util.h"
21
22 /* Integer stuff: */
23
24 u64 rounddown_pow_of_two(u64 n)
25 {
26         u64 ret;
27
28         do {
29                 ret = n;
30                 n &= n - 1;
31         } while (n);
32
33         return ret;
34 }
35
36 unsigned ilog2(u64 n)
37 {
38         unsigned ret = 0;
39
40         while (n) {
41                 ret++;
42                 n >>= 1;
43         }
44
45         return ret;
46 }
47
48 char *skip_spaces(const char *str)
49 {
50         while (isspace(*str))
51                 ++str;
52         return (char *)str;
53 }
54
55 char *strim(char *s)
56 {
57         size_t size;
58         char *end;
59
60         s = skip_spaces(s);
61         size = strlen(s);
62         if (!size)
63                 return s;
64
65         end = s + size - 1;
66         while (end >= s && isspace(*end))
67                 end--;
68         *(end + 1) = '\0';
69
70         return s;
71 }
72
73 /* Argument parsing stuff: */
74
75 long strtoul_or_die(const char *p, size_t max, const char *msg)
76 {
77         errno = 0;
78         long v = strtol(p, NULL, 10);
79         if (errno || v < 0 || v >= max)
80                 die("Invalid %s %zi", msg, v);
81
82         return v;
83 }
84
85 u64 hatoi(const char *s)
86 {
87         char *e;
88         long long i = strtoll(s, &e, 10);
89         switch (*e) {
90                 case 't':
91                 case 'T':
92                         i *= 1024;
93                 case 'g':
94                 case 'G':
95                         i *= 1024;
96                 case 'm':
97                 case 'M':
98                         i *= 1024;
99                 case 'k':
100                 case 'K':
101                         i *= 1024;
102         }
103         return i;
104 }
105
106 unsigned hatoi_validate(const char *s, const char *msg)
107 {
108         u64 v = hatoi(s);
109
110         if (v & (v - 1))
111                 die("%s must be a power of two", msg);
112
113         v /= 512;
114
115         if (v > USHRT_MAX)
116                 die("%s too large\n", msg);
117
118         if (!v)
119                 die("%s too small\n", msg);
120
121         return v;
122 }
123
124 unsigned nr_args(char * const *args)
125 {
126         unsigned i;
127
128         for (i = 0; args[i]; i++)
129                 ;
130
131         return i;
132 }
133
134 /* File parsing (i.e. sysfs) */
135
136 char *read_file_str(int dirfd, const char *path)
137 {
138         int fd = openat(dirfd, path, O_RDONLY);
139
140         if (fd < 0)
141                 die("Unable to open %s\n", path);
142
143         struct stat statbuf;
144         if (fstat(fd, &statbuf) < 0)
145                 die("fstat error\n");
146
147         char *buf = malloc(statbuf.st_size + 1);
148
149         int len = read(fd, buf, statbuf.st_size);
150         if (len < 0)
151                 die("read error while reading from file %s\n", path);
152
153         buf[len] = '\0';
154         if (len && buf[len - 1] == '\n')
155                 buf[len - 1] = '\0';
156
157         close(fd);
158
159         return buf;
160 }
161
162 u64 read_file_u64(int dirfd, const char *path)
163 {
164         char *buf = read_file_str(dirfd, path);
165         u64 ret = strtoll(buf, NULL, 10);
166
167         free(buf);
168         return ret;
169 }
170
171 /* String list options: */
172
173 ssize_t read_string_list(const char *buf, const char * const list[])
174 {
175         size_t i;
176         char *s, *d = strdup(buf);
177         if (!d)
178                 return -ENOMEM;
179
180         s = strim(d);
181
182         for (i = 0; list[i]; i++)
183                 if (!strcmp(list[i], s))
184                         break;
185
186         free(d);
187
188         if (!list[i])
189                 return -EINVAL;
190
191         return i;
192 }
193
194 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
195                                 const char *msg)
196 {
197         ssize_t v = read_string_list(opt, list);
198         if (v < 0)
199                 die("Bad %s %s", msg, opt);
200
201         return v;
202 }
203
204 void print_string_list(const char * const list[], size_t selected)
205 {
206         size_t i;
207
208         for (i = 0; list[i]; i++) {
209                 if (i)
210                         putchar(' ');
211                 printf(i == selected ? "[%s] ": "%s", list[i]);
212         }
213 }
214
215 /* Returns size of file or block device, in units of 512 byte sectors: */
216 u64 get_size(const char *path, int fd)
217 {
218         struct stat statbuf;
219         if (fstat(fd, &statbuf))
220                 die("Error statting %s: %s", path, strerror(errno));
221
222         if (!S_ISBLK(statbuf.st_mode))
223                 return statbuf.st_size >> 9;
224
225         u64 ret;
226         if (ioctl(fd, BLKGETSIZE64, &ret))
227                 die("Error getting block device size on %s: %s\n",
228                     path, strerror(errno));
229
230         return ret >> 9;
231 }
232
233 /* Returns blocksize in units of 512 byte sectors: */
234 unsigned get_blocksize(const char *path, int fd)
235 {
236         struct stat statbuf;
237         if (fstat(fd, &statbuf))
238                 die("Error statting %s: %s", path, strerror(errno));
239
240         if (!S_ISBLK(statbuf.st_mode))
241                 return statbuf.st_blksize >> 9;
242
243         unsigned ret;
244         if (ioctl(fd, BLKPBSZGET, &ret))
245                 die("Error getting blocksize on %s: %s\n",
246                     path, strerror(errno));
247
248         return ret >> 9;
249 }
250
251 /* Open a block device, do magic blkid stuff: */
252 int dev_open(const char *dev)
253 {
254         blkid_probe pr;
255         int fd;
256
257         if ((fd = open(dev, O_RDWR|O_EXCL)) == -1)
258                 die("Can't open dev %s: %s\n", dev, strerror(errno));
259
260         if (!(pr = blkid_new_probe()))
261                 die("Failed to create a new probe");
262         if (blkid_probe_set_device(pr, fd, 0, 0))
263                 die("failed to set probe to device");
264
265         /* enable ptable probing; superblock probing is enabled by default */
266         if (blkid_probe_enable_partitions(pr, true))
267                 die("Failed to enable partitions on probe");
268
269         if (!blkid_do_probe(pr))
270                 /* XXX wipefs doesn't know how to remove partition tables */
271                 die("Device %s already has a non-bcache superblock, "
272                     "remove it using wipefs and wipefs -a\n", dev);
273
274         return fd;
275 }
276
277 /* Checksums: */
278
279 /*
280  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any
281  * use permitted, subject to terms of PostgreSQL license; see.)
282
283  * If we have a 64-bit integer type, then a 64-bit CRC looks just like the
284  * usual sort of implementation. (See Ross Williams' excellent introduction
285  * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from
286  * ftp://ftp.rocksoft.com/papers/crc_v3.txt or several other net sites.)
287  * If we have no working 64-bit type, then fake it with two 32-bit registers.
288  *
289  * The present implementation is a normal (not "reflected", in Williams'
290  * terms) 64-bit CRC, using initial all-ones register contents and a final
291  * bit inversion. The chosen polynomial is borrowed from the DLT1 spec
292  * (ECMA-182, available from http://www.ecma.ch/ecma1/STAND/ECMA-182.HTM):
293  *
294  * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 +
295  * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 +
296  * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 +
297  * x^7 + x^4 + x + 1
298 */
299
300 static const u64 crc_table[256] = {
301         0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
302         0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
303         0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
304         0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
305         0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
306         0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
307         0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
308         0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
309         0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
310         0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
311         0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
312         0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
313         0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
314         0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
315         0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
316         0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
317         0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
318         0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
319         0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
320         0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
321         0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
322         0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
323         0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
324         0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
325         0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
326         0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
327         0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
328         0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
329         0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
330         0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
331         0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
332         0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
333         0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
334         0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
335         0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
336         0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
337         0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
338         0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
339         0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
340         0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
341         0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
342         0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
343         0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
344         0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
345         0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
346         0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
347         0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
348         0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
349         0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
350         0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
351         0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
352         0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
353         0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
354         0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
355         0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
356         0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
357         0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
358         0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
359         0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
360         0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
361         0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
362         0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
363         0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
364         0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
365         0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
366         0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
367         0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
368         0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
369         0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
370         0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
371         0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
372         0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
373         0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
374         0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
375         0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
376         0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
377         0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
378         0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
379         0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
380         0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
381         0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
382         0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
383         0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
384         0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
385         0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL,
386         0x9AFCE626CE85B507ULL
387 };
388
389 static u64 bch_crc64_update(u64 crc, const void *_data, size_t len)
390 {
391         const unsigned char *data = _data;
392
393         while (len--) {
394                 int i = ((int) (crc >> 56) ^ *data++) & 0xFF;
395                 crc = crc_table[i] ^ (crc << 8);
396         }
397
398         return crc;
399 }
400
401 static u64 bch_checksum_update(unsigned type, u64 crc, const void *data, size_t len)
402 {
403         switch (type) {
404         case BCH_CSUM_NONE:
405                 return 0;
406         case BCH_CSUM_CRC32C:
407                 return crc32c(crc, data, len);
408         case BCH_CSUM_CRC64:
409                 return bch_crc64_update(crc, data, len);
410         default:
411                 die("Unknown checksum type %u", type);
412         }
413 }
414
415 u64 bch_checksum(unsigned type, const void *data, size_t len)
416 {
417         u64 crc = 0xffffffffffffffffULL;
418
419         crc = bch_checksum_update(type, crc, data, len);
420
421         return crc ^ 0xffffffffffffffffULL;
422 }
423
424 /* Global control device: */
425 int bcachectl_open(void)
426 {
427         int fd = open("/dev/bcache-ctl", O_RDWR);
428         if (fd < 0)
429                 die("Can't open bcache device: %s", strerror(errno));
430
431         return fd;
432 }
433
434 /* Filesystem handles (ioctl, sysfs dir): */
435
436 #define SYSFS_BASE "/sys/fs/bcache/"
437
438 struct bcache_handle bcache_fs_open(const char *path)
439 {
440         struct bcache_handle ret;
441         uuid_t tmp;
442
443         if (!uuid_parse(path, tmp)) {
444                 /* It's a UUID, look it up in sysfs: */
445
446                 char *sysfs = alloca(strlen(SYSFS_BASE) + strlen(path) + 1);
447                 sprintf(sysfs, "%s%s", SYSFS_BASE, path);
448
449                 ret.sysfs = opendir(sysfs);
450                 if (!ret.sysfs)
451                         die("Unable to open %s\n", path);
452
453                 char *minor = read_file_str(dirfd(ret.sysfs), "minor");
454                 char *ctl = alloca(20 + strlen(minor));
455
456                 sprintf(ctl, "/dev/bcache%s-ctl", minor);
457                 free(minor);
458
459                 ret.fd = open(ctl, O_RDWR);
460                 if (ret.fd < 0)
461                         die("Error opening control device: %s\n",
462                             strerror(errno));
463         } else {
464                 /* It's a path: */
465
466                 ret.fd = open(path, O_RDONLY);
467                 if (ret.fd < 0)
468                         die("Error opening %s: %s\n",
469                             path, strerror(errno));
470
471                 struct bch_ioctl_query_uuid uuid;
472                 if (ioctl(ret.fd, BCH_IOCTL_QUERY_UUID, &uuid))
473                         die("ioctl error (not a bcache fs?): %s\n",
474                             strerror(errno));
475
476                 char uuid_str[40];
477                 uuid_unparse(uuid.uuid.b, uuid_str);
478
479                 char *sysfs = alloca(strlen(SYSFS_BASE) + strlen(uuid_str) + 1);
480                 sprintf(sysfs, "%s%s", SYSFS_BASE, uuid_str);
481
482                 ret.sysfs = opendir(sysfs);
483                 if (!ret.sysfs)
484                         die("Unable to open sysfs dir %s: %s\n",
485                             sysfs, strerror(errno));
486         }
487
488         return ret;
489 }