2 * Authors: Kent Overstreet <kmo@daterainc.com>
3 * Gabriel de Perthuis <g2p.code@gmail.com>
4 * Jacob Malevich <jam@datera.io>
9 #include <nih/option.h>
10 #include <nih/command.h>
12 #include <nih/logging.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
28 #include <uuid/uuid.h>
32 #include "bcacheadm.h"
34 #define PACKAGE_NAME "bcacheadm"
35 #define PACKAGE_VERSION "1.0"
36 #define PACKAGE_BUGREPORT "bugreport"
39 bool force_remove = false;
42 bool modify_list_attrs = false;
43 static const char *modify_set_uuid = NULL;
44 static const char *modify_dev_uuid = NULL;
46 /* query-dev globals */
47 bool force_csum = false;
48 bool uuid_only = false;
49 bool query_brief = false;
55 char *cset_dir = "/sys/fs/bcache";
56 bool list_devs = false;
57 static const char *internal_uuid = NULL;
60 bool status_all = false;
62 /* capacity globals */
63 static const char *capacity_uuid = NULL;
64 bool capacity_devs = false;
67 bool stats_all = false;
68 bool stats_list = false;
69 static const char *stats_uuid = NULL;
70 static const char *stats_dev_uuid = NULL;
71 static const char *stats_cache_num = NULL;
72 bool stats_five_min = false;
73 bool stats_hour = false;
74 bool stats_day = false;
75 bool stats_total = false;
77 /* set_failed globals */
78 static const char *dev_failed_uuid = NULL;
81 static int set_udev(NihOption *option, const char *arg)
83 if (strcmp("udev", arg)) {
84 printf("Invalid output format %s\n", arg);
92 static NihOption probe_bcache_options[] = {
93 {'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev},
97 static NihOption bcache_register_options[] = {
101 static NihOption bcache_unregister_options[] = {
105 static NihOption bcache_add_device_options[] = {
109 static NihOption bcache_rm_device_options[] = {
110 {'f', "force", N_("force cache removal"), NULL, NULL, &force_remove, NULL},
114 static NihOption bcache_modify_options[] = {
115 {'l', "list", N_("list attributes"), NULL, NULL, &modify_list_attrs, NULL},
116 {'u', "set", N_("cacheset uuid"), NULL, "UUID", &modify_set_uuid, NULL},
117 {'d', "dev", N_("device uuid"), NULL, "UUID", &modify_dev_uuid, NULL},
121 static NihOption query_devs_options[] = {
122 {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
123 {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
124 {'b', "brief", N_("only print out the cluster,server,and disk uuids"), NULL, NULL, &query_brief, NULL},
128 static NihOption list_cachesets_options[] = {
129 {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
130 {0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
131 {0, "internal_uuid", N_("Show the internal UUID for the given cacheset UUID"), NULL, "UUID", &internal_uuid, NULL},
135 static NihOption status_options[] = {
136 {'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
140 static NihOption capacity_options[] = {
141 {'u', "set", N_("cache_set UUID"), NULL, "UUID", &capacity_uuid, NULL},
142 {'d', "devs", N_("Individual device capacities"), NULL, NULL, &capacity_devs, NULL},
146 static NihOption stats_options[] = {
147 {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL},
148 {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL},
149 {'u', "set", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL},
150 {'d', "dev", N_("dev UUID"), NULL, "UUID", &stats_dev_uuid, NULL},
151 {'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL},
152 {0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL},
153 {0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL},
154 {0, "day-stats", N_("stats accumulated in last day"), NULL, NULL, &stats_day, NULL},
155 {0, "total-stats", N_("stats accumulated in total"), NULL, NULL, &stats_total, NULL},
159 static NihOption set_failed_options[] = {
160 {'d', "dev", N_("dev UUID"), NULL, "UUID", &dev_failed_uuid, NULL},
164 static NihOption options[] = {
169 int probe_bcache(NihCommand *command, char *const *args)
174 for (i = 0; args[i] != NULL; i++) {
175 err = probe(args[i], udev);
177 printf("probe_bcache error: %s\n", err);
185 int bcache_register(NihCommand *command, char *const *args)
189 err = register_bcache(args);
191 printf("bcache_register error: %s\n", err);
198 int bcache_unregister(NihCommand *command, char *const *args)
202 err = unregister_bcache(args);
204 printf("bcache_unregister error: %s\n", err);
211 int bcache_add_devices(NihCommand *command, char *const *args)
215 err = add_devices(args);
217 printf("bcache_add_devices error: %s\n", err);
224 int bcache_rm_device(NihCommand *command, char *const *args)
229 printf("Must provide a device name\n");
233 err = remove_device(args[0], force_remove);
235 printf("bcache_rm_devices error: %s\n", err);
242 int bcache_modify(NihCommand *command, char *const *args)
246 char *attr = args[0];
250 if (modify_list_attrs) {
255 if (!modify_set_uuid) {
256 printf("Must provide a cacheset uuid\n");
260 snprintf(path, MAX_PATH, "%s/%s", cset_dir, modify_set_uuid);
263 printf("Must provide the name of an attribute to modify\n");
267 enum sysfs_attr type = sysfs_attr_type(attr);
271 else if(type == INTERNAL_ATTR)
272 strcat(path, "/internal");
273 else if(type == CACHE_ATTR) {
274 if(modify_dev_uuid) {
275 /* searches all cache# for a matching uuid,
276 * path gets modified to the correct cache path */
277 char subdir[10] = "/cache";
278 err = find_matching_uuid(path, subdir,
281 printf("Failed to find "
282 "matching dev %s\n", err);
285 strcat(path, subdir);
288 printf("Must provide a device uuid\n");
291 /* SET_ATTRs are just in the current dir */
298 printf("Must provide a value to change the attribute to\n");
302 fd = open(path, O_WRONLY);
304 printf("Unable to open modify attr with path %s\n", path);
308 write(fd, val, strlen(val));
316 int bcache_list_cachesets(NihCommand *command, char *const *args)
321 char uuid_path[MAX_PATH];
325 snprintf(uuid_path, MAX_PATH, "%s/%s", cset_dir, internal_uuid);
327 err = "uuid does not exist";
328 if((uuid_dir = opendir(uuid_path)) == NULL)
331 err = read_stat_dir(uuid_dir, uuid_path, "/internal/internal_uuid", buf);
338 err = list_cachesets(cset_dir, list_devs);
345 printf("bcache_list_cachesets error :%s\n", err);
349 int bcache_query_devs(NihCommand *command, char *const *args)
354 printf("%-10s%-40s%-40s%-40s\n", "dev name", "disk uuid",
355 "server uuid", "cluster uuid");
357 for (i = 0; args[i] != NULL; i++) {
359 struct cache_sb *sb = query_dev(args[i], force_csum,
360 !query_brief, uuid_only, dev_uuid);
363 printf("error opening the superblock for %s\n",
369 printf("%s\n", dev_uuid);
370 } else if (query_brief) {
371 char set_uuid_str[40], dev_uuid_str[40];
372 char *clus_uuid = (char *)sb->label;
374 uuid_unparse(sb->user_uuid.b, set_uuid_str);
375 uuid_unparse(sb->disk_uuid.b, dev_uuid_str);
376 if (!strcmp(clus_uuid, ""))
379 printf("%-10s%-40s%-40s%-40s\n", args[i],
390 int bcache_status(NihCommand *command, char *const *args)
392 int i, dev_count = 0, seq, cache_count = 0;
393 struct cache_sb *seq_sb = NULL;
394 char cache_path[MAX_PATH];
395 char *dev_names[MAX_DEVS];
396 char *dev_uuids[MAX_DEVS];
400 for (i = 0; args[i] != NULL; i++) {
401 struct cache_sb *sb = query_dev(args[i], false, false,
405 printf("Unable to open superblock, bad path\n");
409 if (!seq_sb || sb->seq > seq) {
417 printf("Unable to find a superblock\n");
420 uuid_unparse(seq_sb->user_uuid.b, set_uuid);
421 printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
424 snprintf(intbuf, 4, "%d", i);
425 snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
429 * Get a list of all the devices from sysfs first, then
430 * compare it to the list we get back from the most up
431 * to date superblock. If there are any devices in the superblock
432 * that are not in sysfs, print out 'missing'
439 if(((cache_dir = opendir(cache_path)) == NULL) &&
440 cache_count > MAX_DEVS)
446 if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
452 dev_names[dev_count] = dev_name(buf);
453 snprintf(dev_path, MAX_PATH, "%s/%s", "/dev",
454 dev_names[dev_count]);
455 sb = query_dev(dev_path, false, false,
458 printf("error reading %s\n", dev_path);
463 dev_uuids[dev_count] = strdup(dev_uuid);
467 cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
470 snprintf(intbuf, 4, "%d", cache_count);
471 strcat(cache_path, intbuf);
474 for (i = 0; i < seq_sb->nr_in_set; i++) {
476 struct cache_member *m = seq_sb->members + i;
480 uuid_unparse(m->uuid.b, uuid_str);
481 snprintf(dev_state, MAX_PATH, "%s",
482 cache_state[CACHE_STATE(m)]);
484 for (j = 0; j < dev_count; j++) {
485 if (!strcmp(uuid_str, dev_uuids[j])) {
487 } else if (j == dev_count - 1) {
488 if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
489 snprintf(dev_state, MAX_PATH, "%s", "missing");
494 printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
500 for (i = 0; i < dev_count; i++) {
508 int bcache_capacity(NihCommand *command, char *const *args)
510 char *err = "Must provide a cacheset uuid";
514 err = bcache_get_capacity(cset_dir, capacity_uuid, capacity_devs);
521 printf("bcache_capacity failed with error: %s\n", err);
526 static char *stats_subdir(char* stats_dir)
531 strcat(tmp, "cache");
532 err = find_matching_uuid(stats_dir, tmp, stats_dev_uuid);
535 } else if(stats_cache_num) {
536 strcat(tmp, "cache");
537 strcat(tmp, stats_cache_num);
538 } else if (stats_five_min)
539 strcat(tmp, "stats_five_minute");
541 strcat(tmp, "stats_hour");
543 strcat(tmp, "stats_day");
544 else if (stats_total)
545 strcat(tmp, "stats_total");
549 strcat(stats_dir, tmp);
555 int bcache_stats(NihCommand *command, char *const *args)
558 char stats_dir[MAX_PATH];
560 struct dirent *ent = NULL;
565 snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid);
566 err = stats_subdir(stats_dir);
570 dir = opendir(stats_dir);
572 err = "Failed to open dir";
576 err = "Must provide a cacheset uuid";
580 if(stats_list || stats_all) {
581 while ((ent = readdir(dir)) != NULL) {
582 err = read_stat_dir(dir, stats_dir, ent->d_name, buf);
586 printf("%s\n", ent->d_name);
588 printf("\t%s\n", buf);
592 for (i = 0; args[i] != NULL; i++) {
593 err = read_stat_dir(dir, stats_dir, args[i], buf);
604 printf("bcache_stats error: %s\n", err);
608 int bcache_set_failed(NihCommand *command, char *const *args)
612 if (!dev_failed_uuid) {
613 printf("Pass in a dev uuid\n");
617 err = device_set_failed(dev_failed_uuid);
619 printf("bcache_set_failed_ioctl error: %s\n", err);
626 static NihCommand commands[] = {
627 {"format", N_("format <list of drives>"),
628 "Format one or a list of devices with bcache datastructures."
629 " You need to do this before you create a volume",
630 N_("format drive[s] with bcache"),
631 NULL, bcacheadm_format_options, bcacheadm_format},
632 {"probe", N_("probe <list of devices>"),
633 "Does a blkid_probe on a device",
634 N_("Does a blkid_probe on a device"),
635 NULL, probe_bcache_options, probe_bcache},
636 {"register", N_("register <list of devices>"),
637 "Registers a list of devices",
638 N_("Registers a list of devices"),
639 NULL, bcache_register_options, bcache_register},
640 {"unregister", N_("unregister <list of devices>"),
641 "Unregisters a list of devices",
642 N_("Unregisters a list of devices"),
643 NULL, bcache_unregister_options, bcache_unregister},
644 {"add-devs", N_("add-devs --tier=# <list of devices>"),
645 "Adds a list of devices to a cacheset",
646 N_("Adds a list of devices to a cacheset"),
647 NULL, bcache_add_device_options, bcache_add_devices},
648 {"rm-dev", N_("rm-dev <dev>"),
649 "Removes a device from its cacheset",
650 N_("Removes a device from its cacheset"),
651 NULL, bcache_rm_device_options, bcache_rm_device},
652 {"modify", N_("modify --set=UUID (dev=UUID) name value"),
653 "Modifies attributes related to the cacheset",
654 N_("Modifies attributes related to the cacheset"),
655 NULL, bcache_modify_options, bcache_modify},
656 {"list-cachesets", N_("list-cachesets"),
657 "Lists cachesets in /sys/fs/bcache",
658 N_("Lists cachesets in /sys/fs/bcache"),
659 NULL, list_cachesets_options, bcache_list_cachesets},
660 {"query-devs", N_("query <list of devices>"),
661 "Gives info about the superblock of a list of devices",
662 N_("show superblock on each of the listed drive"),
663 NULL, query_devs_options, bcache_query_devs},
664 {"status", N_("status <list of devices>"),
665 "Finds the status of the most up to date superblock",
666 N_("Finds the status of the most up to date superblock"),
667 NULL, status_options, bcache_status},
668 {"capacity", N_("capacity --set=UUID"),
669 "Shows the capacity of the cacheset",
670 N_("Shows the capacity of the cacheset"),
671 NULL, capacity_options, bcache_capacity},
672 {"stats", N_("stats <list of devices>"),
673 "List various bcache statistics",
674 N_("List various bcache statistics"),
675 NULL, stats_options, bcache_stats},
676 {"set-failed", N_("set-failed --dev=UUID"),
677 "Sets a device to the FAILED state",
678 N_("Sets a device to the FAILED state"),
679 NULL, set_failed_options, bcache_set_failed},
683 int main(int argc, char *argv[])
686 nih_main_init (argv[0]);
688 nih_option_set_synopsis (_("Manage bcache devices"));
689 nih_option_set_help (
690 _("Helps you manage bcache devices"));
692 ret = nih_command_parser (NULL, argc, argv, options, commands);