12 #include <sys/ioctl.h>
14 #include <sys/types.h>
17 #include <uuid/uuid.h>
19 #include "ccan/crc/crc.h"
21 #include "tools-util.h"
25 struct units_buf pr_units(u64 v, enum units units)
31 snprintf(ret.b, sizeof(ret.b), "%llu", v << 9);
34 snprintf(ret.b, sizeof(ret.b), "%llu", v);
40 int exp = log(v) / log(1024);
41 snprintf(ret.b, sizeof(ret.b), "%.1f%c",
45 snprintf(ret.b, sizeof(ret.b), "%llu", v);
54 /* Argument parsing stuff: */
56 long strtoul_or_die(const char *p, size_t max, const char *msg)
59 long v = strtol(p, NULL, 10);
60 if (errno || v < 0 || v >= max)
61 die("Invalid %s %zi", msg, v);
66 u64 hatoi(const char *s)
69 long long i = strtoll(s, &e, 10);
87 unsigned hatoi_validate(const char *s, const char *msg)
92 die("%s must be a power of two", msg);
97 die("%s too large\n", msg);
100 die("%s too small\n", msg);
105 unsigned nr_args(char * const *args)
109 for (i = 0; args[i]; i++)
115 /* File parsing (i.e. sysfs) */
117 char *read_file_str(int dirfd, const char *path)
119 int fd = openat(dirfd, path, O_RDONLY);
122 die("Unable to open %s\n", path);
125 if (fstat(fd, &statbuf) < 0)
126 die("fstat error\n");
128 char *buf = malloc(statbuf.st_size + 1);
130 int len = read(fd, buf, statbuf.st_size);
132 die("read error while reading from file %s\n", path);
135 if (len && buf[len - 1] == '\n')
143 u64 read_file_u64(int dirfd, const char *path)
145 char *buf = read_file_str(dirfd, path);
146 u64 ret = strtoll(buf, NULL, 10);
152 /* String list options: */
154 ssize_t read_string_list(const char *buf, const char * const list[])
157 char *s, *d = strdup(buf);
163 for (i = 0; list[i]; i++)
164 if (!strcmp(list[i], s))
175 ssize_t read_string_list_or_die(const char *opt, const char * const list[],
178 ssize_t v = read_string_list(opt, list);
180 die("Bad %s %s", msg, opt);
185 void print_string_list(const char * const list[], size_t selected)
189 for (i = 0; list[i]; i++) {
192 printf(i == selected ? "[%s] ": "%s", list[i]);
196 /* Returns size of file or block device, in units of 512 byte sectors: */
197 u64 get_size(const char *path, int fd)
200 if (fstat(fd, &statbuf))
201 die("Error statting %s: %s", path, strerror(errno));
203 if (!S_ISBLK(statbuf.st_mode))
204 return statbuf.st_size >> 9;
207 if (ioctl(fd, BLKGETSIZE64, &ret))
208 die("Error getting block device size on %s: %s\n",
209 path, strerror(errno));
214 /* Returns blocksize in units of 512 byte sectors: */
215 unsigned get_blocksize(const char *path, int fd)
218 if (fstat(fd, &statbuf))
219 die("Error statting %s: %s", path, strerror(errno));
221 if (!S_ISBLK(statbuf.st_mode))
222 return statbuf.st_blksize >> 9;
225 if (ioctl(fd, BLKPBSZGET, &ret))
226 die("Error getting blocksize on %s: %s\n",
227 path, strerror(errno));
232 /* Global control device: */
233 int bcachectl_open(void)
235 int fd = open("/dev/bcache-ctl", O_RDWR);
237 die("Can't open bcache device: %s", strerror(errno));
242 /* Filesystem handles (ioctl, sysfs dir): */
244 #define SYSFS_BASE "/sys/fs/bcache/"
246 struct bcache_handle bcache_fs_open(const char *path)
248 struct bcache_handle ret;
251 if (!uuid_parse(path, tmp)) {
252 /* It's a UUID, look it up in sysfs: */
254 char *sysfs = alloca(strlen(SYSFS_BASE) + strlen(path) + 1);
255 sprintf(sysfs, "%s%s", SYSFS_BASE, path);
257 ret.sysfs_fd = open(sysfs, O_RDONLY);
259 die("Unable to open %s\n", path);
261 char *minor = read_file_str(ret.sysfs_fd, "minor");
262 char *ctl = alloca(20 + strlen(minor));
264 sprintf(ctl, "/dev/bcache%s-ctl", minor);
267 ret.ioctl_fd = open(ctl, O_RDWR);
268 if (ret.ioctl_fd < 0)
269 die("Error opening control device: %s\n",
274 ret.ioctl_fd = open(path, O_RDONLY);
275 if (ret.ioctl_fd < 0)
276 die("Error opening %s: %s\n",
277 path, strerror(errno));
279 struct bch_ioctl_query_uuid uuid;
280 if (ioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid))
281 die("ioctl error (not a bcache fs?): %s\n",
285 uuid_unparse(uuid.uuid.b, uuid_str);
287 char *sysfs = alloca(strlen(SYSFS_BASE) + strlen(uuid_str) + 1);
288 sprintf(sysfs, "%s%s", SYSFS_BASE, uuid_str);
290 ret.sysfs_fd = open(sysfs, O_RDONLY);
291 if (ret.sysfs_fd < 0)
292 die("Unable to open sysfs dir %s: %s\n",
293 sysfs, strerror(errno));
299 bool ask_proceed(void)
301 const char *short_yes = "yY";
306 fputs("Proceed anyway? (y,n) ", stdout);
308 if (getline(&buf, &buflen, stdin) < 0)
309 die("error reading from standard input");
311 ret = strchr(short_yes, buf[0]);