2 * Copyright (c) 2005 Christophe Varoqui
6 #include <libdevmapper.h>
13 #include "structs_vec.h"
17 #include "configure.h"
18 #include "pgpolicies.h"
22 #define MAX(x,y) (x > y) ? x : y
23 #define TAIL (line + len - 1 - c)
25 #define PAD(x) while ((int)(c - s) < (x) && (c < (line + len - 1))) \
27 #define PRINT(var, size, format, args...) \
28 fwd = snprintf(var, size, format, ##args); \
29 c += (fwd >= size) ? size : fwd;
32 * information printing helpers
35 snprint_str (char * buff, size_t len, char * str)
37 return snprintf(buff, len, "%s", str);
41 snprint_int (char * buff, size_t len, int val)
43 return snprintf(buff, len, "%i", val);
47 snprint_uint (char * buff, size_t len, unsigned int val)
49 return snprintf(buff, len, "%u", val);
53 snprint_size (char * buff, size_t len, unsigned long long size)
56 return snprintf(buff, len, "%llu kB", size >> 1);
57 else if (size < (1 << 21))
58 return snprintf(buff, len, "%llu MB", size >> 11);
59 else if (size < (1 << 31))
60 return snprintf(buff, len, "%llu GB", size >> 21);
62 return snprintf(buff, len, "%llu TB", size >> 31);
66 snprint_name (char * buff, size_t len, struct multipath * mpp)
69 return snprintf(buff, len, "%s", mpp->alias);
71 return snprintf(buff, len, "%s", mpp->wwid);
75 snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
78 return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
84 snprint_progress (char * buff, size_t len, int cur, int total)
86 int i = PROGRESS_LEN * cur / total;
87 int j = PROGRESS_LEN - i;
89 char * end = buff + len;
92 c += snprintf(c, len, "X");
93 if ((len = (end - c)) <= 1) goto out;
97 c += snprintf(c, len, ".");
98 if ((len = (end - c)) <= 1) goto out;
101 c += snprintf(c, len, " %i/%i", cur, total);
104 buff[c - buff + 1] = '\0';
105 return (c - buff + 1);
109 snprint_failback (char * buff, size_t len, struct multipath * mpp)
111 if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
112 return snprintf(buff, len, "immediate");
114 if (!mpp->failback_tick)
115 return snprintf(buff, len, "-");
117 return snprint_progress(buff, len, mpp->failback_tick,
122 snprint_queueing (char * buff, size_t len, struct multipath * mpp)
124 if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
125 return snprintf(buff, len, "off");
126 else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
127 return snprintf(buff, len, "on");
128 else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
129 return snprintf(buff, len, "-");
130 else if (mpp->no_path_retry > 0) {
132 return snprintf(buff, len, "%i sec",
135 return snprintf(buff, len, "%i chk",
142 snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
144 return snprint_int(buff, len, mpp->nr_active);
148 snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
150 if (mpp->dmi && mpp->dmi->suspended)
151 return snprintf(buff, len, "suspend");
153 return snprintf(buff, len, "active");
157 snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
159 return snprint_size(buff, len, mpp->size);
163 snprint_features (char * buff, size_t len, struct multipath * mpp)
165 return snprint_str(buff, len, mpp->features);
169 snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
171 return snprint_str(buff, len, mpp->hwhandler);
175 snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
177 return snprint_uint(buff, len, mpp->stat_path_failures);
181 snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
183 return snprint_uint(buff, len, mpp->stat_switchgroup);
187 snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
189 return snprint_uint(buff, len, mpp->stat_map_loads);
193 snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
195 return snprint_uint(buff, len, mpp->stat_total_queueing_time);
199 snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
201 return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
205 snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
207 return snprint_str(buff, len, mpp->wwid);
211 snprint_action (char * buff, size_t len, struct multipath * mpp)
213 switch (mpp->action) {
215 return snprint_str(buff, len, ACT_RELOAD_STR);
217 return snprint_str(buff, len, ACT_CREATE_STR);
219 return snprint_str(buff, len, ACT_SWITCHPG_STR);
226 snprint_path_uuid (char * buff, size_t len, struct path * pp)
228 return snprint_str(buff, len, pp->wwid);
232 snprint_hcil (char * buff, size_t len, struct path * pp)
234 if (pp->sg_id.host_no < 0)
235 return snprintf(buff, len, "#:#:#:#");
237 return snprintf(buff, len, "%i:%i:%i:%i",
245 snprint_dev (char * buff, size_t len, struct path * pp)
247 if (!strlen(pp->dev))
248 return snprintf(buff, len, "-");
250 return snprint_str(buff, len, pp->dev);
254 snprint_dev_t (char * buff, size_t len, struct path * pp)
256 if (!strlen(pp->dev))
257 return snprintf(buff, len, "#:#");
259 return snprint_str(buff, len, pp->dev_t);
263 snprint_chk_state (char * buff, size_t len, struct path * pp)
267 return snprintf(buff, len, "[ready]");
269 return snprintf(buff, len, "[faulty]");
271 return snprintf(buff, len, "[shaky]");
273 return snprintf(buff, len, "[ghost]");
275 return snprintf(buff, len, "[undef]");
280 snprint_dm_path_state (char * buff, size_t len, struct path * pp)
282 switch (pp->dmstate) {
284 return snprintf(buff, len, "[active]");
286 return snprintf(buff, len, "[failed]");
288 return snprintf(buff, len, "[undef]");
293 snprint_vpr (char * buff, size_t len, struct path * pp)
295 return snprintf(buff, len, "%s/%s/%s",
296 pp->vendor_id, pp->product_id, pp->rev);
300 snprint_next_check (char * buff, size_t len, struct path * pp)
303 return snprintf(buff, len, "[orphan]");
305 return snprint_progress(buff, len, pp->tick, pp->checkint);
309 snprint_pri (char * buff, size_t len, struct path * pp)
311 return snprint_int(buff, len, pp->priority);
315 snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
317 return snprint_str(buff, len, pgp->selector);
321 snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
323 return snprint_int(buff, len, pgp->priority);
327 snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
329 switch (pgp->status) {
330 case PGSTATE_ENABLED:
331 return snprintf(buff, len, "[enabled]");
332 case PGSTATE_DISABLED:
333 return snprintf(buff, len, "[disabled]");
335 return snprintf(buff, len, "[active]");
337 return snprintf(buff, len, "[undef]");
342 snprint_path_size (char * buff, size_t len, struct path * pp)
344 return snprint_size(buff, len, pp->size);
347 struct multipath_data mpd[] = {
348 {'n', "name", 0, snprint_name},
349 {'w', "uuid", 0, snprint_multipath_uuid},
350 {'d', "sysfs", 0, snprint_sysfs},
351 {'F', "failback", 0, snprint_failback},
352 {'Q', "queueing", 0, snprint_queueing},
353 {'N', "paths", 0, snprint_nb_paths},
354 {'t', "dm-st", 0, snprint_dm_map_state},
355 {'S', "size", 0, snprint_multipath_size},
356 {'f', "features", 0, snprint_features},
357 {'h', "hwhandler", 0, snprint_hwhandler},
358 {'A', "action", 0, snprint_action},
359 {'0', "path_faults", 0, snprint_path_faults},
360 {'1', "switch_grp", 0, snprint_switch_grp},
361 {'2', "map_loads", 0, snprint_map_loads},
362 {'3', "total_q_time", 0, snprint_total_q_time},
363 {'4', "q_timeouts", 0, snprint_q_timeouts},
367 struct path_data pd[] = {
368 {'w', "uuid", 0, snprint_path_uuid},
369 {'i', "hcil", 0, snprint_hcil},
370 {'d', "dev", 0, snprint_dev},
371 {'D', "dev_t", 0, snprint_dev_t},
372 {'t', "dm_st", 0, snprint_dm_path_state},
373 {'T', "chk_st", 0, snprint_chk_state},
374 {'s', "vend/prod/rev", 0, snprint_vpr},
375 {'C', "next_check", 0, snprint_next_check},
376 {'p', "pri", 0, snprint_pri},
377 {'S', "size", 0, snprint_path_size},
381 struct pathgroup_data pgd[] = {
382 {'s', "selector", 0, snprint_pg_selector},
383 {'p', "pri", 0, snprint_pg_pri},
384 {'t', "dm_st", 0, snprint_pg_state},
388 get_path_layout (vector pathvec)
391 char buff[MAX_FIELD_LEN];
394 for (j = 0; pd[j].header; j++) {
395 pd[j].width = strlen(pd[j].header);
397 vector_foreach_slot (pathvec, pp, i) {
398 pd[j].snprint(buff, MAX_FIELD_LEN, pp);
399 pd[j].width = MAX(pd[j].width, strlen(buff));
405 get_multipath_layout (vector mpvec)
408 char buff[MAX_FIELD_LEN];
409 struct multipath * mpp;
411 for (j = 0; mpd[j].header; j++) {
412 mpd[j].width = strlen(mpd[j].header);
414 vector_foreach_slot (mpvec, mpp, i) {
415 mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
416 mpd[j].width = MAX(mpd[j].width, strlen(buff));
421 static struct multipath_data *
422 mpd_lookup(char wildcard)
426 for (i = 0; mpd[i].header; i++)
427 if (mpd[i].wildcard == wildcard)
433 static struct path_data *
434 pd_lookup(char wildcard)
438 for (i = 0; pd[i].header; i++)
439 if (pd[i].wildcard == wildcard)
445 static struct pathgroup_data *
446 pgd_lookup(char wildcard)
450 for (i = 0; pgd[i].header; i++)
451 if (pgd[i].wildcard == wildcard)
458 snprint_multipath_header (char * line, int len, char * format)
460 char * c = line; /* line cursor */
461 char * s = line; /* for padding */
462 char * f = format; /* format string cursor */
464 struct multipath_data * data;
477 if (!(data = mpd_lookup(*f)))
478 break; /* unknown wildcard */
480 PRINT(c, TAIL, data->header);
484 line[c - line - 1] = '\n';
485 line[c - line] = '\0';
491 snprint_multipath (char * line, int len, char * format,
492 struct multipath * mpp)
494 char * c = line; /* line cursor */
495 char * s = line; /* for padding */
496 char * f = format; /* format string cursor */
498 struct multipath_data * data;
499 char buff[MAX_FIELD_LEN];
512 if (!(data = mpd_lookup(*f)))
515 data->snprint(buff, MAX_FIELD_LEN, mpp);
516 PRINT(c, TAIL, buff);
520 line[c - line - 1] = '\n';
521 line[c - line] = '\0';
527 snprint_path_header (char * line, int len, char * format)
529 char * c = line; /* line cursor */
530 char * s = line; /* for padding */
531 char * f = format; /* format string cursor */
533 struct path_data * data;
546 if (!(data = pd_lookup(*f)))
547 break; /* unknown wildcard */
549 PRINT(c, TAIL, data->header);
553 line[c - line - 1] = '\n';
554 line[c - line] = '\0';
560 snprint_path (char * line, int len, char * format,
563 char * c = line; /* line cursor */
564 char * s = line; /* for padding */
565 char * f = format; /* format string cursor */
567 struct path_data * data;
568 char buff[MAX_FIELD_LEN];
581 if (!(data = pd_lookup(*f)))
584 data->snprint(buff, MAX_FIELD_LEN, pp);
585 PRINT(c, TAIL, buff);
589 line[c - line - 1] = '\n';
590 line[c - line] = '\0';
596 snprint_pathgroup (char * line, int len, char * format,
597 struct pathgroup * pgp)
599 char * c = line; /* line cursor */
600 char * s = line; /* for padding */
601 char * f = format; /* format string cursor */
603 struct pathgroup_data * data;
604 char buff[MAX_FIELD_LEN];
617 if (!(data = pgd_lookup(*f)))
620 data->snprint(buff, MAX_FIELD_LEN, pgp);
621 PRINT(c, TAIL, buff);
625 line[c - line - 1] = '\n';
626 line[c - line] = '\0';
632 print_multipath_topology (struct multipath * mpp, int verbosity)
634 char buff[MAX_LINE_LEN * MAX_LINES];
636 snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
642 snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
646 struct path * pp = NULL;
647 struct pathgroup * pgp = NULL;
655 return snprint_multipath(buff, len, "%n", mpp);
658 mpp->action != ACT_NOTHING &&
659 mpp->action != ACT_UNDEF)
660 c += sprintf(c, "%%A: ");
662 c += sprintf(c, "%%n");
664 if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
665 c += sprintf(c, " (%%w)");
667 fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
670 fwd += snprint_multipath(buff + fwd, len - fwd,
671 "[size=%S][features=%f][hwhandler=%h]", mpp);
678 vector_foreach_slot (mpp->pg, pgp, j) {
679 pgp->selector = mpp->selector; /* hack */
680 fwd += snprint_pathgroup(buff + fwd, len - fwd,
681 PRINT_PG_INDENT, pgp);
685 vector_foreach_slot (pgp->paths, pp, i) {
686 fwd += snprint_path(buff + fwd, len - fwd,
687 PRINT_PATH_INDENT, pp);
696 snprint_hwentry (char * buff, int len, struct hwentry * hwe)
701 struct keyword * rootkw;
703 rootkw = find_keyword(NULL, "devices");
705 if (!rootkw || !rootkw->sub)
708 rootkw = find_keyword(rootkw->sub, "device");
713 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
716 iterate_sub_keywords(rootkw, kw, i) {
717 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
722 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
729 snprint_hwtable (char * buff, int len, vector hwtable)
733 struct hwentry * hwe;
734 struct keyword * rootkw;
736 rootkw = find_keyword(NULL, "devices");
740 fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
743 vector_foreach_slot (hwtable, hwe, i) {
744 fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
748 fwd += snprintf(buff + fwd, len - fwd, "}\n");
755 snprint_mpentry (char * buff, int len, struct mpentry * mpe)
760 struct keyword * rootkw;
762 rootkw = find_keyword(NULL, "multipath");
766 fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
769 iterate_sub_keywords(rootkw, kw, i) {
770 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
775 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
782 snprint_mptable (char * buff, int len, vector mptable)
786 struct mpentry * mpe;
787 struct keyword * rootkw;
789 rootkw = find_keyword(NULL, "multipaths");
793 fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
796 vector_foreach_slot (mptable, mpe, i) {
797 fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
801 fwd += snprintf(buff + fwd, len - fwd, "}\n");
808 snprint_defaults (char * buff, int len)
812 struct keyword *rootkw;
815 rootkw = find_keyword(NULL, "defaults");
819 fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
823 iterate_sub_keywords(rootkw, kw, i) {
824 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
829 fwd += snprintf(buff + fwd, len - fwd, "}\n");
837 snprint_blacklist (char * buff, int len)
840 struct blentry * ble;
841 struct blentry_device * bled;
843 struct keyword *rootkw;
846 rootkw = find_keyword(NULL, "blacklist");
850 fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
854 vector_foreach_slot (conf->blist_devnode, ble, i) {
855 kw = find_keyword(rootkw->sub, "devnode");
858 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
863 vector_foreach_slot (conf->blist_wwid, ble, i) {
864 kw = find_keyword(rootkw->sub, "wwid");
867 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
872 rootkw = find_keyword(rootkw->sub, "device");
876 vector_foreach_slot (conf->blist_device, bled, i) {
877 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
880 kw = find_keyword(rootkw->sub, "vendor");
883 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
887 kw = find_keyword(rootkw->sub, "product");
890 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
894 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
899 fwd += snprintf(buff + fwd, len - fwd, "}\n");
907 snprint_config (char * buff, int len)
913 * stdout printing helpers
916 print_path (struct path * pp, char * style)
918 char line[MAX_LINE_LEN];
920 snprint_path(&line[0], MAX_LINE_LEN, style, pp);
925 print_multipath (struct multipath * mpp, char * style)
927 char line[MAX_LINE_LEN];
929 snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
934 print_pathgroup (struct pathgroup * pgp, char * style)
936 char line[MAX_LINE_LEN];
938 snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
943 print_map (struct multipath * mpp)
945 if (mpp->size && mpp->params)
946 printf("0 %llu %s %s\n",
947 mpp->size, DEFAULT_TARGET, mpp->params);
952 print_all_paths (vector pathvec, int banner)
956 char line[MAX_LINE_LEN];
958 if (!VECTOR_SIZE(pathvec)) {
960 fprintf(stdout, "===== no paths =====\n");
965 fprintf(stdout, "===== paths list =====\n");
967 get_path_layout(pathvec);
968 snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
969 fprintf(stdout, "%s", line);
971 vector_foreach_slot (pathvec, pp, i)
972 print_path(pp, PRINT_PATH_LONG);