2 * Copyright (c) 2005 Christophe Varoqui
6 #include <libdevmapper.h>
18 #include "structs_vec.h"
21 #include "configure.h"
22 #include "pgpolicies.h"
26 #include "blacklist.h"
27 #include "switchgroup.h"
28 #include "devmapper.h"
31 #include "discovery.h"
36 #define PRINT_PATH_LONG "%w %i %d %D %p %t %T %s %o"
37 #define PRINT_PATH_INDENT "%i %d %D %t %T %o"
38 #define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r"
39 #define PRINT_PG_INDENT "policy='%s' prio=%p status=%t"
41 #define PRINT_JSON_MULTIPLIER 5
42 #define PRINT_JSON_MAJOR_VERSION 0
43 #define PRINT_JSON_MINOR_VERSION 1
44 #define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \
45 " \"minor_version\": %d,\n"
46 #define PRINT_JSON_START_ELEM "{\n"
47 #define PRINT_JSON_START_MAP " \"map\":"
48 #define PRINT_JSON_START_MAPS "\"maps\": ["
49 #define PRINT_JSON_START_PATHS "\"paths\": ["
50 #define PRINT_JSON_START_GROUPS "\"path_groups\": ["
51 #define PRINT_JSON_END_ELEM "},"
52 #define PRINT_JSON_END_LAST_ELEM "}"
53 #define PRINT_JSON_END_LAST "}\n"
54 #define PRINT_JSON_END_ARRAY "]\n"
55 #define PRINT_JSON_INDENT_N 3
56 #define PRINT_JSON_MAP "{\n" \
57 " \"name\" : \"%n\",\n" \
58 " \"uuid\" : \"%w\",\n" \
59 " \"sysfs\" : \"%d\",\n" \
60 " \"failback\" : \"%F\",\n" \
61 " \"queueing\" : \"%Q\",\n" \
62 " \"paths\" : %N,\n" \
63 " \"write_prot\" : \"%r\",\n" \
64 " \"dm_st\" : \"%t\",\n" \
65 " \"features\" : \"%f\",\n" \
66 " \"hwhandler\" : \"%h\",\n" \
67 " \"action\" : \"%A\",\n" \
68 " \"path_faults\" : %0,\n" \
69 " \"vend\" : \"%v\",\n" \
70 " \"prod\" : \"%p\",\n" \
71 " \"rev\" : \"%e\",\n" \
72 " \"switch_grp\" : %1,\n" \
73 " \"map_loads\" : %2,\n" \
74 " \"total_q_time\" : %3,\n" \
75 " \"q_timeouts\" : %4,"
77 #define PRINT_JSON_GROUP "{\n" \
78 " \"selector\" : \"%s\",\n" \
80 " \"dm_st\" : \"%t\",\n" \
81 " \"marginal_st\" : \"%M\","
83 #define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n"
85 #define PRINT_JSON_PATH "{\n" \
86 " \"dev\" : \"%d\",\n"\
87 " \"dev_t\" : \"%D\",\n" \
88 " \"dm_st\" : \"%t\",\n" \
89 " \"dev_st\" : \"%o\",\n" \
90 " \"chk_st\" : \"%T\",\n" \
91 " \"checker\" : \"%c\",\n" \
93 " \"host_wwnn\" : \"%N\",\n" \
94 " \"target_wwnn\" : \"%n\",\n" \
95 " \"host_wwpn\" : \"%R\",\n" \
96 " \"target_wwpn\" : \"%r\",\n" \
97 " \"host_adapter\" : \"%a\",\n" \
98 " \"lun_hex\" : \"%L\",\n" \
99 " \"marginal_st\" : \"%M\""
101 #define PROGRESS_LEN 10
106 int (*snprint)(struct strbuf *, const struct path * pp);
109 struct multipath_data {
112 int (*snprint)(struct strbuf *, const struct multipath * mpp);
115 struct pathgroup_data {
118 int (*snprint)(struct strbuf *, const struct pathgroup * pgp);
121 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
122 #define MIN(x,y) (((x) > (y)) ? (y) : (x))
124 * information printing helpers
127 snprint_str(struct strbuf *buff, const char *str)
129 return append_strbuf_str(buff, str);
133 snprint_int (struct strbuf *buff, int val)
135 return print_strbuf(buff, "%i", val);
139 snprint_uint (struct strbuf *buff, unsigned int val)
141 return print_strbuf(buff, "%u", val);
145 snprint_size (struct strbuf *buff, unsigned long long size)
147 float s = (float)(size >> 1); /* start with KB */
148 char units[] = {'K','M','G','T','P'};
151 while (s >= 1024 && *u != 'P') {
156 return print_strbuf(buff, "%.*f%c", s < 10, s, *u);
160 * multipath info printing functions
163 snprint_name (struct strbuf *buff, const struct multipath * mpp)
166 return append_strbuf_str(buff, mpp->alias);
168 return append_strbuf_str(buff, mpp->wwid);
172 snprint_sysfs (struct strbuf *buff, const struct multipath * mpp)
174 if (has_dm_info(mpp))
175 return print_strbuf(buff, "dm-%i", mpp->dmi.minor);
177 return append_strbuf_str(buff, "undef");
181 snprint_ro (struct strbuf *buff, const struct multipath * mpp)
183 if (!has_dm_info(mpp))
184 return append_strbuf_str(buff, "undef");
185 if (mpp->dmi.read_only)
186 return append_strbuf_str(buff, "ro");
188 return append_strbuf_str(buff, "rw");
192 snprint_progress (struct strbuf *buff, int cur, int total)
194 size_t initial_len = get_strbuf_len(buff);
198 int i = PROGRESS_LEN * cur / total;
199 int j = PROGRESS_LEN - i;
201 if ((rc = fill_strbuf(buff, 'X', i)) < 0 ||
202 (rc = fill_strbuf(buff, '.', j) < 0)) {
203 truncate_strbuf(buff, initial_len);
208 if ((rc = print_strbuf(buff, " %i/%i", cur, total)) < 0)
210 return get_strbuf_len(buff) - initial_len;
214 snprint_failback (struct strbuf *buff, const struct multipath * mpp)
216 if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
217 return append_strbuf_str(buff, "immediate");
218 if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
219 return append_strbuf_str(buff, "followover");
221 if (!mpp->failback_tick)
222 return append_strbuf_str(buff, "-");
224 return snprint_progress(buff, mpp->failback_tick,
229 snprint_queueing (struct strbuf *buff, const struct multipath * mpp)
231 if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
232 return append_strbuf_str(buff, "off");
233 else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
234 return append_strbuf_str(buff, "on");
235 else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
236 return append_strbuf_str(buff, "-");
237 else if (mpp->no_path_retry > 0) {
238 if (mpp->retry_tick > 0)
240 return print_strbuf(buff, "%i sec", mpp->retry_tick);
241 else if (mpp->retry_tick == 0 && count_active_paths(mpp) > 0)
242 return print_strbuf(buff, "%i chk",
245 return append_strbuf_str(buff, "off");
251 snprint_nb_paths (struct strbuf *buff, const struct multipath * mpp)
253 return snprint_int(buff, count_active_paths(mpp));
257 snprint_dm_map_state (struct strbuf *buff, const struct multipath * mpp)
259 if (!has_dm_info(mpp))
260 return append_strbuf_str(buff, "undef");
261 else if (mpp->dmi.suspended)
262 return append_strbuf_str(buff, "suspend");
264 return append_strbuf_str(buff, "active");
268 snprint_multipath_size (struct strbuf *buff, const struct multipath * mpp)
270 return snprint_size(buff, mpp->size);
274 snprint_features (struct strbuf *buff, const struct multipath * mpp)
276 return snprint_str(buff, mpp->features);
280 snprint_hwhandler (struct strbuf *buff, const struct multipath * mpp)
282 return snprint_str(buff, mpp->hwhandler);
286 snprint_path_faults (struct strbuf *buff, const struct multipath * mpp)
288 return snprint_uint(buff, mpp->stat_path_failures);
292 snprint_switch_grp (struct strbuf *buff, const struct multipath * mpp)
294 return snprint_uint(buff, mpp->stat_switchgroup);
298 snprint_map_loads (struct strbuf *buff, const struct multipath * mpp)
300 return snprint_uint(buff, mpp->stat_map_loads);
304 snprint_total_q_time (struct strbuf *buff, const struct multipath * mpp)
306 return snprint_uint(buff, mpp->stat_total_queueing_time);
310 snprint_q_timeouts (struct strbuf *buff, const struct multipath * mpp)
312 return snprint_uint(buff, mpp->stat_queueing_timeouts);
316 snprint_map_failures (struct strbuf *buff, const struct multipath * mpp)
318 return snprint_uint(buff, mpp->stat_map_failures);
322 snprint_multipath_uuid (struct strbuf *buff, const struct multipath * mpp)
324 return snprint_str(buff, mpp->wwid);
328 snprint_multipath_vpr (struct strbuf *buff, const struct multipath * mpp)
330 struct pathgroup * pgp;
334 vector_foreach_slot(mpp->pg, pgp, i) {
335 vector_foreach_slot(pgp->paths, pp, j) {
336 if (strlen(pp->vendor_id) && strlen(pp->product_id))
337 return print_strbuf(buff, "%s,%s",
338 pp->vendor_id, pp->product_id);
341 return append_strbuf_str(buff, "##,##");
346 snprint_multipath_vend (struct strbuf *buff, const struct multipath * mpp)
348 struct pathgroup * pgp;
352 vector_foreach_slot(mpp->pg, pgp, i) {
353 vector_foreach_slot(pgp->paths, pp, j) {
354 if (strlen(pp->vendor_id))
355 return append_strbuf_str(buff, pp->vendor_id);
358 return append_strbuf_str(buff, "##");
362 snprint_multipath_prod (struct strbuf *buff, const struct multipath * mpp)
364 struct pathgroup * pgp;
368 vector_foreach_slot(mpp->pg, pgp, i) {
369 vector_foreach_slot(pgp->paths, pp, j) {
370 if (strlen(pp->product_id))
371 return append_strbuf_str(buff, pp->product_id);
374 return append_strbuf_str(buff, "##");
378 snprint_multipath_rev (struct strbuf *buff, const struct multipath * mpp)
380 struct pathgroup * pgp;
384 vector_foreach_slot(mpp->pg, pgp, i) {
385 vector_foreach_slot(pgp->paths, pp, j) {
387 return append_strbuf_str(buff, pp->rev);
390 return append_strbuf_str(buff, "##");
394 snprint_multipath_foreign (struct strbuf *buff,
395 __attribute__((unused)) const struct multipath * pp)
397 return append_strbuf_str(buff, "--");
401 snprint_action (struct strbuf *buff, const struct multipath * mpp)
403 switch (mpp->action) {
405 return snprint_str(buff, ACT_REJECT_STR);
407 return snprint_str(buff, ACT_RENAME_STR);
409 return snprint_str(buff, ACT_RELOAD_STR);
411 return snprint_str(buff, ACT_CREATE_STR);
413 return snprint_str(buff, ACT_SWITCHPG_STR);
420 snprint_multipath_vpd_data(struct strbuf *buff,
421 const struct multipath * mpp)
423 struct pathgroup * pgp;
427 vector_foreach_slot(mpp->pg, pgp, i)
428 vector_foreach_slot(pgp->paths, pp, j)
430 return append_strbuf_str(buff, pp->vpd_data);
431 return append_strbuf_str(buff, "[undef]");
435 * path info printing functions
438 snprint_path_uuid (struct strbuf *buff, const struct path * pp)
440 return snprint_str(buff, pp->wwid);
444 snprint_hcil (struct strbuf *buff, const struct path * pp)
446 if (!pp || pp->sg_id.host_no < 0)
447 return append_strbuf_str(buff, "#:#:#:#");
449 return print_strbuf(buff, "%i:%i:%i:%" PRIu64,
458 snprint_path_lunhex (struct strbuf *buff, const struct path * pp)
460 uint64_t lunhex = SCSI_INVALID_LUN, scsilun;
462 if (!pp || pp->sg_id.host_no < 0)
463 return print_strbuf(buff, "0x%016" PRIx64, lunhex);
465 scsilun = pp->sg_id.lun;
466 /* cf. Linux kernel function int_to_scsilun() */
467 lunhex = ((scsilun & 0x000000000000ffffULL) << 48) |
468 ((scsilun & 0x00000000ffff0000ULL) << 16) |
469 ((scsilun & 0x0000ffff00000000ULL) >> 16) |
470 ((scsilun & 0xffff000000000000ULL) >> 48);
471 return print_strbuf(buff, "0x%016" PRIx64, lunhex);
475 snprint_dev (struct strbuf *buff, const struct path * pp)
477 if (!pp || !strlen(pp->dev))
478 return append_strbuf_str(buff, "-");
480 return snprint_str(buff, pp->dev);
484 snprint_dev_t (struct strbuf *buff, const struct path * pp)
486 if (!pp || !strlen(pp->dev))
487 return append_strbuf_str(buff, "#:#");
489 return snprint_str(buff, pp->dev_t);
493 snprint_offline (struct strbuf *buff, const struct path * pp)
496 return append_strbuf_str(buff, "unknown");
497 else if (pp->offline)
498 return append_strbuf_str(buff, "offline");
500 return append_strbuf_str(buff, "running");
504 snprint_chk_state (struct strbuf *buff, const struct path * pp)
507 return append_strbuf_str(buff, "undef");
511 return append_strbuf_str(buff, "ready");
513 return append_strbuf_str(buff, "faulty");
515 return append_strbuf_str(buff, "shaky");
517 return append_strbuf_str(buff, "ghost");
519 return append_strbuf_str(buff, "i/o pending");
521 return append_strbuf_str(buff, "i/o timeout");
523 return append_strbuf_str(buff, "delayed");
525 return append_strbuf_str(buff, "undef");
530 snprint_dm_path_state (struct strbuf *buff, const struct path * pp)
533 return append_strbuf_str(buff, "undef");
535 switch (pp->dmstate) {
537 return append_strbuf_str(buff, "active");
539 return append_strbuf_str(buff, "failed");
541 return append_strbuf_str(buff, "undef");
545 static int snprint_initialized(struct strbuf *buff, const struct path * pp)
547 static const char *init_state_name[] = {
549 [INIT_FAILED] = "failed",
550 [INIT_MISSING_UDEV] = "udev-missing",
551 [INIT_REQUESTED_UDEV] = "udev-requested",
553 [INIT_REMOVED] = "removed",
554 [INIT_PARTIAL] = "partial",
558 if (pp->initialized < INIT_NEW || pp->initialized >= __INIT_LAST)
561 str = init_state_name[pp->initialized];
562 return append_strbuf_str(buff, str);
566 snprint_vpr (struct strbuf *buff, const struct path * pp)
568 return print_strbuf(buff, "%s,%s", pp->vendor_id, pp->product_id);
572 snprint_next_check (struct strbuf *buff, const struct path * pp)
575 return append_strbuf_str(buff, "orphan");
577 return snprint_progress(buff, pp->tick, pp->checkint);
581 snprint_pri (struct strbuf *buff, const struct path * pp)
583 return snprint_int(buff, pp ? pp->priority : -1);
587 snprint_pg_selector (struct strbuf *buff, const struct pathgroup * pgp)
589 const char *s = pgp->mpp->selector;
591 return snprint_str(buff, s ? s : "");
595 snprint_pg_pri (struct strbuf *buff, const struct pathgroup * pgp)
597 return snprint_int(buff, pgp->priority);
601 snprint_pg_state (struct strbuf *buff, const struct pathgroup * pgp)
603 switch (pgp->status) {
604 case PGSTATE_ENABLED:
605 return append_strbuf_str(buff, "enabled");
606 case PGSTATE_DISABLED:
607 return append_strbuf_str(buff, "disabled");
609 return append_strbuf_str(buff, "active");
611 return append_strbuf_str(buff, "undef");
616 snprint_pg_marginal (struct strbuf *buff, const struct pathgroup * pgp)
619 return append_strbuf_str(buff, "marginal");
620 return append_strbuf_str(buff, "normal");
624 snprint_path_size (struct strbuf *buff, const struct path * pp)
626 return snprint_size(buff, pp->size);
630 snprint_path_serial (struct strbuf *buff, const struct path * pp)
632 return snprint_str(buff, pp->serial);
636 snprint_path_mpp (struct strbuf *buff, const struct path * pp)
639 return append_strbuf_str(buff, "[orphan]");
641 return append_strbuf_str(buff, "[unknown]");
642 return snprint_str(buff, pp->mpp->alias);
646 snprint_host_attr (struct strbuf *buff, const struct path * pp, char *attr)
648 struct udev_device *host_dev = NULL;
650 const char *value = NULL;
653 if (pp->bus != SYSFS_BUS_SCSI ||
654 pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
655 return append_strbuf_str(buff, "[undef]");
656 sprintf(host_id, "host%d", pp->sg_id.host_no);
657 host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
660 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
663 value = udev_device_get_sysattr_value(host_dev, attr);
665 ret = snprint_str(buff, value);
666 udev_device_unref(host_dev);
669 ret = append_strbuf_str(buff, "[unknown]");
674 snprint_host_wwnn (struct strbuf *buff, const struct path * pp)
676 return snprint_host_attr(buff, pp, "node_name");
680 snprint_host_wwpn (struct strbuf *buff, const struct path * pp)
682 return snprint_host_attr(buff, pp, "port_name");
686 snprint_tgt_wwpn (struct strbuf *buff, const struct path * pp)
688 struct udev_device *rport_dev = NULL;
690 const char *value = NULL;
693 if (pp->bus != SYSFS_BUS_SCSI ||
694 pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
695 return append_strbuf_str(buff, "[undef]");
696 sprintf(rport_id, "rport-%d:%d-%d",
697 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
698 rport_dev = udev_device_new_from_subsystem_sysname(udev,
699 "fc_remote_ports", rport_id);
701 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
705 value = udev_device_get_sysattr_value(rport_dev, "port_name");
707 ret = snprint_str(buff, value);
708 udev_device_unref(rport_dev);
711 ret = append_strbuf_str(buff, "[unknown]");
717 snprint_tgt_wwnn (struct strbuf *buff, const struct path * pp)
719 if (pp->tgt_node_name[0] == '\0')
720 return append_strbuf_str(buff, "[undef]");
721 return snprint_str(buff, pp->tgt_node_name);
725 snprint_host_adapter (struct strbuf *buff, const struct path * pp)
727 char adapter[SLOT_NAME_SIZE];
729 if (sysfs_get_host_adapter_name(pp, adapter))
730 return append_strbuf_str(buff, "[undef]");
731 return snprint_str(buff, adapter);
735 snprint_path_checker (struct strbuf *buff, const struct path * pp)
737 const char * n = checker_name(&pp->checker);
740 return snprint_str(buff, n);
742 return snprint_str(buff, "(null)");
746 snprint_path_foreign (struct strbuf *buff,
747 __attribute__((unused)) const struct path * pp)
749 return append_strbuf_str(buff, "--");
753 snprint_path_failures(struct strbuf *buff, const struct path * pp)
755 return snprint_int(buff, pp->failcount);
758 /* if you add a protocol string bigger than "scsi:unspec" you must
759 * also change PROTOCOL_BUF_SIZE */
761 snprint_path_protocol(struct strbuf *buff, const struct path * pp)
763 const char *pn = protocol_name[bus_protocol_id(pp)];
766 return append_strbuf_str(buff, pn);
770 snprint_path_marginal(struct strbuf *buff, const struct path * pp)
773 return append_strbuf_str(buff, "marginal");
774 return append_strbuf_str(buff, "normal");
778 snprint_path_vpd_data(struct strbuf *buff, const struct path * pp)
781 return append_strbuf_str(buff, pp->vpd_data);
782 return append_strbuf_str(buff, "[undef]");
786 snprint_alua_tpg(struct strbuf *buff, const struct path * pp)
789 return append_strbuf_str(buff, "[undef]");
790 return print_strbuf(buff, "0x%04x", pp->tpg_id);
793 static const struct multipath_data mpd[] = {
794 {'n', "name", snprint_name},
795 {'w', "uuid", snprint_multipath_uuid},
796 {'d', "sysfs", snprint_sysfs},
797 {'F', "failback", snprint_failback},
798 {'Q', "queueing", snprint_queueing},
799 {'N', "paths", snprint_nb_paths},
800 {'r', "write_prot", snprint_ro},
801 {'t', "dm-st", snprint_dm_map_state},
802 {'S', "size", snprint_multipath_size},
803 {'f', "features", snprint_features},
804 {'x', "failures", snprint_map_failures},
805 {'h', "hwhandler", snprint_hwhandler},
806 {'A', "action", snprint_action},
807 {'0', "path_faults", snprint_path_faults},
808 {'1', "switch_grp", snprint_switch_grp},
809 {'2', "map_loads", snprint_map_loads},
810 {'3', "total_q_time", snprint_total_q_time},
811 {'4', "q_timeouts", snprint_q_timeouts},
812 {'s', "vend/prod/rev", snprint_multipath_vpr},
813 {'v', "vend", snprint_multipath_vend},
814 {'p', "prod", snprint_multipath_prod},
815 {'e', "rev", snprint_multipath_rev},
816 {'G', "foreign", snprint_multipath_foreign},
817 {'g', "vpd page data", snprint_multipath_vpd_data},
820 static const struct path_data pd[] = {
821 {'w', "uuid", snprint_path_uuid},
822 {'i', "hcil", snprint_hcil},
823 {'d', "dev", snprint_dev},
824 {'D', "dev_t", snprint_dev_t},
825 {'t', "dm_st", snprint_dm_path_state},
826 {'o', "dev_st", snprint_offline},
827 {'T', "chk_st", snprint_chk_state},
828 {'s', "vend/prod/rev", snprint_vpr},
829 {'c', "checker", snprint_path_checker},
830 {'C', "next_check", snprint_next_check},
831 {'p', "pri", snprint_pri},
832 {'S', "size", snprint_path_size},
833 {'z', "serial", snprint_path_serial},
834 {'M', "marginal_st", snprint_path_marginal},
835 {'m', "multipath", snprint_path_mpp},
836 {'N', "host WWNN", snprint_host_wwnn},
837 {'n', "target WWNN", snprint_tgt_wwnn},
838 {'R', "host WWPN", snprint_host_wwpn},
839 {'r', "target WWPN", snprint_tgt_wwpn},
840 {'a', "host adapter", snprint_host_adapter},
841 {'G', "foreign", snprint_path_foreign},
842 {'g', "vpd page data", snprint_path_vpd_data},
843 {'0', "failures", snprint_path_failures},
844 {'P', "protocol", snprint_path_protocol},
845 {'I', "init_st", snprint_initialized},
846 {'L', "LUN hex", snprint_path_lunhex},
847 {'A', "TPG", snprint_alua_tpg},
850 static const struct pathgroup_data pgd[] = {
851 {'s', "selector", snprint_pg_selector},
852 {'p', "pri", snprint_pg_pri},
853 {'t', "dm_st", snprint_pg_state},
854 {'M', "marginal_st", snprint_pg_marginal},
857 int snprint_wildcards(struct strbuf *buff)
859 int initial_len = get_strbuf_len(buff);
863 if ((rc = append_strbuf_str(buff, "multipath format wildcards:\n")) < 0)
865 for (i = 0; i < ARRAY_SIZE(mpd); i++)
866 if ((rc = print_strbuf(buff, "%%%c %s\n",
867 mpd[i].wildcard, mpd[i].header)) < 0)
870 if ((rc = append_strbuf_str(buff, "\npath format wildcards:\n")) < 0)
872 for (i = 0; i < ARRAY_SIZE(pd); i++)
873 if ((rc = print_strbuf(buff, "%%%c %s\n",
874 pd[i].wildcard, pd[i].header)) < 0)
877 if ((rc = append_strbuf_str(buff, "\npathgroup format wildcards:\n")) < 0)
879 for (i = 0; i < ARRAY_SIZE(pgd); i++)
880 if ((rc = print_strbuf(buff, "%%%c %s\n",
881 pgd[i].wildcard, pgd[i].header)) < 0)
884 return get_strbuf_len(buff) - initial_len;
887 fieldwidth_t *alloc_path_layout(void) {
888 return calloc(ARRAY_SIZE(pd), sizeof(fieldwidth_t));
891 void get_path_layout(vector pathvec, int header, fieldwidth_t *width)
893 vector gpvec = vector_convert(NULL, pathvec, struct path,
895 _get_path_layout(gpvec,
896 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
902 reset_width(fieldwidth_t *width, enum layout_reset reset, const char *header)
905 case LAYOUT_RESET_HEADER:
906 *width = strlen(header);
908 case LAYOUT_RESET_ZERO:
917 void _get_path_layout (const struct _vector *gpvec, enum layout_reset reset,
921 const struct gen_path *gp;
926 for (j = 0; j < ARRAY_SIZE(pd); j++) {
927 STRBUF_ON_STACK(buff);
929 reset_width(&width[j], reset, pd[j].header);
934 vector_foreach_slot (gpvec, gp, i) {
935 gp->ops->snprint(gp, &buff, pd[j].wildcard);
936 width[j] = MAX(width[j],
937 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
938 truncate_strbuf(&buff, 0);
943 fieldwidth_t *alloc_multipath_layout(void) {
945 return calloc(ARRAY_SIZE(mpd), sizeof(fieldwidth_t));
948 void get_multipath_layout (vector mpvec, int header, fieldwidth_t *width) {
949 vector gmvec = vector_convert(NULL, mpvec, struct multipath,
950 dm_multipath_to_gen);
951 _get_multipath_layout(gmvec,
952 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
958 _get_multipath_layout (const struct _vector *gmvec, enum layout_reset reset,
962 const struct gen_multipath * gm;
966 for (j = 0; j < ARRAY_SIZE(mpd); j++) {
967 STRBUF_ON_STACK(buff);
969 reset_width(&width[j], reset, mpd[j].header);
974 vector_foreach_slot (gmvec, gm, i) {
975 gm->ops->snprint(gm, &buff, mpd[j].wildcard);
976 width[j] = MAX(width[j],
977 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
978 truncate_strbuf(&buff, 0);
980 condlog(4, "%s: width %d", mpd[j].header, width[j]);
984 static int mpd_lookup(char wildcard)
988 for (i = 0; i < ARRAY_SIZE(mpd); i++)
989 if (mpd[i].wildcard == wildcard)
995 int snprint_multipath_attr(const struct gen_multipath* gm,
996 struct strbuf *buf, char wildcard)
998 const struct multipath *mpp = gen_multipath_to_dm(gm);
999 int i = mpd_lookup(wildcard);
1003 return mpd[i].snprint(buf, mpp);
1006 static int pd_lookup(char wildcard)
1010 for (i = 0; i < ARRAY_SIZE(pd); i++)
1011 if (pd[i].wildcard == wildcard)
1017 int snprint_path_attr(const struct gen_path* gp,
1018 struct strbuf *buf, char wildcard)
1020 const struct path *pp = gen_path_to_dm(gp);
1021 int i = pd_lookup(wildcard);
1025 return pd[i].snprint(buf, pp);
1028 static int pgd_lookup(char wildcard)
1032 for (i = 0; i < ARRAY_SIZE(pgd); i++)
1033 if (pgd[i].wildcard == wildcard)
1039 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
1040 struct strbuf *buf, char wildcard)
1042 const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
1043 int i = pgd_lookup(wildcard);
1047 return pgd[i].snprint(buf, pg);
1050 int snprint_multipath_header(struct strbuf *line, const char *format,
1051 const fieldwidth_t *width)
1053 int initial_len = get_strbuf_len(line);
1055 const struct multipath_data * data;
1058 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1061 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1065 if ((iwc = mpd_lookup(*format)) == -1)
1066 continue; /* unknown wildcard */
1069 if ((rc = append_strbuf_str(line, data->header)) < 0)
1071 else if ((unsigned int)rc < width[iwc])
1072 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1076 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1078 return get_strbuf_len(line) - initial_len;
1081 int _snprint_multipath(const struct gen_multipath *gmp,
1082 struct strbuf *line, const char *format,
1083 const fieldwidth_t *width)
1085 int initial_len = get_strbuf_len(line);
1089 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1092 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1096 if ((iwc = mpd_lookup(*format)) == -1)
1097 continue; /* unknown wildcard */
1099 if ((rc = gmp->ops->snprint(gmp, line, *format)) < 0)
1101 else if (width != NULL && (unsigned int)rc < width[iwc])
1102 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1106 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1108 return get_strbuf_len(line) - initial_len;
1111 int snprint_path_header(struct strbuf *line, const char *format,
1112 const fieldwidth_t *width)
1114 int initial_len = get_strbuf_len(line);
1116 const struct path_data *data;
1119 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1122 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1126 if ((iwc = pd_lookup(*format)) == -1)
1127 continue; /* unknown wildcard */
1130 if ((rc = append_strbuf_str(line, data->header)) < 0)
1132 else if ((unsigned int)rc < width[iwc])
1133 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1137 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1139 return get_strbuf_len(line) - initial_len;
1142 int _snprint_path(const struct gen_path *gp, struct strbuf *line,
1143 const char *format, const fieldwidth_t *width)
1145 int initial_len = get_strbuf_len(line);
1149 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1152 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1156 if ((iwc = pd_lookup(*format)) == -1)
1157 continue; /* unknown wildcard */
1159 if ((rc = gp->ops->snprint(gp, line, *format)) < 0)
1161 else if (width != NULL && (unsigned int)rc < width[iwc])
1162 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1166 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1168 return get_strbuf_len(line) - initial_len;
1171 int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
1174 int initial_len = get_strbuf_len(line);
1178 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1179 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1184 if ((rc = ggp->ops->snprint(ggp, line, *format)) < 0)
1188 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1190 return get_strbuf_len(line) - initial_len;
1193 #define snprint_pathgroup(line, fmt, pgp) \
1194 _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, fmt)
1196 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1198 STRBUF_ON_STACK(buff);
1199 fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1200 const struct gen_pathgroup *gpg;
1201 const struct _vector *pgvec, *pathvec;
1204 p_width = alloc_path_layout();
1205 pgvec = gmp->ops->get_pathgroups(gmp);
1207 if (pgvec != NULL) {
1208 vector_foreach_slot (pgvec, gpg, j) {
1209 pathvec = gpg->ops->get_paths(gpg);
1210 if (pathvec == NULL)
1212 _get_path_layout(pathvec, LAYOUT_RESET_NOT, p_width);
1213 gpg->ops->rel_paths(gpg, pathvec);
1215 gmp->ops->rel_pathgroups(gmp, pgvec);
1218 _snprint_multipath_topology(gmp, &buff, verbosity, p_width);
1219 printf("%s", get_strbuf_str(&buff));
1222 int snprint_multipath_style(const struct gen_multipath *gmp,
1223 struct strbuf *style, int verbosity)
1225 const struct multipath *mpp = gen_multipath_to_dm(gmp);
1226 bool need_action = (verbosity > 1 &&
1227 mpp->action != ACT_NOTHING &&
1228 mpp->action != ACT_UNDEF &&
1229 mpp->action != ACT_IMPOSSIBLE);
1230 bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1232 return print_strbuf(style, "%s%s%s%s",
1233 need_action ? "%A: " : "", "%n",
1234 need_wwid ? " (%w)" : "", " %d %s");
1237 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1238 struct strbuf *buff, int verbosity,
1239 const fieldwidth_t *p_width)
1242 const struct _vector *pgvec;
1243 const struct gen_pathgroup *gpg;
1244 STRBUF_ON_STACK(style);
1245 size_t initial_len = get_strbuf_len(buff);
1246 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1251 if ((width = alloc_multipath_layout()) == NULL)
1255 return _snprint_multipath(gmp, buff, "%n", width);
1258 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 1)) < 0) /* bold on */
1260 if ((rc = gmp->ops->style(gmp, &style, verbosity)) < 0)
1263 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 0)) < 0) /* bold off */
1266 if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), width)) < 0
1267 || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, width)) < 0)
1270 pgvec = gmp->ops->get_pathgroups(gmp);
1274 vector_foreach_slot (pgvec, gpg, j) {
1275 const struct _vector *pathvec;
1276 struct gen_path *gp;
1277 bool last_group = j + 1 == VECTOR_SIZE(pgvec);
1279 if ((rc = print_strbuf(buff, "%c-+- ",
1280 last_group ? '`' : '|')) < 0 ||
1281 (rc = _snprint_pathgroup(gpg, buff, PRINT_PG_INDENT)) < 0)
1284 pathvec = gpg->ops->get_paths(gpg);
1285 if (pathvec == NULL)
1288 vector_foreach_slot (pathvec, gp, i) {
1289 if ((rc = print_strbuf(buff, "%c %c- ",
1290 last_group ? ' ' : '|',
1291 i + 1 == VECTOR_SIZE(pathvec) ?
1293 (rc = _snprint_path(gp, buff,
1294 PRINT_PATH_INDENT, p_width)) < 0)
1297 gpg->ops->rel_paths(gpg, pathvec);
1300 gmp->ops->rel_pathgroups(gmp, pgvec);
1302 return get_strbuf_len(buff) - initial_len;
1307 snprint_json(struct strbuf *buff, int indent, const char *json_str)
1311 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1314 return append_strbuf_str(buff, json_str);
1317 static int snprint_json_header(struct strbuf *buff)
1321 if ((rc = snprint_json(buff, 0, PRINT_JSON_START_ELEM)) < 0)
1323 return print_strbuf(buff, PRINT_JSON_START_VERSION,
1324 PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1327 static int snprint_json_elem_footer(struct strbuf *buff, int indent, bool last)
1331 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1335 return append_strbuf_str(buff, PRINT_JSON_END_LAST_ELEM);
1337 return append_strbuf_str(buff, PRINT_JSON_END_ELEM);
1340 static int snprint_multipath_fields_json(struct strbuf *buff,
1341 const struct multipath *mpp, int last)
1345 struct pathgroup *pgp;
1346 size_t initial_len = get_strbuf_len(buff);
1348 if ((rc = snprint_multipath(buff, PRINT_JSON_MAP, mpp, 0)) < 0 ||
1349 (rc = snprint_json(buff, 2, PRINT_JSON_START_GROUPS)) < 0)
1352 vector_foreach_slot (mpp->pg, pgp, i) {
1354 if ((rc = snprint_pathgroup(buff, PRINT_JSON_GROUP, pgp)) < 0 ||
1355 (rc = print_strbuf(buff, PRINT_JSON_GROUP_NUM, i + 1)) < 0 ||
1356 (rc = snprint_json(buff, 3, PRINT_JSON_START_PATHS)) < 0)
1359 vector_foreach_slot (pgp->paths, pp, j) {
1360 if ((rc = snprint_path(buff, PRINT_JSON_PATH,
1362 (rc = snprint_json_elem_footer(
1364 j + 1 == VECTOR_SIZE(pgp->paths))) < 0)
1367 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1368 (rc = snprint_json_elem_footer(
1369 buff, 2, i + 1 == VECTOR_SIZE(mpp->pg))) < 0)
1373 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1374 (rc = snprint_json_elem_footer(buff, 1, last)) < 0)
1377 return get_strbuf_len(buff) - initial_len;
1380 int snprint_multipath_map_json(struct strbuf *buff, const struct multipath * mpp)
1382 size_t initial_len = get_strbuf_len(buff);
1385 if ((rc = snprint_json_header(buff)) < 0 ||
1386 (rc = snprint_json(buff, 0, PRINT_JSON_START_MAP)) < 0)
1389 if ((rc = snprint_multipath_fields_json(buff, mpp, 1)) < 0)
1392 if ((rc = snprint_json(buff, 0, "\n")) < 0 ||
1393 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1396 return get_strbuf_len(buff) - initial_len;
1399 int snprint_multipath_topology_json (struct strbuf *buff,
1400 const struct vectors * vecs)
1403 struct multipath * mpp;
1404 size_t initial_len = get_strbuf_len(buff);
1407 if ((rc = snprint_json_header(buff)) < 0 ||
1408 (rc = snprint_json(buff, 1, PRINT_JSON_START_MAPS)) < 0)
1411 vector_foreach_slot(vecs->mpvec, mpp, i) {
1412 if ((rc = snprint_multipath_fields_json(
1413 buff, mpp, i + 1 == VECTOR_SIZE(vecs->mpvec))) < 0)
1417 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1418 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1421 return get_strbuf_len(buff) - initial_len;
1425 snprint_pcentry (const struct config *conf, struct strbuf *buff,
1426 const struct pcentry *pce)
1430 struct keyword * rootkw;
1431 size_t initial_len = get_strbuf_len(buff);
1433 rootkw = find_keyword(conf->keywords, NULL, "overrides");
1434 assert(rootkw && rootkw->sub);
1435 rootkw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1438 if ((rc = append_strbuf_str(buff, "\tprotocol {\n")) < 0)
1441 iterate_sub_keywords(rootkw, kw, i) {
1442 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, pce)) < 0)
1446 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1448 return get_strbuf_len(buff) - initial_len;
1452 snprint_pctable (const struct config *conf, struct strbuf *buff,
1453 const struct _vector *pctable)
1456 struct pcentry *pce;
1457 struct keyword * rootkw;
1458 size_t initial_len = get_strbuf_len(buff);
1460 rootkw = find_keyword(conf->keywords, NULL, "overrides");
1463 vector_foreach_slot(pctable, pce, i) {
1464 if ((rc = snprint_pcentry(conf, buff, pce)) < 0)
1467 return get_strbuf_len(buff) - initial_len;
1471 snprint_hwentry (const struct config *conf,
1472 struct strbuf *buff, const struct hwentry * hwe)
1475 struct keyword * kw;
1476 struct keyword * rootkw;
1477 size_t initial_len = get_strbuf_len(buff);
1479 rootkw = find_keyword(conf->keywords, NULL, "devices");
1480 assert(rootkw && rootkw->sub);
1481 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1484 if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0)
1487 iterate_sub_keywords(rootkw, kw, i) {
1488 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, hwe)) < 0)
1491 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1493 return get_strbuf_len(buff) - initial_len;
1496 static int snprint_hwtable(const struct config *conf, struct strbuf *buff,
1497 const struct _vector *hwtable)
1500 struct hwentry * hwe;
1501 struct keyword * rootkw;
1502 size_t initial_len = get_strbuf_len(buff);
1504 rootkw = find_keyword(conf->keywords, NULL, "devices");
1507 if ((rc = append_strbuf_str(buff, "devices {\n")) < 0)
1510 vector_foreach_slot (hwtable, hwe, i) {
1511 if ((rc = snprint_hwentry(conf, buff, hwe)) < 0)
1515 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1518 return get_strbuf_len(buff) - initial_len;
1522 snprint_mpentry (const struct config *conf, struct strbuf *buff,
1523 const struct mpentry * mpe, const struct _vector *mpvec)
1526 struct keyword * kw;
1527 struct keyword * rootkw;
1528 struct multipath *mpp = NULL;
1529 size_t initial_len = get_strbuf_len(buff);
1531 if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
1534 rootkw = find_keyword(conf->keywords, NULL, "multipath");
1537 if ((rc = append_strbuf_str(buff, "\tmultipath {\n")) < 0)
1540 iterate_sub_keywords(rootkw, kw, i) {
1541 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, mpe)) < 0)
1545 * This mpp doesn't have alias defined. Add the alias in a comment.
1547 if (mpp != NULL && strcmp(mpp->alias, mpp->wwid) &&
1548 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n", mpp->alias)) < 0)
1551 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1554 return get_strbuf_len(buff) - initial_len;
1557 static int snprint_mptable(const struct config *conf, struct strbuf *buff,
1558 const struct _vector *mpvec)
1561 struct mpentry * mpe;
1562 struct keyword * rootkw;
1563 size_t initial_len = get_strbuf_len(buff);
1565 rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1568 if ((rc = append_strbuf_str(buff, "multipaths {\n")) < 0)
1571 vector_foreach_slot (conf->mptable, mpe, i) {
1572 if ((rc = snprint_mpentry(conf, buff, mpe, mpvec)) < 0)
1575 if (mpvec != NULL) {
1576 struct multipath *mpp;
1578 vector_foreach_slot(mpvec, mpp, i) {
1579 if (find_mpe(conf->mptable, mpp->wwid) != NULL)
1582 if ((rc = print_strbuf(buff,
1583 "\tmultipath {\n\t\twwid \"%s\"\n",
1587 * This mpp doesn't have alias defined in
1588 * multipath.conf - otherwise find_mpe would have
1589 * found it. Add the alias in a comment.
1591 if (strcmp(mpp->alias, mpp->wwid) &&
1592 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n",
1595 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1599 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1601 return get_strbuf_len(buff) - initial_len;
1604 static int snprint_overrides(const struct config *conf, struct strbuf *buff,
1605 const struct hwentry *overrides)
1608 struct keyword *rootkw;
1610 size_t initial_len = get_strbuf_len(buff);
1612 rootkw = find_keyword(conf->keywords, NULL, "overrides");
1615 if ((rc = append_strbuf_str(buff, "overrides {\n")) < 0)
1620 iterate_sub_keywords(rootkw, kw, i) {
1621 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1625 if (overrides->pctable &&
1626 (rc = snprint_pctable(conf, buff, overrides->pctable)) < 0)
1629 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1631 return get_strbuf_len(buff) - initial_len;
1634 static int snprint_defaults(const struct config *conf, struct strbuf *buff)
1637 struct keyword *rootkw;
1639 size_t initial_len = get_strbuf_len(buff);
1641 rootkw = find_keyword(conf->keywords, NULL, "defaults");
1644 if ((rc = append_strbuf_str(buff, "defaults {\n")) < 0)
1647 iterate_sub_keywords(rootkw, kw, i) {
1648 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1651 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1653 return get_strbuf_len(buff) - initial_len;
1656 static int snprint_blacklist_group(struct strbuf *buff, vector *vec)
1658 struct blentry * ble;
1659 size_t initial_len = get_strbuf_len(buff);
1662 if (!VECTOR_SIZE(*vec)) {
1663 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1665 } else vector_foreach_slot (*vec, ble, i) {
1666 rc = print_strbuf(buff, " %s %s\n",
1667 ble->origin == ORIGIN_CONFIG ?
1668 "(config file rule)" :
1669 "(default rule) ", ble->str);
1674 return get_strbuf_len(buff) - initial_len;
1678 snprint_blacklist_devgroup (struct strbuf *buff, vector *vec)
1680 struct blentry_device * bled;
1681 size_t initial_len = get_strbuf_len(buff);
1684 if (!VECTOR_SIZE(*vec)) {
1685 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1687 } else vector_foreach_slot (*vec, bled, i) {
1688 rc = print_strbuf(buff, " %s %s:%s\n",
1689 bled->origin == ORIGIN_CONFIG ?
1690 "(config file rule)" :
1692 bled->vendor, bled->product);
1697 return get_strbuf_len(buff) - initial_len;
1700 int snprint_blacklist_report(struct config *conf, struct strbuf *buff)
1702 size_t initial_len = get_strbuf_len(buff);
1705 if ((rc = append_strbuf_str(buff, "device node rules:\n- blacklist:\n")) < 0)
1707 if ((rc = snprint_blacklist_group(buff, &conf->blist_devnode)) < 0)
1710 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1712 if ((rc = snprint_blacklist_group(buff, &conf->elist_devnode)) < 0)
1715 if ((rc = append_strbuf_str(buff, "udev property rules:\n- blacklist:\n")) < 0)
1717 if ((rc = snprint_blacklist_group(buff, &conf->blist_property)) < 0)
1720 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1722 if ((rc = snprint_blacklist_group(buff, &conf->elist_property)) < 0)
1725 if ((rc = append_strbuf_str(buff, "protocol rules:\n- blacklist:\n")) < 0)
1727 if ((rc = snprint_blacklist_group(buff, &conf->blist_protocol)) < 0)
1730 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1732 if ((rc = snprint_blacklist_group(buff, &conf->elist_protocol)) < 0)
1735 if ((rc = append_strbuf_str(buff, "wwid rules:\n- blacklist:\n")) < 0)
1737 if ((rc = snprint_blacklist_group(buff, &conf->blist_wwid)) < 0)
1740 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1742 if ((rc = snprint_blacklist_group(buff, &conf->elist_wwid)) < 0)
1745 if ((rc = append_strbuf_str(buff, "device rules:\n- blacklist:\n")) < 0)
1747 if ((rc = snprint_blacklist_devgroup(buff, &conf->blist_device)) < 0)
1750 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1752 if ((rc = snprint_blacklist_devgroup(buff, &conf->elist_device)) < 0)
1755 return get_strbuf_len(buff) - initial_len;
1758 static int snprint_blacklist(const struct config *conf, struct strbuf *buff)
1761 struct blentry * ble;
1762 struct blentry_device * bled;
1763 struct keyword *rootkw;
1764 struct keyword *kw, *pkw;
1765 size_t initial_len = get_strbuf_len(buff);
1767 rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1770 if ((rc = append_strbuf_str(buff, "blacklist {\n")) < 0)
1773 vector_foreach_slot (conf->blist_devnode, ble, i) {
1774 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1776 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1779 vector_foreach_slot (conf->blist_wwid, ble, i) {
1780 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1782 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1785 vector_foreach_slot (conf->blist_property, ble, i) {
1786 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1788 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1791 vector_foreach_slot (conf->blist_protocol, ble, i) {
1792 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1794 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1798 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1800 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1801 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1804 vector_foreach_slot (conf->blist_device, bled, i) {
1805 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1808 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1813 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1815 return get_strbuf_len(buff) - initial_len;
1818 static int snprint_blacklist_except(const struct config *conf,
1819 struct strbuf *buff)
1822 struct blentry * ele;
1823 struct blentry_device * eled;
1824 struct keyword *rootkw;
1825 struct keyword *kw, *pkw;
1826 size_t initial_len = get_strbuf_len(buff);
1828 rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1831 if ((rc = append_strbuf_str(buff, "blacklist_exceptions {\n")) < 0)
1834 vector_foreach_slot (conf->elist_devnode, ele, i) {
1835 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1837 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1840 vector_foreach_slot (conf->elist_wwid, ele, i) {
1841 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1843 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1846 vector_foreach_slot (conf->elist_property, ele, i) {
1847 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1849 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1852 vector_foreach_slot (conf->elist_protocol, ele, i) {
1853 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1855 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1859 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1861 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1862 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1865 vector_foreach_slot (conf->elist_device, eled, i) {
1866 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1869 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1874 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1876 return get_strbuf_len(buff) - initial_len;
1879 int __snprint_config(const struct config *conf, struct strbuf *buff,
1880 const struct _vector *hwtable, const struct _vector *mpvec)
1884 if ((rc = snprint_defaults(conf, buff)) < 0 ||
1885 (rc = snprint_blacklist(conf, buff)) < 0 ||
1886 (rc = snprint_blacklist_except(conf, buff)) < 0 ||
1887 (rc = snprint_hwtable(conf, buff,
1888 hwtable ? hwtable : conf->hwtable)) < 0 ||
1889 (rc = snprint_overrides(conf, buff, conf->overrides)) < 0)
1892 if (VECTOR_SIZE(conf->mptable) > 0 ||
1893 (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
1894 if ((rc = snprint_mptable(conf, buff, mpvec)) < 0)
1900 char *snprint_config(const struct config *conf, int *len,
1901 const struct _vector *hwtable, const struct _vector *mpvec)
1903 STRBUF_ON_STACK(buff);
1905 int rc = __snprint_config(conf, &buff, hwtable, mpvec);
1911 *len = get_strbuf_len(&buff);
1912 reply = steal_strbuf_str(&buff);
1917 int snprint_status(struct strbuf *buff, const struct vectors *vecs)
1920 unsigned int count[PATH_MAX_STATE] = {0};
1921 int monitored_count = 0;
1923 size_t initial_len = get_strbuf_len(buff);
1925 vector_foreach_slot (vecs->pathvec, pp, i) {
1928 if ((rc = append_strbuf_str(buff, "path checker states:\n")) < 0)
1930 for (i = 0; i < PATH_MAX_STATE; i++) {
1933 if ((rc = print_strbuf(buff, "%-20s%u\n",
1934 checker_state_name(i), count[i])) < 0)
1938 vector_foreach_slot(vecs->pathvec, pp, i)
1941 if ((rc = print_strbuf(buff, "\npaths: %d\nbusy: %s\n",
1943 is_uevent_busy()? "True" : "False")) < 0)
1946 return get_strbuf_len(buff) - initial_len;
1949 int snprint_devices(struct config *conf, struct strbuf *buff,
1950 const struct vectors *vecs)
1953 struct udev_enumerate *enm;
1954 struct udev_list_entry *item, *first;
1956 size_t initial_len = get_strbuf_len(buff);
1958 enm = udev_enumerate_new(udev);
1961 udev_enumerate_add_match_subsystem(enm, "block");
1963 if ((r = append_strbuf_str(buff, "available block devices:\n")) < 0)
1965 r = udev_enumerate_scan_devices(enm);
1969 first = udev_enumerate_get_list_entry(enm);
1970 udev_list_entry_foreach(item, first) {
1971 const char *path, *devname, *status;
1972 struct udev_device *u_dev;
1974 path = udev_list_entry_get_name(item);
1977 u_dev = udev_device_new_from_syspath(udev, path);
1980 devname = udev_device_get_sysname(u_dev);
1982 udev_device_unref(u_dev);
1986 pp = find_path_by_dev(vecs->pathvec, devname);
1990 hidden = udev_device_get_sysattr_value(u_dev,
1992 if (hidden && !strcmp(hidden, "1"))
1993 status = "hidden, unmonitored";
1994 else if (is_claimed_by_foreign(u_dev))
1995 status = "foreign, monitored";
1997 r = filter_devnode(conf->blist_devnode,
1998 conf->elist_devnode,
2001 status = "devnode blacklisted, unmonitored";
2003 status = "devnode whitelisted, unmonitored";
2006 status = " devnode whitelisted, monitored";
2008 r = print_strbuf(buff, " %s %s\n", devname, status);
2009 udev_device_unref(u_dev);
2014 udev_enumerate_unref(enm);
2018 return get_strbuf_len(buff) - initial_len;
2022 * stdout printing helpers
2024 static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
2028 STRBUF_ON_STACK(line);
2029 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
2031 if (!VECTOR_SIZE(pathvec)) {
2033 fprintf(stdout, "===== no paths =====\n");
2037 if ((width = alloc_path_layout()) == NULL)
2039 get_path_layout(pathvec, 1, width);
2042 append_strbuf_str(&line, "===== paths list =====\n");
2044 snprint_path_header(&line, fmt, width);
2046 vector_foreach_slot (pathvec, pp, i)
2047 snprint_path(&line, fmt, pp, width);
2049 printf("%s", get_strbuf_str(&line));
2052 void print_all_paths(vector pathvec, int banner)
2054 print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);