13 #include <nih/command.h>
14 #include <nih/option.h>
16 #include <uuid/uuid.h>
19 #include "bcacheadm-query.h"
21 static char *cset_dir = "/sys/fs/bcache";
22 static bool list_devs = false;
23 static const char *internal_uuid = NULL;
25 NihOption opts_list[] = {
26 {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL},
27 {0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL},
28 {0, "internal_uuid", N_("Show the internal UUID for the given cacheset UUID"), NULL, "UUID", &internal_uuid, NULL},
32 static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name)
35 struct stat cache_stat;
38 snprintf(entry, MAX_PATH, "%s/%s", cset_dir, cset_name);
40 if((dir = opendir(entry)) != NULL) {
41 while((ent = readdir(dir)) != NULL) {
47 * We are looking for all cache# directories
48 * do a strlen < 9 to skip over other entries
49 * that also start with "cache"
51 if(strncmp(ent->d_name, "cache", 5) ||
52 !(strlen(ent->d_name) < 9))
55 snprintf(entry, MAX_PATH, "%s/%s/%s",
60 if((cachedir = opendir(entry)) == NULL)
63 if(stat(entry, &cache_stat))
66 if((len = readlink(entry, buf, sizeof(buf) - 1)) !=
71 printf("/dev%s\n", tmp);
74 printf("\t%s\n", buf);
81 static char *list_cachesets(char *cset_dir, bool list_devs)
87 dir = opendir(cset_dir);
89 err = "Failed to open cacheset dir";
93 while ((ent = readdir(dir)) != NULL) {
97 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
100 snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name);
101 if(stat(entry, &statbuf) == -1) {
102 err = "Failed to stat cacheset subdir";
106 if (S_ISDIR(statbuf.st_mode)) {
107 printf("%s\n", ent->d_name);
110 list_cacheset_devs(cset_dir, ent->d_name, true);
120 static char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, char *ret)
123 char entry[MAX_PATH];
126 snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name);
127 if(stat(entry, &statbuf) == -1) {
129 snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry);
134 if (S_ISREG(statbuf.st_mode)) {
137 fp = fopen(entry, "r");
139 /* If we can't open the file, this is probably because
140 * of permissions, just move to the next file */
144 while(fgets(ret, MAX_PATH, fp));
151 int cmd_list(NihCommand *command, char *const *args)
156 char uuid_path[MAX_PATH];
160 snprintf(uuid_path, MAX_PATH, "%s/%s", cset_dir, internal_uuid);
162 err = "uuid does not exist";
163 if((uuid_dir = opendir(uuid_path)) == NULL)
166 err = read_stat_dir(uuid_dir, uuid_path, "/internal/internal_uuid", buf);
173 err = list_cachesets(cset_dir, list_devs);
180 printf("bcache_list_cachesets error :%s\n", err);
184 static bool force_csum = false;
185 static bool uuid_only = false;
186 static bool query_brief = false;
188 NihOption opts_query[] = {
189 {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL},
190 {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL},
191 {'b', "brief", N_("only print out the cluster,server,and disk uuids"), NULL, NULL, &query_brief, NULL},
195 int cmd_query(NihCommand *command, char *const *args)
200 printf("%-10s%-40s%-40s%-40s\n", "dev name", "disk uuid",
201 "server uuid", "cluster uuid");
203 for (i = 0; args[i] != NULL; i++) {
205 struct cache_sb *sb = query_dev(args[i], force_csum,
206 !query_brief, uuid_only, dev_uuid);
209 printf("error opening the superblock for %s\n",
215 printf("%s\n", dev_uuid);
216 } else if (query_brief) {
217 char set_uuid_str[40], dev_uuid_str[40];
218 char *clus_uuid = (char *)sb->label;
220 uuid_unparse(sb->user_uuid.b, set_uuid_str);
221 uuid_unparse(sb->disk_uuid.b, dev_uuid_str);
222 if (!strcmp(clus_uuid, ""))
225 printf("%-10s%-40s%-40s%-40s\n", args[i],
236 static bool status_all = false;
238 NihOption opts_status[] = {
239 {'a', "all", N_("all"), NULL, NULL, &status_all, NULL},
243 int cmd_status(NihCommand *command, char *const *args)
245 int i, dev_count = 0, seq, cache_count = 0;
246 struct cache_sb *seq_sb = NULL;
247 char cache_path[MAX_PATH];
248 char *dev_names[MAX_DEVS];
249 char *dev_uuids[MAX_DEVS];
253 for (i = 0; args[i] != NULL; i++) {
254 struct cache_sb *sb = query_dev(args[i], false, false,
258 printf("Unable to open superblock, bad path\n");
262 if (!seq_sb || sb->seq > seq) {
270 printf("Unable to find a superblock\n");
273 uuid_unparse(seq_sb->user_uuid.b, set_uuid);
274 printf("%-50s%-15s%-4s\n", "uuid", "state", "tier");
277 snprintf(intbuf, 4, "%d", i);
278 snprintf(cache_path, MAX_PATH, "%s/%s/%s", cset_dir, set_uuid,
282 * Get a list of all the devices from sysfs first, then
283 * compare it to the list we get back from the most up
284 * to date superblock. If there are any devices in the superblock
285 * that are not in sysfs, print out 'missing'
292 if(((cache_dir = opendir(cache_path)) == NULL) &&
293 cache_count > MAX_DEVS)
299 if((len = readlink(cache_path, buf, sizeof(buf) - 1)) != -1) {
305 dev_names[dev_count] = dev_name(buf);
306 snprintf(dev_path, sizeof(dev_path), "%s/%s", "/dev",
307 dev_names[dev_count]);
308 sb = query_dev(dev_path, false, false,
311 printf("error reading %s\n", dev_path);
316 dev_uuids[dev_count] = strdup(dev_uuid);
320 cache_path[strlen(cache_path) - strlen(intbuf)] = 0;
323 snprintf(intbuf, 4, "%d", cache_count);
324 strcat(cache_path, intbuf);
327 for (i = 0; i < seq_sb->nr_in_set; i++) {
329 struct cache_member *m = seq_sb->members + i;
333 uuid_unparse(m->uuid.b, uuid_str);
334 snprintf(dev_state, sizeof(dev_state), "%s",
335 cache_state[CACHE_STATE(m)]);
337 for (j = 0; j < dev_count; j++) {
338 if (!strcmp(uuid_str, dev_uuids[j])) {
340 } else if (j == dev_count - 1) {
341 if (!strcmp(cache_state[CACHE_STATE(m)], "active"))
342 snprintf(dev_state, sizeof(dev_state), "%s", "missing");
347 printf("%-50s%-15s%-4llu\n", uuid_str, dev_state,
353 for (i = 0; i < dev_count; i++) {