]> git.sesse.net Git - bcachefs-tools-debian/blob - bcacheadm.c
bcacheadm: fix --cache_replacement_policy flag
[bcachefs-tools-debian] / bcacheadm.c
1 /*
2  * Authors: Kent Overstreet <kmo@daterainc.com>
3  *          Gabriel de Perthuis <g2p.code@gmail.com>
4  *          Jacob Malevich <jam@datera.io>
5  *
6  * GPLv2
7  */
8
9 #include <nih/option.h>
10 #include <nih/command.h>
11 #include <nih/main.h>
12 #include <nih/logging.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <blkid.h>
24 #include <string.h>
25 #include <linux/fs.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <uuid/uuid.h>
30 #include <dirent.h>
31 #include <bcache.h> //libbcache
32
33 #define PACKAGE_NAME "bcacheadm"
34 #define PACKAGE_VERSION "1.0"
35 #define PACKAGE_BUGREPORT "bugreport"
36
37
38
39 /* make-bcache globals */
40 int bdev = -1;
41 int devs = 0;
42 char *cache_devices[MAX_DEVS];
43 int tier_mapping[MAX_DEVS];
44 unsigned replacement_policy_mapping[MAX_DEVS];
45 char *backing_devices[MAX_DEVS];
46 char *backing_dev_labels[MAX_DEVS];
47 size_t i, nr_backing_devices = 0, nr_cache_devices = 0;
48 unsigned block_size = 0;
49 unsigned bucket_sizes[MAX_DEVS];
50 int num_bucket_sizes = 0;
51 int writeback = 0, discard = 0, wipe_bcache = 0;
52 unsigned replication_set = 0;
53 char *replacement_policy = 0;
54 uint64_t data_offset = BDEV_DATA_START_DEFAULT;
55 char *label = NULL;
56 struct cache_sb *cache_set_sb = NULL;
57 const char *cache_set_uuid = 0;
58 const char *csum_type = 0;
59 char *metadata_replicas = 0;
60 char *data_replicas = 0;
61 char *tier = 0;
62
63 /* rm-dev globals */
64 bool force_remove = false;
65
66 /* Modify globals */
67 bool modify_list_attrs = false;
68 static const char *modify_set_uuid = NULL;
69 static const char *modify_dev_uuid = NULL;
70
71 /* query-dev globals */
72 bool force_csum = false;
73 bool uuid_only = false;
74 bool query_brief = false;
75
76 /* probe globals */
77 bool udev = false;
78
79 /* list globals */
80 char *cset_dir = "/sys/fs/bcache";
81 bool list_devs = false;
82
83 /* status globals */
84 bool status_all = false;
85
86 /* capacity globals */
87 static const char *capacity_uuid = NULL;
88 bool capacity_devs = false;
89
90 /* stats globals */
91 bool stats_all = false;
92 bool stats_list = false;
93 static const char *stats_uuid = NULL;
94 static const char *stats_dev_uuid = NULL;
95 static const char *stats_cache_num = NULL;
96 bool stats_five_min = false;
97 bool stats_hour = false;
98 bool stats_day = false;
99 bool stats_total = false;
100
101 /* set_failed globals */
102 static const char *dev_failed_uuid = NULL;
103
104 /* make-bcache option setters */
105 static int set_block_size(NihOption *option, const char *arg)
106 {
107         block_size = hatoi_validate(arg, "block size");
108         return 0;
109 }
110
111 static int set_cache(NihOption *option, const char *arg)
112 {
113         bdev = 0;
114         cache_devices[nr_cache_devices] = strdup(arg);
115         if(!tier)
116                 tier_mapping[nr_cache_devices] = 0;
117         else {
118                 int ntier = atoi(tier);
119                 if(ntier == 0 || ntier == 1)
120                         tier_mapping[nr_cache_devices] = ntier;
121                 else
122                         printf("Invalid tier %s\n", tier);
123         }
124
125         if (!replacement_policy)
126                 replacement_policy_mapping[nr_cache_devices] = 0;
127         else {
128                 int i = 0;
129
130                 while (replacement_policies[i] != NULL) {
131                         if (!strcmp(replacement_policy,
132                                     replacement_policies[i])) {
133                                 replacement_policy_mapping[nr_cache_devices] = i;
134                                 break;
135                         }
136                         i++;
137                 }
138
139                 if (replacement_policies[i] == NULL)
140                         printf("Invalid replacement policy: %s\n",
141                                replacement_policy);
142         }
143
144         devs++;
145         nr_cache_devices++;
146
147         return 0;
148 }
149
150 static int set_bdev(NihOption *option, const char *arg)
151 {
152         bdev = 1;
153
154         if(label)
155                 backing_dev_labels[nr_backing_devices] = strdup(label);
156
157         backing_devices[nr_backing_devices] = strdup(arg);
158
159         nr_backing_devices++;
160         devs++;
161
162         return 0;
163 }
164
165 static int set_bucket_sizes(NihOption *option, const char *arg)
166 {
167         bucket_sizes[num_bucket_sizes]=hatoi_validate(arg, "bucket size");
168         num_bucket_sizes++;
169         return 0;
170 }
171
172 /* probe setters */
173 static int set_udev(NihOption *option, const char *arg)
174 {
175         if (strcmp("udev", arg)) {
176                 printf("Invalid output format %s\n", arg);
177                 exit(EXIT_FAILURE);
178         }
179         udev = true;
180         return 0;
181 }
182
183
184 /* options */
185 static NihOption make_bcache_options[] = {
186 //      {int shortoption, char* longoption, char* help, NihOptionGroup, char* argname, void *value, NihOptionSetter}
187         {'C', "cache",  N_("Format a cache device"), NULL, "dev", NULL, set_cache},
188         {'B', "bdev",   N_("Format a backing device"), NULL, "dev", NULL, set_bdev},
189         {'l', "label",  N_("label"), NULL, "label", &label, NULL},
190         //Only one bucket_size supported until a list of bucket sizes is parsed correctly
191         {'b', "bucket", N_("bucket size"), NULL, "size", NULL, set_bucket_sizes},
192         //Does the default setter automatically convert strings to an int?
193         {'w', "block",  N_("block size (hard sector size of SSD, often 2k"), NULL,"size", NULL, set_block_size},
194         {'t', "tier",   N_("tier of subsequent devices"), NULL,"#", &tier, NULL},
195         {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,"policy", &replacement_policy, NULL},
196         {'o', "data_offset", N_("data offset in sectors"), NULL,"offset", &data_offset, NULL},
197
198         {0, "cset-uuid",        N_("UUID for the cache set"),           NULL,   "uuid", &cache_set_uuid, NULL},
199         {0, "csum-type",        N_("One of (none|crc32c|crc64)"),               NULL,   "type", &csum_type, NULL },
200         {0, "replication-set",N_("replication set of subsequent devices"),      NULL,   NULL, &replication_set, NULL },
201         {0, "meta-replicas",N_("number of metadata replicas"),          NULL,   "#", &metadata_replicas, NULL},
202         {0, "data-replicas",N_("number of data replicas"),              NULL,   "#", &data_replicas, NULL },
203
204         {0, "wipe-bcache",      N_("destroy existing bcache data if present"),          NULL, NULL, &wipe_bcache, NULL},
205         {0, "discard",          N_("enable discards"),          NULL, NULL, &discard,           NULL},
206         {0, "writeback",        N_("enable writeback"),         NULL, NULL, &writeback,         NULL},
207
208         NIH_OPTION_LAST
209 };
210
211 static NihOption probe_bcache_options[] = {
212         {'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev},
213         NIH_OPTION_LAST
214 };
215
216 static NihOption bcache_register_options[] = {
217         NIH_OPTION_LAST
218 };
219
220 static NihOption bcache_unregister_options[] = {
221         NIH_OPTION_LAST
222 };
223
224 static NihOption bcache_add_device_options[] = {
225         NIH_OPTION_LAST
226 };
227
228 static NihOption bcache_rm_device_options[] = {
229         {'f', "force", N_("force cache removal"), NULL, NULL, &force_remove, NULL},
230         NIH_OPTION_LAST
231 };
232
233 static NihOption bcache_modify_options[] = {
234         {'l', "list", N_("list attributes"), NULL, NULL, &modify_list_attrs, NULL},
235         {'u', "set", N_("cacheset uuid"), NULL, "UUID", &modify_set_uuid, NULL},
236         {'d', "dev", N_("device uuid"), NULL, "UUID", &modify_dev_uuid, NULL},
237         NIH_OPTION_LAST
238 };
239
240 static NihOption query_devs_options[] = {
241         {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
242         {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
243         {'b', "brief", N_("only print out the cluster,server,and disk uuids"), NULL, NULL, &query_brief, NULL},
244         NIH_OPTION_LAST
245 };
246
247 static NihOption list_cachesets_options[] = {
248         {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
249         {0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
250         NIH_OPTION_LAST
251 };
252
253 static NihOption status_options[] = {
254         {'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
255         NIH_OPTION_LAST
256 };
257
258 static NihOption capacity_options[] = {
259         {'u', "set", N_("cache_set UUID"), NULL, "UUID", &capacity_uuid, NULL},
260         {'d', "devs", N_("dev UUID"), NULL, NULL, &capacity_devs, NULL},
261         NIH_OPTION_LAST
262 };
263
264 static NihOption stats_options[] = {
265         {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL},
266         {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL},
267         {'u', "set", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL},
268         {'d', "dev", N_("dev UUID"), NULL, "UUID", &stats_dev_uuid, NULL},
269         {'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL},
270         {0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL},
271         {0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL},
272         {0, "day-stats", N_("stats accumulated in last day"), NULL, NULL, &stats_day, NULL},
273         {0, "total-stats", N_("stats accumulated in total"), NULL, NULL, &stats_total, NULL},
274         NIH_OPTION_LAST
275 };
276
277 static NihOption set_failed_options[] = {
278         {'d', "dev", N_("dev UUID"), NULL, "UUID", &dev_failed_uuid, NULL},
279         NIH_OPTION_LAST
280 };
281
282 static NihOption options[] = {
283         NIH_OPTION_LAST
284 };
285
286
287 /* commands */
288 int make_bcache(NihCommand *command, char *const *args)
289 {
290         int cache_dev_fd[devs];
291
292         int backing_dev_fd[devs];
293
294         cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
295                                      sizeof(struct cache_member) * devs);
296
297         if (cache_set_uuid) {
298                 if(uuid_parse(cache_set_uuid, cache_set_sb->set_uuid.b)) {
299                         fprintf(stderr, "Bad uuid\n");
300                         return -1;
301                 }
302         } else {
303                 uuid_generate(cache_set_sb->set_uuid.b);
304         }
305
306         if (label) 
307                 memcpy(cache_set_sb->label, label, sizeof(cache_set_sb->label));
308
309         if (csum_type) {
310                 SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb,
311                                 read_string_list_or_die(csum_type, csum_types,
312                                         "csum type"));
313         } else {
314                 SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C);
315         }
316
317         if (metadata_replicas) {
318                 SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
319                                 strtoul_or_die(metadata_replicas,
320                                         CACHE_SET_META_REPLICAS_WANT_MAX,
321                                         "meta replicas"));
322         } else {
323                 SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1);
324         }
325
326         if (data_replicas) {
327                 SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
328                         strtoul_or_die(data_replicas,
329                                 CACHE_SET_DATA_REPLICAS_WANT_MAX,
330                                 "data replicas"));
331         } else {
332                 SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1);
333         }
334
335         if (bdev == -1) {
336                 fprintf(stderr, "Please specify -C or -B\n");
337                 exit(EXIT_FAILURE);
338         }
339
340         if(!bucket_sizes[0]) bucket_sizes[0] = 1024;
341
342         for(i = 0; i < nr_cache_devices; i++)
343                 next_cache_device(cache_set_sb,
344                                   replication_set,
345                                   tier_mapping[i],
346                                   replacement_policy_mapping[i],
347                                   discard);
348
349         if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
350                 fprintf(stderr, "Please supply a device\n");
351                 exit(EXIT_FAILURE);
352         }
353
354         i = 0;
355         do {
356                 if (bucket_sizes[i] < block_size) {
357                         fprintf(stderr,
358                         "Bucket size cannot be smaller than block size\n");
359                         exit(EXIT_FAILURE);
360                 }
361                 i++;
362         } while (i < num_bucket_sizes);
363
364         if (!block_size) {
365                 for (i = 0; i < cache_set_sb->nr_in_set; i++)
366                         block_size = max(block_size,
367                                          get_blocksize(cache_devices[i]));
368
369                 for (i = 0; i < nr_backing_devices; i++)
370                         block_size = max(block_size,
371                                          get_blocksize(backing_devices[i]));
372         }
373
374         for (i = 0; i < cache_set_sb->nr_in_set; i++)
375                 cache_dev_fd[i] = dev_open(cache_devices[i], wipe_bcache);
376
377         for (i = 0; i < nr_backing_devices; i++)
378                 backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache);
379
380         write_cache_sbs(cache_dev_fd, cache_set_sb, block_size,
381                                         bucket_sizes, num_bucket_sizes);
382
383         for (i = 0; i < nr_backing_devices; i++)
384                 write_backingdev_sb(backing_dev_fd[i],
385                                     block_size, bucket_sizes,
386                                     writeback, data_offset,
387                                     backing_dev_labels[i],
388                                     cache_set_sb->set_uuid);
389
390
391         return 0;
392 }
393
394 int probe_bcache(NihCommand *command, char *const *args)
395 {
396         int i;
397         char *err = NULL;
398
399         for (i = 0; args[i] != NULL; i++) {
400                 err = probe(args[i], udev);
401                 if(err) {
402                         printf("probe_bcache error: %s\n", err);
403                         return -1;
404                 }
405         }
406
407         return 0;
408 }
409
410 int bcache_register(NihCommand *command, char *const *args)
411 {
412         char *err = NULL;
413
414         err = register_bcache(args);
415         if (err) {
416                 printf("bcache_register error: %s\n", err);
417                 return -1;
418         }
419
420         return 0;
421 }
422
423 int bcache_unregister(NihCommand *command, char *const *args)
424 {
425         char *err = NULL;
426
427         err = unregister_bcache(args);
428         if (err) {
429                 printf("bcache_unregister error: %s\n", err);
430                 return -1;
431         }
432
433         return 0;
434 }
435
436 int bcache_add_devices(NihCommand *command, char *const *args)
437 {
438         char *err;
439
440         err = add_devices(args);
441         if (err) {
442                 printf("bcache_add_devices error: %s\n", err);
443                 return -1;
444         }
445
446         return 0;
447 }
448
449 int bcache_rm_device(NihCommand *command, char *const *args)
450 {
451         char *err;
452
453         err = remove_device(args[0], force_remove);
454         if (err) {
455                 printf("bcache_rm_devices error: %s\n", err);
456                 return -1;
457         }
458
459         return 0;
460 }
461
462 int bcache_modify(NihCommand *command, char *const *args)
463 {
464         char *err;
465         char path[MAX_PATH];
466         DIR *path_dir;
467         struct stat cache_stat;
468         char *attr = args[0];
469         char *val = NULL;
470         int fd = -1;
471
472         if (modify_list_attrs) {
473                 sysfs_attr_list();
474                 return 0;
475         }
476
477         if (!modify_set_uuid) {
478                 printf("Must provide a cacheset uuid\n");
479                 return -1;
480         }
481
482         snprintf(path, MAX_PATH, "%s/%s", cset_dir, modify_set_uuid);
483
484         if(!attr) {
485                 printf("Must provide the name of an attribute to modify\n");
486                 goto err;
487         }
488
489         enum sysfs_attr type = sysfs_attr_type(attr);
490
491         if (type == -1)
492                 goto err;
493         else if(type == INTERNAL_ATTR)
494                 strcat(path, "/internal");
495         else if(type == CACHE_ATTR) {
496                 if(modify_dev_uuid) {
497                         /* searches all cache# for a matching uuid,
498                          * path gets modified to the correct cache path */
499                         char subdir[10] = "/cache";
500                         err = find_matching_uuid(path, subdir,
501                                         modify_dev_uuid);
502                         if (err) {
503                                 printf("Failed to find "
504                                         "matching dev %s\n", err);
505                                 goto err;
506                         } else {
507                                 strcat(path, subdir);
508                         }
509                 } else {
510                         printf("Must provide a device uuid\n");
511                 }
512         }
513         /* SET_ATTRs are just in the current dir */
514
515         strcat(path, "/");
516         strcat(path, attr);
517
518         val = args[1];
519         if (!val) {
520                 printf("Must provide a value to change the attribute to\n");
521                 goto err;
522         }
523
524         fd = open(path, O_WRONLY);
525         if (fd < 0) {
526                 printf("Unable to open modify attr with path %s\n", path);
527                 goto err;
528         }
529
530         write(fd, val, strlen(val));
531
532 err:
533         if(fd)
534                 close(fd);
535         return 0;
536 }
537
538 int bcache_list_cachesets(NihCommand *command, char *const *args)
539 {
540         char *err = NULL;
541         err = list_cachesets(cset_dir, list_devs);
542         if (err) {
543                 printf("bcache_list_cachesets error :%s\n", err);
544                 return -1;
545         }
546
547         return 0;
548 }
549
550 int bcache_query_devs(NihCommand *command, char *const *args)
551 {
552         int i;
553
554         if (query_brief)
555                 printf("%-10s%-40s%-40s%-40s\n", "dev name", "disk uuid",
556                                 "server uuid", "cluster uuid");
557
558         for (i = 0; args[i] != NULL; i++) {
559                 char dev_uuid[40];
560                 struct cache_sb *sb = query_dev(args[i], force_csum,
561                                 !query_brief, uuid_only, dev_uuid);
562
563                 if (!sb) {
564                         printf("error opening the superblock for %s\n",
565                                         args[i]);
566                         return -1;
567                 }
568
569                 if (uuid_only) {
570                         printf("%s\n", dev_uuid);
571                 } else if (query_brief) {
572                         char set_uuid_str[40], dev_uuid_str[40];
573                         char *clus_uuid = (char *)sb->label;
574
575                         uuid_unparse(sb->set_uuid.b, set_uuid_str);
576                         uuid_unparse(sb->uuid.b, dev_uuid_str);
577                         if (!strcmp(clus_uuid, ""))
578                                 clus_uuid = "None";
579
580                         printf("%-10s%-40s%-40s%-40s\n", args[i],
581                                         dev_uuid_str,
582                                         set_uuid_str,
583                                         clus_uuid);
584                 }
585                 free(sb);
586         }
587
588         return 0;
589 }
590
591 int bcache_status(NihCommand *command, char *const *args)
592 {
593         int i, dev_count = 0, seq, nr_in_set = 0;
594         struct cache_sb *seq_sb = NULL;
595         char cache_path[MAX_PATH];
596         char *dev_names[MAX_DEVS];
597         char *dev_uuids[MAX_DEVS];
598         char intbuf[4];
599         char set_uuid[40];
600
601         for (i = 0; args[i] != NULL; i++) {
602                 struct cache_sb *sb = query_dev(args[i], false, false,
603                                 false, NULL);
604
605                 if (!sb) {
606                         printf("Unable to open superblock, bad path\n");
607                         return -1;
608                 }
609
610                 if (!seq_sb || sb->seq > seq) {
611                         seq = sb->seq;
612                         seq_sb = sb;
613                         nr_in_set = sb->nr_in_set;
614                 } else
615                         free(sb);
616         }
617
618         if (!seq_sb) {
619                 printf("Unable to find a superblock\n");
620                 return -1;
621         } else {
622                 uuid_unparse(seq_sb->set_uuid.b, set_uuid);
623                 printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
624         }
625
626         snprintf(intbuf, 4, "%d", i);
627         snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
628                         "cache0");
629
630         /*
631          * Get a list of all the devices from sysfs first, then
632          * compare it to the list we get back from the most up
633          * to date superblock. If there are any devices in the superblock
634          * that are not in sysfs, print out 'NOT PRESENT'
635          */
636         while (true) {
637                 char buf[MAX_PATH];
638                 int len;
639                 DIR *cache_dir;
640
641                 if(((cache_dir = opendir(cache_path)) == NULL) &&
642                     dev_count < MAX_DEVS)
643                         break;
644
645                 if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
646                         struct cache_sb *sb;
647                         char dev_uuid[40];
648                         char dev_path[32];
649
650                         buf[len] = '\0';
651                         dev_names[dev_count] = dev_name(buf);
652                         snprintf(dev_path, MAX_PATH, "%s/%s", "/dev",
653                                         dev_names[dev_count]);
654                         sb = query_dev(dev_path, false, false,
655                                         true, dev_uuid);
656                         if (!sb) {
657                                 printf("error reading %s\n", dev_path);
658                                 return -1;
659                         } else
660                                 free(sb);
661
662                         dev_uuids[dev_count] = strdup(dev_uuid);
663                 } else {
664                         dev_uuids[dev_count] = strdup("Nothing");
665                         dev_names[dev_count] = strdup("Nothing");
666                 }
667
668                 cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
669                 dev_count++;
670
671                 snprintf(intbuf, 4, "%d", dev_count);
672                 strcat(cache_path, intbuf);
673         }
674
675         for (i = 0; i < seq_sb->nr_in_set; i++) {
676                 char uuid_str[40];
677                 struct cache_member *m = ((struct cache_member *) seq_sb->d) + i;
678                 char dev_state[32];
679                 int j;
680
681                 uuid_unparse(m->uuid.b, uuid_str);
682
683                 for (j = 0; j < dev_count; j++) {
684                         if (!strcmp(uuid_str, dev_uuids[j])) {
685                                 snprintf(dev_state, MAX_PATH, "%s",
686                                                 cache_state[CACHE_STATE(m)]);
687                                 break;
688                         } else if (j == dev_count - 1) {
689                                 if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
690                                         snprintf(dev_state, MAX_PATH, "%s", "missing");
691                                 else
692                                         snprintf(dev_state, MAX_PATH, "%s",
693                                                         cache_state[CACHE_STATE(m)]);
694                                 break;
695                         }
696                 }
697
698                 printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
699                                 CACHE_TIER(m));
700         }
701
702         if (seq_sb)
703                 free(seq_sb);
704         for (i = 0; i < dev_count; i++) {
705                 free(dev_names[i]);
706                 free(dev_uuids[i]);
707         }
708
709         return 0;
710 }
711
712 int bcache_capacity(NihCommand *command, char *const *args)
713 {
714         char *err = "Must provide a cacheset uuid";
715         if(!capacity_uuid)
716                 goto err;
717
718         err = bcache_get_capacity(cset_dir, capacity_uuid, capacity_devs);
719         if (err)
720                 goto err;
721
722         return 0;
723
724 err:
725         printf("bcache_capacity failed with error: %s\n", err);
726         return -1;
727
728 }
729
730 static char *stats_subdir(char* stats_dir)
731 {
732         char tmp[50] = "/";
733         char *err = NULL;
734         if(stats_dev_uuid) {
735                 strcat(tmp, "cache");
736                 err = find_matching_uuid(stats_dir, tmp, stats_dev_uuid);
737                 if(err)
738                         goto err;
739         } else if(stats_cache_num) {
740                 strcat(tmp, "cache");
741                 strcat(tmp, stats_cache_num);
742         } else if (stats_five_min)
743                 strcat(tmp, "stats_five_minute");
744         else if (stats_hour)
745                 strcat(tmp, "stats_hour");
746         else if (stats_day)
747                 strcat(tmp, "stats_day");
748         else if (stats_total)
749                 strcat(tmp, "stats_total");
750         else
751                 return err;
752
753         strcat(stats_dir, tmp);
754
755 err:
756         return err;
757 }
758
759 int bcache_stats(NihCommand *command, char *const *args)
760 {
761         int i;
762         char stats_dir[MAX_PATH];
763         DIR *dir = NULL;
764         struct dirent *ent = NULL;
765         char *err = NULL;
766         char buf[MAX_PATH];
767
768         if (stats_uuid) {
769                 snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid);
770                 err = stats_subdir(stats_dir);
771                 if(err)
772                         goto err;
773
774                 dir = opendir(stats_dir);
775                 if (!dir) {
776                         err = "Failed to open dir";
777                         goto err;
778                 }
779         } else {
780                 err = "Must provide a cacheset uuid";
781                 goto err;
782         }
783
784         if(stats_list || stats_all) {
785                 while ((ent = readdir(dir)) != NULL) {
786                         err = read_stat_dir(dir, stats_dir, ent->d_name, buf);
787                         if (err)
788                                 goto err;
789                         if(stats_list)
790                                 printf("%s\n", ent->d_name);
791                         if(stats_all)
792                                 printf("\t%s\n", buf);
793                 }
794         }
795
796         for (i = 0; args[i] != NULL; i++) {
797                 err = read_stat_dir(dir, stats_dir, args[i], buf);
798                 if (err)
799                         goto err;
800                 printf("%s\n", buf);
801         }
802
803         closedir(dir);
804         return 0;
805
806 err:
807         closedir(dir);
808         printf("bcache_stats error: %s\n", err);
809         return -1;
810 }
811
812 int bcache_set_failed(NihCommand *command, char *const *args)
813 {
814         int i;
815         char *err = NULL;
816
817         if (!dev_failed_uuid) {
818                 printf("Pass in a dev uuid\n");
819                 return -1;
820         }
821
822         err = device_set_failed(dev_failed_uuid);
823         if (err) {
824                 printf("bcache_set_failed_ioctl error: %s\n", err);
825                 return -1;
826         }
827
828         return 0;
829 }
830
831 static NihCommand commands[] = {
832         {"format", N_("format <list of drives>"),
833                   "Format one or a list of devices with bcache datastructures."
834                   " You need to do this before you create a volume",
835                   N_("format drive[s] with bcache"),
836                   NULL, make_bcache_options, make_bcache},
837         {"probe", N_("probe <list of devices>"),
838                   "Does a blkid_probe on a device",
839                   N_("Does a blkid_probe on a device"),
840                   NULL, probe_bcache_options, probe_bcache},
841         {"register", N_("register <list of devices>"),
842                      "Registers a list of devices",
843                      N_("Registers a list of devices"),
844                      NULL, bcache_register_options, bcache_register},
845         {"unregister", N_("unregister <list of devices>"),
846                      "Unregisters a list of devices",
847                      N_("Unregisters a list of devices"),
848                      NULL, bcache_unregister_options, bcache_unregister},
849         {"add-devs", N_("add-devs --tier=# <list of devices>"),
850                 "Adds a list of devices to a cacheset",
851                 N_("Adds a list of devices to a cacheset"),
852                 NULL, bcache_add_device_options, bcache_add_devices},
853         {"rm-dev", N_("rm-dev <dev>"),
854                 "Removes a device from its cacheset",
855                 N_("Removes a device from its cacheset"),
856                 NULL, bcache_rm_device_options, bcache_rm_device},
857         {"modify", N_("modify --set=UUID (dev=UUID) name value"),
858                 "Modifies attributes related to the cacheset",
859                 N_("Modifies attributes related to the cacheset"),
860                 NULL, bcache_modify_options, bcache_modify},
861         {"list-cachesets", N_("list-cachesets"),
862                            "Lists cachesets in /sys/fs/bcache",
863                            N_("Lists cachesets in /sys/fs/bcache"),
864                            NULL, list_cachesets_options, bcache_list_cachesets},
865         {"query-devs", N_("query <list of devices>"),
866                        "Gives info about the superblock of a list of devices",
867                        N_("show superblock on each of the listed drive"),
868                        NULL, query_devs_options, bcache_query_devs},
869         {"status", N_("status <list of devices>"),
870                    "Finds the status of the most up to date superblock",
871                    N_("Finds the status of the most up to date superblock"),
872                    NULL, status_options, bcache_status},
873         {"capacity", N_("capacity --set=UUID"),
874                 "Shows the capacity of the cacheset",
875                 N_("Shows the capacity of the cacheset"),
876                 NULL, capacity_options, bcache_capacity},
877         {"stats", N_("stats <list of devices>"),
878                   "List various bcache statistics",
879                   N_("List various bcache statistics"),
880                   NULL, stats_options, bcache_stats},
881         {"set-failed", N_("set-failed --dev=UUID"),
882                 "Sets a device to the FAILED state",
883                 N_("Sets a device to the FAILED state"),
884                 NULL, set_failed_options, bcache_set_failed},
885         NIH_COMMAND_LAST
886 };
887
888
889 int main(int argc, char *argv[])
890 {
891         int ret = 0;
892         nih_main_init (argv[0]);
893
894         nih_option_set_synopsis (_("Manage bcache devices"));
895         nih_option_set_help (
896                         _("Helps you manage bcache devices"));
897
898         ret = nih_command_parser (NULL, argc, argv, options, commands);
899         if (ret < 0)
900                 exit (1);
901
902         nih_signal_reset();
903
904         return 0;
905 }