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->sg_id.proto_id != SCSI_PROTOCOL_FCP)
654 return append_strbuf_str(buff, "[undef]");
655 sprintf(host_id, "host%d", pp->sg_id.host_no);
656 host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
659 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
662 value = udev_device_get_sysattr_value(host_dev, attr);
664 ret = snprint_str(buff, value);
665 udev_device_unref(host_dev);
668 ret = append_strbuf_str(buff, "[unknown]");
673 snprint_host_wwnn (struct strbuf *buff, const struct path * pp)
675 return snprint_host_attr(buff, pp, "node_name");
679 snprint_host_wwpn (struct strbuf *buff, const struct path * pp)
681 return snprint_host_attr(buff, pp, "port_name");
685 snprint_tgt_wwpn (struct strbuf *buff, const struct path * pp)
687 struct udev_device *rport_dev = NULL;
689 const char *value = NULL;
692 if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
693 return append_strbuf_str(buff, "[undef]");
694 sprintf(rport_id, "rport-%d:%d-%d",
695 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
696 rport_dev = udev_device_new_from_subsystem_sysname(udev,
697 "fc_remote_ports", rport_id);
699 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
703 value = udev_device_get_sysattr_value(rport_dev, "port_name");
705 ret = snprint_str(buff, value);
706 udev_device_unref(rport_dev);
709 ret = append_strbuf_str(buff, "[unknown]");
715 snprint_tgt_wwnn (struct strbuf *buff, const struct path * pp)
717 if (pp->tgt_node_name[0] == '\0')
718 return append_strbuf_str(buff, "[undef]");
719 return snprint_str(buff, pp->tgt_node_name);
723 snprint_host_adapter (struct strbuf *buff, const struct path * pp)
725 char adapter[SLOT_NAME_SIZE];
727 if (sysfs_get_host_adapter_name(pp, adapter))
728 return append_strbuf_str(buff, "[undef]");
729 return snprint_str(buff, adapter);
733 snprint_path_checker (struct strbuf *buff, const struct path * pp)
735 const struct checker * c = &pp->checker;
736 return snprint_str(buff, checker_name(c));
740 snprint_path_foreign (struct strbuf *buff,
741 __attribute__((unused)) const struct path * pp)
743 return append_strbuf_str(buff, "--");
747 snprint_path_failures(struct strbuf *buff, const struct path * pp)
749 return snprint_int(buff, pp->failcount);
752 /* if you add a protocol string bigger than "scsi:unspec" you must
753 * also change PROTOCOL_BUF_SIZE */
755 snprint_path_protocol(struct strbuf *buff, const struct path * pp)
757 static const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
758 [SYSFS_BUS_UNDEF] = "undef",
759 [SYSFS_BUS_CCW] = "ccw",
760 [SYSFS_BUS_CCISS] = "cciss",
761 [SYSFS_BUS_NVME] = "nvme",
762 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_FCP] = "scsi:fcp",
763 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SPI] = "scsi:spi",
764 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SSA] = "scsi:ssa",
765 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SBP] = "scsi:sbp",
766 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SRP] = "scsi:srp",
767 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ISCSI] = "scsi:iscsi",
768 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_SAS] = "scsi:sas",
769 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ADT] = "scsi:adt",
770 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_ATA] = "scsi:ata",
771 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_USB] = "scsi:usb",
772 [SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC] = "scsi:unspec",
774 const char *pn = protocol_name[bus_protocol_id(pp)];
777 return append_strbuf_str(buff, pn);
781 snprint_path_marginal(struct strbuf *buff, const struct path * pp)
784 return append_strbuf_str(buff, "marginal");
785 return append_strbuf_str(buff, "normal");
789 snprint_path_vpd_data(struct strbuf *buff, const struct path * pp)
792 return append_strbuf_str(buff, pp->vpd_data);
793 return append_strbuf_str(buff, "[undef]");
796 static const struct multipath_data mpd[] = {
797 {'n', "name", snprint_name},
798 {'w', "uuid", snprint_multipath_uuid},
799 {'d', "sysfs", snprint_sysfs},
800 {'F', "failback", snprint_failback},
801 {'Q', "queueing", snprint_queueing},
802 {'N', "paths", snprint_nb_paths},
803 {'r', "write_prot", snprint_ro},
804 {'t', "dm-st", snprint_dm_map_state},
805 {'S', "size", snprint_multipath_size},
806 {'f', "features", snprint_features},
807 {'x', "failures", snprint_map_failures},
808 {'h', "hwhandler", snprint_hwhandler},
809 {'A', "action", snprint_action},
810 {'0', "path_faults", snprint_path_faults},
811 {'1', "switch_grp", snprint_switch_grp},
812 {'2', "map_loads", snprint_map_loads},
813 {'3', "total_q_time", snprint_total_q_time},
814 {'4', "q_timeouts", snprint_q_timeouts},
815 {'s', "vend/prod/rev", snprint_multipath_vpr},
816 {'v', "vend", snprint_multipath_vend},
817 {'p', "prod", snprint_multipath_prod},
818 {'e', "rev", snprint_multipath_rev},
819 {'G', "foreign", snprint_multipath_foreign},
820 {'g', "vpd page data", snprint_multipath_vpd_data},
823 static const struct path_data pd[] = {
824 {'w', "uuid", snprint_path_uuid},
825 {'i', "hcil", snprint_hcil},
826 {'d', "dev", snprint_dev},
827 {'D', "dev_t", snprint_dev_t},
828 {'t', "dm_st", snprint_dm_path_state},
829 {'o', "dev_st", snprint_offline},
830 {'T', "chk_st", snprint_chk_state},
831 {'s', "vend/prod/rev", snprint_vpr},
832 {'c', "checker", snprint_path_checker},
833 {'C', "next_check", snprint_next_check},
834 {'p', "pri", snprint_pri},
835 {'S', "size", snprint_path_size},
836 {'z', "serial", snprint_path_serial},
837 {'M', "marginal_st", snprint_path_marginal},
838 {'m', "multipath", snprint_path_mpp},
839 {'N', "host WWNN", snprint_host_wwnn},
840 {'n', "target WWNN", snprint_tgt_wwnn},
841 {'R', "host WWPN", snprint_host_wwpn},
842 {'r', "target WWPN", snprint_tgt_wwpn},
843 {'a', "host adapter", snprint_host_adapter},
844 {'G', "foreign", snprint_path_foreign},
845 {'g', "vpd page data", snprint_path_vpd_data},
846 {'0', "failures", snprint_path_failures},
847 {'P', "protocol", snprint_path_protocol},
848 {'I', "init_st", snprint_initialized},
849 {'L', "LUN hex", snprint_path_lunhex},
852 static const struct pathgroup_data pgd[] = {
853 {'s', "selector", snprint_pg_selector},
854 {'p', "pri", snprint_pg_pri},
855 {'t', "dm_st", snprint_pg_state},
856 {'M', "marginal_st", snprint_pg_marginal},
859 int snprint_wildcards(struct strbuf *buff)
861 int initial_len = get_strbuf_len(buff);
865 if ((rc = append_strbuf_str(buff, "multipath format wildcards:\n")) < 0)
867 for (i = 0; i < ARRAY_SIZE(mpd); i++)
868 if ((rc = print_strbuf(buff, "%%%c %s\n",
869 mpd[i].wildcard, mpd[i].header)) < 0)
872 if ((rc = append_strbuf_str(buff, "\npath format wildcards:\n")) < 0)
874 for (i = 0; i < ARRAY_SIZE(pd); i++)
875 if ((rc = print_strbuf(buff, "%%%c %s\n",
876 pd[i].wildcard, pd[i].header)) < 0)
879 if ((rc = append_strbuf_str(buff, "\npathgroup format wildcards:\n")) < 0)
881 for (i = 0; i < ARRAY_SIZE(pgd); i++)
882 if ((rc = print_strbuf(buff, "%%%c %s\n",
883 pgd[i].wildcard, pgd[i].header)) < 0)
886 return get_strbuf_len(buff) - initial_len;
889 fieldwidth_t *alloc_path_layout(void) {
890 return calloc(ARRAY_SIZE(pd), sizeof(fieldwidth_t));
893 void get_path_layout(vector pathvec, int header, fieldwidth_t *width)
895 vector gpvec = vector_convert(NULL, pathvec, struct path,
897 _get_path_layout(gpvec,
898 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
904 reset_width(fieldwidth_t *width, enum layout_reset reset, const char *header)
907 case LAYOUT_RESET_HEADER:
908 *width = strlen(header);
910 case LAYOUT_RESET_ZERO:
919 void _get_path_layout (const struct _vector *gpvec, enum layout_reset reset,
923 const struct gen_path *gp;
928 for (j = 0; j < ARRAY_SIZE(pd); j++) {
929 STRBUF_ON_STACK(buff);
931 reset_width(&width[j], reset, pd[j].header);
936 vector_foreach_slot (gpvec, gp, i) {
937 gp->ops->snprint(gp, &buff, pd[j].wildcard);
938 width[j] = MAX(width[j],
939 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
940 truncate_strbuf(&buff, 0);
945 fieldwidth_t *alloc_multipath_layout(void) {
947 return calloc(ARRAY_SIZE(mpd), sizeof(fieldwidth_t));
950 void get_multipath_layout (vector mpvec, int header, fieldwidth_t *width) {
951 vector gmvec = vector_convert(NULL, mpvec, struct multipath,
952 dm_multipath_to_gen);
953 _get_multipath_layout(gmvec,
954 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
960 _get_multipath_layout (const struct _vector *gmvec, enum layout_reset reset,
964 const struct gen_multipath * gm;
968 for (j = 0; j < ARRAY_SIZE(mpd); j++) {
969 STRBUF_ON_STACK(buff);
971 reset_width(&width[j], reset, mpd[j].header);
976 vector_foreach_slot (gmvec, gm, i) {
977 gm->ops->snprint(gm, &buff, mpd[j].wildcard);
978 width[j] = MAX(width[j],
979 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
980 truncate_strbuf(&buff, 0);
982 condlog(4, "%s: width %d", mpd[j].header, width[j]);
986 static int mpd_lookup(char wildcard)
990 for (i = 0; i < ARRAY_SIZE(mpd); i++)
991 if (mpd[i].wildcard == wildcard)
997 int snprint_multipath_attr(const struct gen_multipath* gm,
998 struct strbuf *buf, char wildcard)
1000 const struct multipath *mpp = gen_multipath_to_dm(gm);
1001 int i = mpd_lookup(wildcard);
1005 return mpd[i].snprint(buf, mpp);
1008 static int pd_lookup(char wildcard)
1012 for (i = 0; i < ARRAY_SIZE(pd); i++)
1013 if (pd[i].wildcard == wildcard)
1019 int snprint_path_attr(const struct gen_path* gp,
1020 struct strbuf *buf, char wildcard)
1022 const struct path *pp = gen_path_to_dm(gp);
1023 int i = pd_lookup(wildcard);
1027 return pd[i].snprint(buf, pp);
1030 static int pgd_lookup(char wildcard)
1034 for (i = 0; i < ARRAY_SIZE(pgd); i++)
1035 if (pgd[i].wildcard == wildcard)
1041 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
1042 struct strbuf *buf, char wildcard)
1044 const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
1045 int i = pgd_lookup(wildcard);
1049 return pgd[i].snprint(buf, pg);
1052 int snprint_multipath_header(struct strbuf *line, const char *format,
1053 const fieldwidth_t *width)
1055 int initial_len = get_strbuf_len(line);
1057 const struct multipath_data * data;
1060 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1063 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1067 if ((iwc = mpd_lookup(*format)) == -1)
1068 continue; /* unknown wildcard */
1071 if ((rc = append_strbuf_str(line, data->header)) < 0)
1073 else if ((unsigned int)rc < width[iwc])
1074 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1078 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1080 return get_strbuf_len(line) - initial_len;
1083 int _snprint_multipath(const struct gen_multipath *gmp,
1084 struct strbuf *line, const char *format,
1085 const fieldwidth_t *width)
1087 int initial_len = get_strbuf_len(line);
1091 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1094 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1098 if ((iwc = mpd_lookup(*format)) == -1)
1099 continue; /* unknown wildcard */
1101 if ((rc = gmp->ops->snprint(gmp, line, *format)) < 0)
1103 else if (width != NULL && (unsigned int)rc < width[iwc])
1104 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1108 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1110 return get_strbuf_len(line) - initial_len;
1113 int snprint_path_header(struct strbuf *line, const char *format,
1114 const fieldwidth_t *width)
1116 int initial_len = get_strbuf_len(line);
1118 const struct path_data *data;
1121 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1124 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1128 if ((iwc = pd_lookup(*format)) == -1)
1129 continue; /* unknown wildcard */
1132 if ((rc = append_strbuf_str(line, data->header)) < 0)
1134 else if ((unsigned int)rc < width[iwc])
1135 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1139 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1141 return get_strbuf_len(line) - initial_len;
1144 int _snprint_path(const struct gen_path *gp, struct strbuf *line,
1145 const char *format, const fieldwidth_t *width)
1147 int initial_len = get_strbuf_len(line);
1151 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1154 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1158 if ((iwc = pd_lookup(*format)) == -1)
1159 continue; /* unknown wildcard */
1161 if ((rc = gp->ops->snprint(gp, line, *format)) < 0)
1163 else if (width != NULL && (unsigned int)rc < width[iwc])
1164 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1168 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1170 return get_strbuf_len(line) - initial_len;
1173 int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
1176 int initial_len = get_strbuf_len(line);
1180 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1181 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1186 if ((rc = ggp->ops->snprint(ggp, line, *format)) < 0)
1190 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1192 return get_strbuf_len(line) - initial_len;
1195 #define snprint_pathgroup(line, fmt, pgp) \
1196 _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, fmt)
1198 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1200 STRBUF_ON_STACK(buff);
1201 fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1202 const struct gen_pathgroup *gpg;
1203 const struct _vector *pgvec, *pathvec;
1206 p_width = alloc_path_layout();
1207 pgvec = gmp->ops->get_pathgroups(gmp);
1209 if (pgvec != NULL) {
1210 vector_foreach_slot (pgvec, gpg, j) {
1211 pathvec = gpg->ops->get_paths(gpg);
1212 if (pathvec == NULL)
1214 _get_path_layout(pathvec, LAYOUT_RESET_NOT, p_width);
1215 gpg->ops->rel_paths(gpg, pathvec);
1217 gmp->ops->rel_pathgroups(gmp, pgvec);
1220 _snprint_multipath_topology(gmp, &buff, verbosity, p_width);
1221 printf("%s", get_strbuf_str(&buff));
1224 int snprint_multipath_style(const struct gen_multipath *gmp,
1225 struct strbuf *style, int verbosity)
1227 const struct multipath *mpp = gen_multipath_to_dm(gmp);
1228 bool need_action = (verbosity > 1 &&
1229 mpp->action != ACT_NOTHING &&
1230 mpp->action != ACT_UNDEF &&
1231 mpp->action != ACT_IMPOSSIBLE);
1232 bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1234 return print_strbuf(style, "%s%s%s%s",
1235 need_action ? "%A: " : "", "%n",
1236 need_wwid ? " (%w)" : "", " %d %s");
1239 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1240 struct strbuf *buff, int verbosity,
1241 const fieldwidth_t *p_width)
1244 const struct _vector *pgvec;
1245 const struct gen_pathgroup *gpg;
1246 STRBUF_ON_STACK(style);
1247 size_t initial_len = get_strbuf_len(buff);
1248 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1253 if ((width = alloc_multipath_layout()) == NULL)
1257 return _snprint_multipath(gmp, buff, "%n", width);
1260 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 1)) < 0) /* bold on */
1262 if ((rc = gmp->ops->style(gmp, &style, verbosity)) < 0)
1265 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 0)) < 0) /* bold off */
1268 if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), width)) < 0
1269 || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, width)) < 0)
1272 pgvec = gmp->ops->get_pathgroups(gmp);
1276 vector_foreach_slot (pgvec, gpg, j) {
1277 const struct _vector *pathvec;
1278 struct gen_path *gp;
1279 bool last_group = j + 1 == VECTOR_SIZE(pgvec);
1281 if ((rc = print_strbuf(buff, "%c-+- ",
1282 last_group ? '`' : '|')) < 0 ||
1283 (rc = _snprint_pathgroup(gpg, buff, PRINT_PG_INDENT)) < 0)
1286 pathvec = gpg->ops->get_paths(gpg);
1287 if (pathvec == NULL)
1290 vector_foreach_slot (pathvec, gp, i) {
1291 if ((rc = print_strbuf(buff, "%c %c- ",
1292 last_group ? ' ' : '|',
1293 i + 1 == VECTOR_SIZE(pathvec) ?
1295 (rc = _snprint_path(gp, buff,
1296 PRINT_PATH_INDENT, p_width)) < 0)
1299 gpg->ops->rel_paths(gpg, pathvec);
1302 gmp->ops->rel_pathgroups(gmp, pgvec);
1304 return get_strbuf_len(buff) - initial_len;
1309 snprint_json(struct strbuf *buff, int indent, const char *json_str)
1313 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1316 return append_strbuf_str(buff, json_str);
1319 static int snprint_json_header(struct strbuf *buff)
1323 if ((rc = snprint_json(buff, 0, PRINT_JSON_START_ELEM)) < 0)
1325 return print_strbuf(buff, PRINT_JSON_START_VERSION,
1326 PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1329 static int snprint_json_elem_footer(struct strbuf *buff, int indent, bool last)
1333 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1337 return append_strbuf_str(buff, PRINT_JSON_END_LAST_ELEM);
1339 return append_strbuf_str(buff, PRINT_JSON_END_ELEM);
1342 static int snprint_multipath_fields_json(struct strbuf *buff,
1343 const struct multipath *mpp, int last)
1347 struct pathgroup *pgp;
1348 size_t initial_len = get_strbuf_len(buff);
1350 if ((rc = snprint_multipath(buff, PRINT_JSON_MAP, mpp, 0)) < 0 ||
1351 (rc = snprint_json(buff, 2, PRINT_JSON_START_GROUPS)) < 0)
1354 vector_foreach_slot (mpp->pg, pgp, i) {
1356 if ((rc = snprint_pathgroup(buff, PRINT_JSON_GROUP, pgp)) < 0 ||
1357 (rc = print_strbuf(buff, PRINT_JSON_GROUP_NUM, i + 1)) < 0 ||
1358 (rc = snprint_json(buff, 3, PRINT_JSON_START_PATHS)) < 0)
1361 vector_foreach_slot (pgp->paths, pp, j) {
1362 if ((rc = snprint_path(buff, PRINT_JSON_PATH,
1364 (rc = snprint_json_elem_footer(
1366 j + 1 == VECTOR_SIZE(pgp->paths))) < 0)
1369 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1370 (rc = snprint_json_elem_footer(
1371 buff, 2, i + 1 == VECTOR_SIZE(mpp->pg))) < 0)
1375 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1376 (rc = snprint_json_elem_footer(buff, 1, last)) < 0)
1379 return get_strbuf_len(buff) - initial_len;
1382 int snprint_multipath_map_json(struct strbuf *buff, const struct multipath * mpp)
1384 size_t initial_len = get_strbuf_len(buff);
1387 if ((rc = snprint_json_header(buff)) < 0 ||
1388 (rc = snprint_json(buff, 0, PRINT_JSON_START_MAP)) < 0)
1391 if ((rc = snprint_multipath_fields_json(buff, mpp, 1)) < 0)
1394 if ((rc = snprint_json(buff, 0, "\n")) < 0 ||
1395 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1398 return get_strbuf_len(buff) - initial_len;
1401 int snprint_multipath_topology_json (struct strbuf *buff,
1402 const struct vectors * vecs)
1405 struct multipath * mpp;
1406 size_t initial_len = get_strbuf_len(buff);
1409 if ((rc = snprint_json_header(buff)) < 0 ||
1410 (rc = snprint_json(buff, 1, PRINT_JSON_START_MAPS)) < 0)
1413 vector_foreach_slot(vecs->mpvec, mpp, i) {
1414 if ((rc = snprint_multipath_fields_json(
1415 buff, mpp, i + 1 == VECTOR_SIZE(vecs->mpvec))) < 0)
1419 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1420 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1423 return get_strbuf_len(buff) - initial_len;
1427 snprint_hwentry (const struct config *conf,
1428 struct strbuf *buff, const struct hwentry * hwe)
1431 struct keyword * kw;
1432 struct keyword * rootkw;
1433 size_t initial_len = get_strbuf_len(buff);
1435 rootkw = find_keyword(conf->keywords, NULL, "devices");
1436 assert(rootkw && rootkw->sub);
1437 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1440 if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0)
1443 iterate_sub_keywords(rootkw, kw, i) {
1444 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, hwe)) < 0)
1447 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1449 return get_strbuf_len(buff) - initial_len;
1452 static int snprint_hwtable(const struct config *conf, struct strbuf *buff,
1453 const struct _vector *hwtable)
1456 struct hwentry * hwe;
1457 struct keyword * rootkw;
1458 size_t initial_len = get_strbuf_len(buff);
1460 rootkw = find_keyword(conf->keywords, NULL, "devices");
1463 if ((rc = append_strbuf_str(buff, "devices {\n")) < 0)
1466 vector_foreach_slot (hwtable, hwe, i) {
1467 if ((rc = snprint_hwentry(conf, buff, hwe)) < 0)
1471 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1474 return get_strbuf_len(buff) - initial_len;
1478 snprint_mpentry (const struct config *conf, struct strbuf *buff,
1479 const struct mpentry * mpe, const struct _vector *mpvec)
1482 struct keyword * kw;
1483 struct keyword * rootkw;
1484 struct multipath *mpp = NULL;
1485 size_t initial_len = get_strbuf_len(buff);
1487 if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
1490 rootkw = find_keyword(conf->keywords, NULL, "multipath");
1493 if ((rc = append_strbuf_str(buff, "\tmultipath {\n")) < 0)
1496 iterate_sub_keywords(rootkw, kw, i) {
1497 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, mpe)) < 0)
1501 * This mpp doesn't have alias defined. Add the alias in a comment.
1503 if (mpp != NULL && strcmp(mpp->alias, mpp->wwid) &&
1504 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n", mpp->alias)) < 0)
1507 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1510 return get_strbuf_len(buff) - initial_len;
1513 static int snprint_mptable(const struct config *conf, struct strbuf *buff,
1514 const struct _vector *mpvec)
1517 struct mpentry * mpe;
1518 struct keyword * rootkw;
1519 size_t initial_len = get_strbuf_len(buff);
1521 rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1524 if ((rc = append_strbuf_str(buff, "multipaths {\n")) < 0)
1527 vector_foreach_slot (conf->mptable, mpe, i) {
1528 if ((rc = snprint_mpentry(conf, buff, mpe, mpvec)) < 0)
1531 if (mpvec != NULL) {
1532 struct multipath *mpp;
1534 vector_foreach_slot(mpvec, mpp, i) {
1535 if (find_mpe(conf->mptable, mpp->wwid) != NULL)
1538 if ((rc = print_strbuf(buff,
1539 "\tmultipath {\n\t\twwid \"%s\"\n",
1543 * This mpp doesn't have alias defined in
1544 * multipath.conf - otherwise find_mpe would have
1545 * found it. Add the alias in a comment.
1547 if (strcmp(mpp->alias, mpp->wwid) &&
1548 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n",
1551 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1555 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1557 return get_strbuf_len(buff) - initial_len;
1560 static int snprint_overrides(const struct config *conf, struct strbuf *buff,
1561 const struct hwentry *overrides)
1564 struct keyword *rootkw;
1566 size_t initial_len = get_strbuf_len(buff);
1568 rootkw = find_keyword(conf->keywords, NULL, "overrides");
1571 if ((rc = append_strbuf_str(buff, "overrides {\n")) < 0)
1576 iterate_sub_keywords(rootkw, kw, i) {
1577 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1581 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1583 return get_strbuf_len(buff) - initial_len;
1586 static int snprint_defaults(const struct config *conf, struct strbuf *buff)
1589 struct keyword *rootkw;
1591 size_t initial_len = get_strbuf_len(buff);
1593 rootkw = find_keyword(conf->keywords, NULL, "defaults");
1596 if ((rc = append_strbuf_str(buff, "defaults {\n")) < 0)
1599 iterate_sub_keywords(rootkw, kw, i) {
1600 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1603 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1605 return get_strbuf_len(buff) - initial_len;
1608 static int snprint_blacklist_group(struct strbuf *buff, vector *vec)
1610 struct blentry * ble;
1611 size_t initial_len = get_strbuf_len(buff);
1614 if (!VECTOR_SIZE(*vec)) {
1615 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1617 } else vector_foreach_slot (*vec, ble, i) {
1618 rc = print_strbuf(buff, " %s %s\n",
1619 ble->origin == ORIGIN_CONFIG ?
1620 "(config file rule)" :
1621 "(default rule) ", ble->str);
1626 return get_strbuf_len(buff) - initial_len;
1630 snprint_blacklist_devgroup (struct strbuf *buff, vector *vec)
1632 struct blentry_device * bled;
1633 size_t initial_len = get_strbuf_len(buff);
1636 if (!VECTOR_SIZE(*vec)) {
1637 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1639 } else vector_foreach_slot (*vec, bled, i) {
1640 rc = print_strbuf(buff, " %s %s:%s\n",
1641 bled->origin == ORIGIN_CONFIG ?
1642 "(config file rule)" :
1644 bled->vendor, bled->product);
1649 return get_strbuf_len(buff) - initial_len;
1652 int snprint_blacklist_report(struct config *conf, struct strbuf *buff)
1654 size_t initial_len = get_strbuf_len(buff);
1657 if ((rc = append_strbuf_str(buff, "device node rules:\n- blacklist:\n")) < 0)
1659 if ((rc = snprint_blacklist_group(buff, &conf->blist_devnode)) < 0)
1662 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1664 if ((rc = snprint_blacklist_group(buff, &conf->elist_devnode)) < 0)
1667 if ((rc = append_strbuf_str(buff, "udev property rules:\n- blacklist:\n")) < 0)
1669 if ((rc = snprint_blacklist_group(buff, &conf->blist_property)) < 0)
1672 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1674 if ((rc = snprint_blacklist_group(buff, &conf->elist_property)) < 0)
1677 if ((rc = append_strbuf_str(buff, "protocol rules:\n- blacklist:\n")) < 0)
1679 if ((rc = snprint_blacklist_group(buff, &conf->blist_protocol)) < 0)
1682 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1684 if ((rc = snprint_blacklist_group(buff, &conf->elist_protocol)) < 0)
1687 if ((rc = append_strbuf_str(buff, "wwid rules:\n- blacklist:\n")) < 0)
1689 if ((rc = snprint_blacklist_group(buff, &conf->blist_wwid)) < 0)
1692 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1694 if ((rc = snprint_blacklist_group(buff, &conf->elist_wwid)) < 0)
1697 if ((rc = append_strbuf_str(buff, "device rules:\n- blacklist:\n")) < 0)
1699 if ((rc = snprint_blacklist_devgroup(buff, &conf->blist_device)) < 0)
1702 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1704 if ((rc = snprint_blacklist_devgroup(buff, &conf->elist_device)) < 0)
1707 return get_strbuf_len(buff) - initial_len;
1710 static int snprint_blacklist(const struct config *conf, struct strbuf *buff)
1713 struct blentry * ble;
1714 struct blentry_device * bled;
1715 struct keyword *rootkw;
1716 struct keyword *kw, *pkw;
1717 size_t initial_len = get_strbuf_len(buff);
1719 rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1722 if ((rc = append_strbuf_str(buff, "blacklist {\n")) < 0)
1725 vector_foreach_slot (conf->blist_devnode, ble, i) {
1726 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1728 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1731 vector_foreach_slot (conf->blist_wwid, ble, i) {
1732 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1734 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1737 vector_foreach_slot (conf->blist_property, ble, i) {
1738 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1740 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1743 vector_foreach_slot (conf->blist_protocol, ble, i) {
1744 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1746 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1750 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1752 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1753 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1756 vector_foreach_slot (conf->blist_device, bled, i) {
1757 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1760 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1765 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1767 return get_strbuf_len(buff) - initial_len;
1770 static int snprint_blacklist_except(const struct config *conf,
1771 struct strbuf *buff)
1774 struct blentry * ele;
1775 struct blentry_device * eled;
1776 struct keyword *rootkw;
1777 struct keyword *kw, *pkw;
1778 size_t initial_len = get_strbuf_len(buff);
1780 rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1783 if ((rc = append_strbuf_str(buff, "blacklist_exceptions {\n")) < 0)
1786 vector_foreach_slot (conf->elist_devnode, ele, i) {
1787 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1789 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1792 vector_foreach_slot (conf->elist_wwid, ele, i) {
1793 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1795 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1798 vector_foreach_slot (conf->elist_property, ele, i) {
1799 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1801 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1804 vector_foreach_slot (conf->elist_protocol, ele, i) {
1805 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1807 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1811 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1813 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1814 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1817 vector_foreach_slot (conf->elist_device, eled, i) {
1818 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1821 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1826 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1828 return get_strbuf_len(buff) - initial_len;
1831 int __snprint_config(const struct config *conf, struct strbuf *buff,
1832 const struct _vector *hwtable, const struct _vector *mpvec)
1836 if ((rc = snprint_defaults(conf, buff)) < 0 ||
1837 (rc = snprint_blacklist(conf, buff)) < 0 ||
1838 (rc = snprint_blacklist_except(conf, buff)) < 0 ||
1839 (rc = snprint_hwtable(conf, buff,
1840 hwtable ? hwtable : conf->hwtable)) < 0 ||
1841 (rc = snprint_overrides(conf, buff, conf->overrides)) < 0)
1844 if (VECTOR_SIZE(conf->mptable) > 0 ||
1845 (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
1846 if ((rc = snprint_mptable(conf, buff, mpvec)) < 0)
1852 char *snprint_config(const struct config *conf, int *len,
1853 const struct _vector *hwtable, const struct _vector *mpvec)
1855 STRBUF_ON_STACK(buff);
1857 int rc = __snprint_config(conf, &buff, hwtable, mpvec);
1863 *len = get_strbuf_len(&buff);
1864 reply = steal_strbuf_str(&buff);
1869 int snprint_status(struct strbuf *buff, const struct vectors *vecs)
1872 unsigned int count[PATH_MAX_STATE] = {0};
1873 int monitored_count = 0;
1875 size_t initial_len = get_strbuf_len(buff);
1877 vector_foreach_slot (vecs->pathvec, pp, i) {
1880 if ((rc = append_strbuf_str(buff, "path checker states:\n")) < 0)
1882 for (i = 0; i < PATH_MAX_STATE; i++) {
1885 if ((rc = print_strbuf(buff, "%-20s%u\n",
1886 checker_state_name(i), count[i])) < 0)
1890 vector_foreach_slot(vecs->pathvec, pp, i)
1893 if ((rc = print_strbuf(buff, "\npaths: %d\nbusy: %s\n",
1895 is_uevent_busy()? "True" : "False")) < 0)
1898 return get_strbuf_len(buff) - initial_len;
1901 int snprint_devices(struct config *conf, struct strbuf *buff,
1902 const struct vectors *vecs)
1905 struct udev_enumerate *enm;
1906 struct udev_list_entry *item, *first;
1908 size_t initial_len = get_strbuf_len(buff);
1910 enm = udev_enumerate_new(udev);
1913 udev_enumerate_add_match_subsystem(enm, "block");
1915 if ((r = append_strbuf_str(buff, "available block devices:\n")) < 0)
1917 r = udev_enumerate_scan_devices(enm);
1921 first = udev_enumerate_get_list_entry(enm);
1922 udev_list_entry_foreach(item, first) {
1923 const char *path, *devname, *status;
1924 struct udev_device *u_dev;
1926 path = udev_list_entry_get_name(item);
1929 u_dev = udev_device_new_from_syspath(udev, path);
1932 devname = udev_device_get_sysname(u_dev);
1934 udev_device_unref(u_dev);
1938 pp = find_path_by_dev(vecs->pathvec, devname);
1942 hidden = udev_device_get_sysattr_value(u_dev,
1944 if (hidden && !strcmp(hidden, "1"))
1945 status = "hidden, unmonitored";
1946 else if (is_claimed_by_foreign(u_dev))
1947 status = "foreign, monitored";
1949 r = filter_devnode(conf->blist_devnode,
1950 conf->elist_devnode,
1953 status = "devnode blacklisted, unmonitored";
1955 status = "devnode whitelisted, unmonitored";
1958 status = " devnode whitelisted, monitored";
1960 r = print_strbuf(buff, " %s %s\n", devname, status);
1961 udev_device_unref(u_dev);
1966 udev_enumerate_unref(enm);
1970 return get_strbuf_len(buff) - initial_len;
1974 * stdout printing helpers
1976 static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
1980 STRBUF_ON_STACK(line);
1981 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1983 if (!VECTOR_SIZE(pathvec)) {
1985 fprintf(stdout, "===== no paths =====\n");
1989 if ((width = alloc_path_layout()) == NULL)
1991 get_path_layout(pathvec, 1, width);
1994 append_strbuf_str(&line, "===== paths list =====\n");
1996 snprint_path_header(&line, fmt, width);
1998 vector_foreach_slot (pathvec, pp, i)
1999 snprint_path(&line, fmt, pp, width);
2001 printf("%s", get_strbuf_str(&line));
2004 void print_all_paths(vector pathvec, int banner)
2006 print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);