2 * Copyright (c) 2005 Christophe Varoqui
6 #include <libdevmapper.h>
19 #include "structs_vec.h"
22 #include "configure.h"
23 #include "pgpolicies.h"
27 #include "blacklist.h"
28 #include "switchgroup.h"
29 #include "devmapper.h"
32 #include "discovery.h"
37 #define PRINT_PATH_LONG "%w %i %d %D %p %t %T %s %o"
38 #define PRINT_PATH_INDENT "%i %d %D %t %T %o"
39 #define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r"
40 #define PRINT_PG_INDENT "policy='%s' prio=%p status=%t"
42 #define PRINT_JSON_MULTIPLIER 5
43 #define PRINT_JSON_MAJOR_VERSION 0
44 #define PRINT_JSON_MINOR_VERSION 1
45 #define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \
46 " \"minor_version\": %d,\n"
47 #define PRINT_JSON_START_ELEM "{\n"
48 #define PRINT_JSON_START_MAP " \"map\":"
49 #define PRINT_JSON_START_MAPS "\"maps\": ["
50 #define PRINT_JSON_START_PATHS "\"paths\": ["
51 #define PRINT_JSON_START_GROUPS "\"path_groups\": ["
52 #define PRINT_JSON_END_ELEM "},"
53 #define PRINT_JSON_END_LAST_ELEM "}"
54 #define PRINT_JSON_END_LAST "}\n"
55 #define PRINT_JSON_END_ARRAY "]\n"
56 #define PRINT_JSON_INDENT_N 3
57 #define PRINT_JSON_MAP "{\n" \
58 " \"name\" : \"%n\",\n" \
59 " \"uuid\" : \"%w\",\n" \
60 " \"sysfs\" : \"%d\",\n" \
61 " \"failback\" : \"%F\",\n" \
62 " \"queueing\" : \"%Q\",\n" \
63 " \"paths\" : %N,\n" \
64 " \"write_prot\" : \"%r\",\n" \
65 " \"dm_st\" : \"%t\",\n" \
66 " \"features\" : \"%f\",\n" \
67 " \"hwhandler\" : \"%h\",\n" \
68 " \"action\" : \"%A\",\n" \
69 " \"path_faults\" : %0,\n" \
70 " \"vend\" : \"%v\",\n" \
71 " \"prod\" : \"%p\",\n" \
72 " \"rev\" : \"%e\",\n" \
73 " \"switch_grp\" : %1,\n" \
74 " \"map_loads\" : %2,\n" \
75 " \"total_q_time\" : %3,\n" \
76 " \"q_timeouts\" : %4,"
78 #define PRINT_JSON_GROUP "{\n" \
79 " \"selector\" : \"%s\",\n" \
81 " \"dm_st\" : \"%t\",\n" \
82 " \"marginal_st\" : \"%M\","
84 #define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n"
86 #define PRINT_JSON_PATH "{\n" \
87 " \"dev\" : \"%d\",\n"\
88 " \"dev_t\" : \"%D\",\n" \
89 " \"dm_st\" : \"%t\",\n" \
90 " \"dev_st\" : \"%o\",\n" \
91 " \"chk_st\" : \"%T\",\n" \
92 " \"checker\" : \"%c\",\n" \
94 " \"host_wwnn\" : \"%N\",\n" \
95 " \"target_wwnn\" : \"%n\",\n" \
96 " \"host_wwpn\" : \"%R\",\n" \
97 " \"target_wwpn\" : \"%r\",\n" \
98 " \"host_adapter\" : \"%a\",\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)
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)
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 (mpp->dmi && mpp->dmi->suspended)
260 return append_strbuf_str(buff, "suspend");
262 return append_strbuf_str(buff, "active");
266 snprint_multipath_size (struct strbuf *buff, const struct multipath * mpp)
268 return snprint_size(buff, mpp->size);
272 snprint_features (struct strbuf *buff, const struct multipath * mpp)
274 return snprint_str(buff, mpp->features);
278 snprint_hwhandler (struct strbuf *buff, const struct multipath * mpp)
280 return snprint_str(buff, mpp->hwhandler);
284 snprint_path_faults (struct strbuf *buff, const struct multipath * mpp)
286 return snprint_uint(buff, mpp->stat_path_failures);
290 snprint_switch_grp (struct strbuf *buff, const struct multipath * mpp)
292 return snprint_uint(buff, mpp->stat_switchgroup);
296 snprint_map_loads (struct strbuf *buff, const struct multipath * mpp)
298 return snprint_uint(buff, mpp->stat_map_loads);
302 snprint_total_q_time (struct strbuf *buff, const struct multipath * mpp)
304 return snprint_uint(buff, mpp->stat_total_queueing_time);
308 snprint_q_timeouts (struct strbuf *buff, const struct multipath * mpp)
310 return snprint_uint(buff, mpp->stat_queueing_timeouts);
314 snprint_map_failures (struct strbuf *buff, const struct multipath * mpp)
316 return snprint_uint(buff, mpp->stat_map_failures);
320 snprint_multipath_uuid (struct strbuf *buff, const struct multipath * mpp)
322 return snprint_str(buff, mpp->wwid);
326 snprint_multipath_vpr (struct strbuf *buff, const struct multipath * mpp)
328 struct pathgroup * pgp;
332 vector_foreach_slot(mpp->pg, pgp, i) {
333 vector_foreach_slot(pgp->paths, pp, j) {
334 if (strlen(pp->vendor_id) && strlen(pp->product_id))
335 return print_strbuf(buff, "%s,%s",
336 pp->vendor_id, pp->product_id);
339 return append_strbuf_str(buff, "##,##");
344 snprint_multipath_vend (struct strbuf *buff, const struct multipath * mpp)
346 struct pathgroup * pgp;
350 vector_foreach_slot(mpp->pg, pgp, i) {
351 vector_foreach_slot(pgp->paths, pp, j) {
352 if (strlen(pp->vendor_id))
353 return append_strbuf_str(buff, pp->vendor_id);
356 return append_strbuf_str(buff, "##");
360 snprint_multipath_prod (struct strbuf *buff, const struct multipath * mpp)
362 struct pathgroup * pgp;
366 vector_foreach_slot(mpp->pg, pgp, i) {
367 vector_foreach_slot(pgp->paths, pp, j) {
368 if (strlen(pp->product_id))
369 return append_strbuf_str(buff, pp->product_id);
372 return append_strbuf_str(buff, "##");
376 snprint_multipath_rev (struct strbuf *buff, const struct multipath * mpp)
378 struct pathgroup * pgp;
382 vector_foreach_slot(mpp->pg, pgp, i) {
383 vector_foreach_slot(pgp->paths, pp, j) {
385 return append_strbuf_str(buff, pp->rev);
388 return append_strbuf_str(buff, "##");
392 snprint_multipath_foreign (struct strbuf *buff,
393 __attribute__((unused)) const struct multipath * pp)
395 return append_strbuf_str(buff, "--");
399 snprint_action (struct strbuf *buff, const struct multipath * mpp)
401 switch (mpp->action) {
403 return snprint_str(buff, ACT_REJECT_STR);
405 return snprint_str(buff, ACT_RENAME_STR);
407 return snprint_str(buff, ACT_RELOAD_STR);
409 return snprint_str(buff, ACT_CREATE_STR);
411 return snprint_str(buff, ACT_SWITCHPG_STR);
418 snprint_multipath_vpd_data(struct strbuf *buff,
419 const struct multipath * mpp)
421 struct pathgroup * pgp;
425 vector_foreach_slot(mpp->pg, pgp, i)
426 vector_foreach_slot(pgp->paths, pp, j)
428 return append_strbuf_str(buff, pp->vpd_data);
429 return append_strbuf_str(buff, "[undef]");
433 * path info printing functions
436 snprint_path_uuid (struct strbuf *buff, const struct path * pp)
438 return snprint_str(buff, pp->wwid);
442 snprint_hcil (struct strbuf *buff, const struct path * pp)
444 if (!pp || pp->sg_id.host_no < 0)
445 return append_strbuf_str(buff, "#:#:#:#");
447 return print_strbuf(buff, "%i:%i:%i:%" PRIu64,
455 snprint_dev (struct strbuf *buff, const struct path * pp)
457 if (!pp || !strlen(pp->dev))
458 return append_strbuf_str(buff, "-");
460 return snprint_str(buff, pp->dev);
464 snprint_dev_t (struct strbuf *buff, const struct path * pp)
466 if (!pp || !strlen(pp->dev))
467 return append_strbuf_str(buff, "#:#");
469 return snprint_str(buff, pp->dev_t);
473 snprint_offline (struct strbuf *buff, const struct path * pp)
476 return append_strbuf_str(buff, "unknown");
477 else if (pp->offline)
478 return append_strbuf_str(buff, "offline");
480 return append_strbuf_str(buff, "running");
484 snprint_chk_state (struct strbuf *buff, const struct path * pp)
487 return append_strbuf_str(buff, "undef");
491 return append_strbuf_str(buff, "ready");
493 return append_strbuf_str(buff, "faulty");
495 return append_strbuf_str(buff, "shaky");
497 return append_strbuf_str(buff, "ghost");
499 return append_strbuf_str(buff, "i/o pending");
501 return append_strbuf_str(buff, "i/o timeout");
503 return append_strbuf_str(buff, "delayed");
505 return append_strbuf_str(buff, "undef");
510 snprint_dm_path_state (struct strbuf *buff, const struct path * pp)
513 return append_strbuf_str(buff, "undef");
515 switch (pp->dmstate) {
517 return append_strbuf_str(buff, "active");
519 return append_strbuf_str(buff, "failed");
521 return append_strbuf_str(buff, "undef");
525 static int snprint_initialized(struct strbuf *buff, const struct path * pp)
527 static const char *init_state_name[] = {
529 [INIT_FAILED] = "failed",
530 [INIT_MISSING_UDEV] = "udev-missing",
531 [INIT_REQUESTED_UDEV] = "udev-requested",
533 [INIT_REMOVED] = "removed",
534 [INIT_PARTIAL] = "partial",
538 if (pp->initialized < INIT_NEW || pp->initialized >= __INIT_LAST)
541 str = init_state_name[pp->initialized];
542 return append_strbuf_str(buff, str);
546 snprint_vpr (struct strbuf *buff, const struct path * pp)
548 return print_strbuf(buff, "%s,%s", pp->vendor_id, pp->product_id);
552 snprint_next_check (struct strbuf *buff, const struct path * pp)
555 return append_strbuf_str(buff, "orphan");
557 return snprint_progress(buff, pp->tick, pp->checkint);
561 snprint_pri (struct strbuf *buff, const struct path * pp)
563 return snprint_int(buff, pp ? pp->priority : -1);
567 snprint_pg_selector (struct strbuf *buff, const struct pathgroup * pgp)
569 const char *s = pgp->mpp->selector;
571 return snprint_str(buff, s ? s : "");
575 snprint_pg_pri (struct strbuf *buff, const struct pathgroup * pgp)
577 return snprint_int(buff, pgp->priority);
581 snprint_pg_state (struct strbuf *buff, const struct pathgroup * pgp)
583 switch (pgp->status) {
584 case PGSTATE_ENABLED:
585 return append_strbuf_str(buff, "enabled");
586 case PGSTATE_DISABLED:
587 return append_strbuf_str(buff, "disabled");
589 return append_strbuf_str(buff, "active");
591 return append_strbuf_str(buff, "undef");
596 snprint_pg_marginal (struct strbuf *buff, const struct pathgroup * pgp)
599 return append_strbuf_str(buff, "marginal");
600 return append_strbuf_str(buff, "normal");
604 snprint_path_size (struct strbuf *buff, const struct path * pp)
606 return snprint_size(buff, pp->size);
610 snprint_path_serial (struct strbuf *buff, const struct path * pp)
612 return snprint_str(buff, pp->serial);
616 snprint_path_mpp (struct strbuf *buff, const struct path * pp)
619 return append_strbuf_str(buff, "[orphan]");
621 return append_strbuf_str(buff, "[unknown]");
622 return snprint_str(buff, pp->mpp->alias);
626 snprint_host_attr (struct strbuf *buff, const struct path * pp, char *attr)
628 struct udev_device *host_dev = NULL;
630 const char *value = NULL;
633 if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
634 return append_strbuf_str(buff, "[undef]");
635 sprintf(host_id, "host%d", pp->sg_id.host_no);
636 host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
639 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
642 value = udev_device_get_sysattr_value(host_dev, attr);
644 ret = snprint_str(buff, value);
645 udev_device_unref(host_dev);
648 ret = append_strbuf_str(buff, "[unknown]");
653 snprint_host_wwnn (struct strbuf *buff, const struct path * pp)
655 return snprint_host_attr(buff, pp, "node_name");
659 snprint_host_wwpn (struct strbuf *buff, const struct path * pp)
661 return snprint_host_attr(buff, pp, "port_name");
665 snprint_tgt_wwpn (struct strbuf *buff, const struct path * pp)
667 struct udev_device *rport_dev = NULL;
669 const char *value = NULL;
672 if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
673 return append_strbuf_str(buff, "[undef]");
674 sprintf(rport_id, "rport-%d:%d-%d",
675 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
676 rport_dev = udev_device_new_from_subsystem_sysname(udev,
677 "fc_remote_ports", rport_id);
679 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
683 value = udev_device_get_sysattr_value(rport_dev, "port_name");
685 ret = snprint_str(buff, value);
686 udev_device_unref(rport_dev);
689 ret = append_strbuf_str(buff, "[unknown]");
695 snprint_tgt_wwnn (struct strbuf *buff, const struct path * pp)
697 if (pp->tgt_node_name[0] == '\0')
698 return append_strbuf_str(buff, "[undef]");
699 return snprint_str(buff, pp->tgt_node_name);
703 snprint_host_adapter (struct strbuf *buff, const struct path * pp)
705 char adapter[SLOT_NAME_SIZE];
707 if (sysfs_get_host_adapter_name(pp, adapter))
708 return append_strbuf_str(buff, "[undef]");
709 return snprint_str(buff, adapter);
713 snprint_path_checker (struct strbuf *buff, const struct path * pp)
715 const struct checker * c = &pp->checker;
716 return snprint_str(buff, checker_name(c));
720 snprint_path_foreign (struct strbuf *buff,
721 __attribute__((unused)) const struct path * pp)
723 return append_strbuf_str(buff, "--");
727 snprint_path_failures(struct strbuf *buff, const struct path * pp)
729 return snprint_int(buff, pp->failcount);
732 /* if you add a protocol string bigger than "scsi:unspec" you must
733 * also change PROTOCOL_BUF_SIZE */
735 snprint_path_protocol(struct strbuf *buff, const struct path * pp)
739 switch (pp->sg_id.proto_id) {
740 case SCSI_PROTOCOL_FCP:
741 return append_strbuf_str(buff, "scsi:fcp");
742 case SCSI_PROTOCOL_SPI:
743 return append_strbuf_str(buff, "scsi:spi");
744 case SCSI_PROTOCOL_SSA:
745 return append_strbuf_str(buff, "scsi:ssa");
746 case SCSI_PROTOCOL_SBP:
747 return append_strbuf_str(buff, "scsi:sbp");
748 case SCSI_PROTOCOL_SRP:
749 return append_strbuf_str(buff, "scsi:srp");
750 case SCSI_PROTOCOL_ISCSI:
751 return append_strbuf_str(buff, "scsi:iscsi");
752 case SCSI_PROTOCOL_SAS:
753 return append_strbuf_str(buff, "scsi:sas");
754 case SCSI_PROTOCOL_ADT:
755 return append_strbuf_str(buff, "scsi:adt");
756 case SCSI_PROTOCOL_ATA:
757 return append_strbuf_str(buff, "scsi:ata");
758 case SCSI_PROTOCOL_USB:
759 return append_strbuf_str(buff, "scsi:usb");
760 case SCSI_PROTOCOL_UNSPEC:
762 return append_strbuf_str(buff, "scsi:unspec");
765 return append_strbuf_str(buff, "ccw");
766 case SYSFS_BUS_CCISS:
767 return append_strbuf_str(buff, "cciss");
769 return append_strbuf_str(buff, "nvme");
770 case SYSFS_BUS_UNDEF:
772 return append_strbuf_str(buff, "undef");
777 snprint_path_marginal(struct strbuf *buff, const struct path * pp)
780 return append_strbuf_str(buff, "marginal");
781 return append_strbuf_str(buff, "normal");
785 snprint_path_vpd_data(struct strbuf *buff, const struct path * pp)
788 return append_strbuf_str(buff, pp->vpd_data);
789 return append_strbuf_str(buff, "[undef]");
792 static const struct multipath_data mpd[] = {
793 {'n', "name", snprint_name},
794 {'w', "uuid", snprint_multipath_uuid},
795 {'d', "sysfs", snprint_sysfs},
796 {'F', "failback", snprint_failback},
797 {'Q', "queueing", snprint_queueing},
798 {'N', "paths", snprint_nb_paths},
799 {'r', "write_prot", snprint_ro},
800 {'t', "dm-st", snprint_dm_map_state},
801 {'S', "size", snprint_multipath_size},
802 {'f', "features", snprint_features},
803 {'x', "failures", snprint_map_failures},
804 {'h', "hwhandler", snprint_hwhandler},
805 {'A', "action", snprint_action},
806 {'0', "path_faults", snprint_path_faults},
807 {'1', "switch_grp", snprint_switch_grp},
808 {'2', "map_loads", snprint_map_loads},
809 {'3', "total_q_time", snprint_total_q_time},
810 {'4', "q_timeouts", snprint_q_timeouts},
811 {'s', "vend/prod/rev", snprint_multipath_vpr},
812 {'v', "vend", snprint_multipath_vend},
813 {'p', "prod", snprint_multipath_prod},
814 {'e', "rev", snprint_multipath_rev},
815 {'G', "foreign", snprint_multipath_foreign},
816 {'g', "vpd page data", snprint_multipath_vpd_data},
819 static const struct path_data pd[] = {
820 {'w', "uuid", snprint_path_uuid},
821 {'i', "hcil", snprint_hcil},
822 {'d', "dev", snprint_dev},
823 {'D', "dev_t", snprint_dev_t},
824 {'t', "dm_st", snprint_dm_path_state},
825 {'o', "dev_st", snprint_offline},
826 {'T', "chk_st", snprint_chk_state},
827 {'s', "vend/prod/rev", snprint_vpr},
828 {'c', "checker", snprint_path_checker},
829 {'C', "next_check", snprint_next_check},
830 {'p', "pri", snprint_pri},
831 {'S', "size", snprint_path_size},
832 {'z', "serial", snprint_path_serial},
833 {'M', "marginal_st", snprint_path_marginal},
834 {'m', "multipath", snprint_path_mpp},
835 {'N', "host WWNN", snprint_host_wwnn},
836 {'n', "target WWNN", snprint_tgt_wwnn},
837 {'R', "host WWPN", snprint_host_wwpn},
838 {'r', "target WWPN", snprint_tgt_wwpn},
839 {'a', "host adapter", snprint_host_adapter},
840 {'G', "foreign", snprint_path_foreign},
841 {'g', "vpd page data", snprint_path_vpd_data},
842 {'0', "failures", snprint_path_failures},
843 {'P', "protocol", snprint_path_protocol},
844 {'I', "init_st", snprint_initialized},
847 static const struct pathgroup_data pgd[] = {
848 {'s', "selector", snprint_pg_selector},
849 {'p', "pri", snprint_pg_pri},
850 {'t', "dm_st", snprint_pg_state},
851 {'M', "marginal_st", snprint_pg_marginal},
854 int snprint_wildcards(struct strbuf *buff)
856 int initial_len = get_strbuf_len(buff);
860 if ((rc = append_strbuf_str(buff, "multipath format wildcards:\n")) < 0)
862 for (i = 0; i < ARRAY_SIZE(mpd); i++)
863 if ((rc = print_strbuf(buff, "%%%c %s\n",
864 mpd[i].wildcard, mpd[i].header)) < 0)
867 if ((rc = append_strbuf_str(buff, "\npath format wildcards:\n")) < 0)
869 for (i = 0; i < ARRAY_SIZE(pd); i++)
870 if ((rc = print_strbuf(buff, "%%%c %s\n",
871 pd[i].wildcard, pd[i].header)) < 0)
874 if ((rc = append_strbuf_str(buff, "\npathgroup format wildcards:\n")) < 0)
876 for (i = 0; i < ARRAY_SIZE(pgd); i++)
877 if ((rc = print_strbuf(buff, "%%%c %s\n",
878 pgd[i].wildcard, pgd[i].header)) < 0)
881 return get_strbuf_len(buff) - initial_len;
884 fieldwidth_t *alloc_path_layout(void) {
885 return calloc(ARRAY_SIZE(pd), sizeof(fieldwidth_t));
888 void get_path_layout(vector pathvec, int header, fieldwidth_t *width)
890 vector gpvec = vector_convert(NULL, pathvec, struct path,
892 _get_path_layout(gpvec,
893 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
899 reset_width(fieldwidth_t *width, enum layout_reset reset, const char *header)
902 case LAYOUT_RESET_HEADER:
903 *width = strlen(header);
905 case LAYOUT_RESET_ZERO:
914 void _get_path_layout (const struct _vector *gpvec, enum layout_reset reset,
918 const struct gen_path *gp;
923 for (j = 0; j < ARRAY_SIZE(pd); j++) {
924 STRBUF_ON_STACK(buff);
926 reset_width(&width[j], reset, pd[j].header);
931 vector_foreach_slot (gpvec, gp, i) {
932 gp->ops->snprint(gp, &buff, pd[j].wildcard);
933 width[j] = MAX(width[j],
934 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
935 truncate_strbuf(&buff, 0);
940 fieldwidth_t *alloc_multipath_layout(void) {
942 return calloc(ARRAY_SIZE(mpd), sizeof(fieldwidth_t));
945 void get_multipath_layout (vector mpvec, int header, fieldwidth_t *width) {
946 vector gmvec = vector_convert(NULL, mpvec, struct multipath,
947 dm_multipath_to_gen);
948 _get_multipath_layout(gmvec,
949 header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO,
955 _get_multipath_layout (const struct _vector *gmvec, enum layout_reset reset,
959 const struct gen_multipath * gm;
963 for (j = 0; j < ARRAY_SIZE(mpd); j++) {
964 STRBUF_ON_STACK(buff);
966 reset_width(&width[j], reset, mpd[j].header);
971 vector_foreach_slot (gmvec, gm, i) {
972 gm->ops->snprint(gm, &buff, mpd[j].wildcard);
973 width[j] = MAX(width[j],
974 MIN(get_strbuf_len(&buff), MAX_FIELD_WIDTH));
975 truncate_strbuf(&buff, 0);
977 condlog(4, "%s: width %d", mpd[j].header, width[j]);
981 static int mpd_lookup(char wildcard)
985 for (i = 0; i < ARRAY_SIZE(mpd); i++)
986 if (mpd[i].wildcard == wildcard)
992 int snprint_multipath_attr(const struct gen_multipath* gm,
993 struct strbuf *buf, char wildcard)
995 const struct multipath *mpp = gen_multipath_to_dm(gm);
996 int i = mpd_lookup(wildcard);
1000 return mpd[i].snprint(buf, mpp);
1003 static int pd_lookup(char wildcard)
1007 for (i = 0; i < ARRAY_SIZE(pd); i++)
1008 if (pd[i].wildcard == wildcard)
1014 int snprint_path_attr(const struct gen_path* gp,
1015 struct strbuf *buf, char wildcard)
1017 const struct path *pp = gen_path_to_dm(gp);
1018 int i = pd_lookup(wildcard);
1022 return pd[i].snprint(buf, pp);
1025 static int pgd_lookup(char wildcard)
1029 for (i = 0; i < ARRAY_SIZE(pgd); i++)
1030 if (pgd[i].wildcard == wildcard)
1036 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
1037 struct strbuf *buf, char wildcard)
1039 const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
1040 int i = pgd_lookup(wildcard);
1044 return pgd[i].snprint(buf, pg);
1047 int snprint_multipath_header(struct strbuf *line, const char *format,
1048 const fieldwidth_t *width)
1050 int initial_len = get_strbuf_len(line);
1052 const struct multipath_data * data;
1055 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1058 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1062 if ((iwc = mpd_lookup(*format)) == -1)
1063 continue; /* unknown wildcard */
1066 if ((rc = append_strbuf_str(line, data->header)) < 0)
1068 else if ((unsigned int)rc < width[iwc])
1069 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1073 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1075 return get_strbuf_len(line) - initial_len;
1078 int _snprint_multipath(const struct gen_multipath *gmp,
1079 struct strbuf *line, const char *format,
1080 const fieldwidth_t *width)
1082 int initial_len = get_strbuf_len(line);
1086 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1089 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1093 if ((iwc = mpd_lookup(*format)) == -1)
1094 continue; /* unknown wildcard */
1096 if ((rc = gmp->ops->snprint(gmp, line, *format)) < 0)
1098 else if (width != NULL && (unsigned int)rc < width[iwc])
1099 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1103 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1105 return get_strbuf_len(line) - initial_len;
1108 int snprint_path_header(struct strbuf *line, const char *format,
1109 const fieldwidth_t *width)
1111 int initial_len = get_strbuf_len(line);
1113 const struct path_data *data;
1116 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1119 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1123 if ((iwc = pd_lookup(*format)) == -1)
1124 continue; /* unknown wildcard */
1127 if ((rc = append_strbuf_str(line, data->header)) < 0)
1129 else if ((unsigned int)rc < width[iwc])
1130 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1134 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1136 return get_strbuf_len(line) - initial_len;
1139 int _snprint_path(const struct gen_path *gp, struct strbuf *line,
1140 const char *format, const fieldwidth_t *width)
1142 int initial_len = get_strbuf_len(line);
1146 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1149 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1153 if ((iwc = pd_lookup(*format)) == -1)
1154 continue; /* unknown wildcard */
1156 if ((rc = gp->ops->snprint(gp, line, *format)) < 0)
1158 else if (width != NULL && (unsigned int)rc < width[iwc])
1159 if ((rc = fill_strbuf(line, ' ', width[iwc] - rc)) < 0)
1163 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1165 return get_strbuf_len(line) - initial_len;
1168 int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
1171 int initial_len = get_strbuf_len(line);
1175 for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
1176 if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
1181 if ((rc = ggp->ops->snprint(ggp, line, *format)) < 0)
1185 if ((rc = print_strbuf(line, "%s\n", format)) < 0)
1187 return get_strbuf_len(line) - initial_len;
1190 #define snprint_pathgroup(line, fmt, pgp) \
1191 _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, fmt)
1193 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1195 STRBUF_ON_STACK(buff);
1196 fieldwidth_t *p_width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1197 const struct gen_pathgroup *gpg;
1198 const struct _vector *pgvec, *pathvec;
1201 p_width = alloc_path_layout();
1202 pgvec = gmp->ops->get_pathgroups(gmp);
1204 if (pgvec != NULL) {
1205 vector_foreach_slot (pgvec, gpg, j) {
1206 pathvec = gpg->ops->get_paths(gpg);
1207 if (pathvec == NULL)
1209 _get_path_layout(pathvec, LAYOUT_RESET_NOT, p_width);
1210 gpg->ops->rel_paths(gpg, pathvec);
1212 gmp->ops->rel_pathgroups(gmp, pgvec);
1215 _snprint_multipath_topology(gmp, &buff, verbosity, p_width);
1216 printf("%s", get_strbuf_str(&buff));
1219 int snprint_multipath_style(const struct gen_multipath *gmp,
1220 struct strbuf *style, int verbosity)
1222 const struct multipath *mpp = gen_multipath_to_dm(gmp);
1223 bool need_action = (verbosity > 1 &&
1224 mpp->action != ACT_NOTHING &&
1225 mpp->action != ACT_UNDEF &&
1226 mpp->action != ACT_IMPOSSIBLE);
1227 bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1229 return print_strbuf(style, "%s%s%s%s",
1230 need_action ? "%A: " : "", "%n",
1231 need_wwid ? " (%w)" : "", " %d %s");
1234 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1235 struct strbuf *buff, int verbosity,
1236 const fieldwidth_t *p_width)
1239 const struct _vector *pgvec;
1240 const struct gen_pathgroup *gpg;
1241 STRBUF_ON_STACK(style);
1242 size_t initial_len = get_strbuf_len(buff);
1243 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1248 if ((width = alloc_multipath_layout()) == NULL)
1252 return _snprint_multipath(gmp, buff, "%n", width);
1255 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 1)) < 0) /* bold on */
1257 if ((rc = gmp->ops->style(gmp, &style, verbosity)) < 0)
1260 (rc = print_strbuf(&style, "%c[%dm", 0x1B, 0)) < 0) /* bold off */
1263 if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), width)) < 0
1264 || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, width)) < 0)
1267 pgvec = gmp->ops->get_pathgroups(gmp);
1271 vector_foreach_slot (pgvec, gpg, j) {
1272 const struct _vector *pathvec;
1273 struct gen_path *gp;
1274 bool last_group = j + 1 == VECTOR_SIZE(pgvec);
1276 if ((rc = print_strbuf(buff, "%c-+- ",
1277 last_group ? '`' : '|')) < 0 ||
1278 (rc = _snprint_pathgroup(gpg, buff, PRINT_PG_INDENT)) < 0)
1281 pathvec = gpg->ops->get_paths(gpg);
1282 if (pathvec == NULL)
1285 vector_foreach_slot (pathvec, gp, i) {
1286 if ((rc = print_strbuf(buff, "%c %c- ",
1287 last_group ? ' ' : '|',
1288 i + 1 == VECTOR_SIZE(pathvec) ?
1290 (rc = _snprint_path(gp, buff,
1291 PRINT_PATH_INDENT, p_width)) < 0)
1294 gpg->ops->rel_paths(gpg, pathvec);
1297 gmp->ops->rel_pathgroups(gmp, pgvec);
1299 return get_strbuf_len(buff) - initial_len;
1304 snprint_json(struct strbuf *buff, int indent, const char *json_str)
1308 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1311 return append_strbuf_str(buff, json_str);
1314 static int snprint_json_header(struct strbuf *buff)
1318 if ((rc = snprint_json(buff, 0, PRINT_JSON_START_ELEM)) < 0)
1320 return print_strbuf(buff, PRINT_JSON_START_VERSION,
1321 PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1324 static int snprint_json_elem_footer(struct strbuf *buff, int indent, bool last)
1328 if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
1332 return append_strbuf_str(buff, PRINT_JSON_END_LAST_ELEM);
1334 return append_strbuf_str(buff, PRINT_JSON_END_ELEM);
1337 static int snprint_multipath_fields_json(struct strbuf *buff,
1338 const struct multipath *mpp, int last)
1342 struct pathgroup *pgp;
1343 size_t initial_len = get_strbuf_len(buff);
1345 if ((rc = snprint_multipath(buff, PRINT_JSON_MAP, mpp, 0)) < 0 ||
1346 (rc = snprint_json(buff, 2, PRINT_JSON_START_GROUPS)) < 0)
1349 vector_foreach_slot (mpp->pg, pgp, i) {
1351 if ((rc = snprint_pathgroup(buff, PRINT_JSON_GROUP, pgp)) < 0 ||
1352 (rc = print_strbuf(buff, PRINT_JSON_GROUP_NUM, i + 1)) < 0 ||
1353 (rc = snprint_json(buff, 3, PRINT_JSON_START_PATHS)) < 0)
1356 vector_foreach_slot (pgp->paths, pp, j) {
1357 if ((rc = snprint_path(buff, PRINT_JSON_PATH,
1359 (rc = snprint_json_elem_footer(
1361 j + 1 == VECTOR_SIZE(pgp->paths))) < 0)
1364 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1365 (rc = snprint_json_elem_footer(
1366 buff, 2, i + 1 == VECTOR_SIZE(mpp->pg))) < 0)
1370 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1371 (rc = snprint_json_elem_footer(buff, 1, last)) < 0)
1374 return get_strbuf_len(buff) - initial_len;
1377 int snprint_multipath_map_json(struct strbuf *buff, const struct multipath * mpp)
1379 size_t initial_len = get_strbuf_len(buff);
1382 if ((rc = snprint_json_header(buff)) < 0 ||
1383 (rc = snprint_json(buff, 0, PRINT_JSON_START_MAP)) < 0)
1386 if ((rc = snprint_multipath_fields_json(buff, mpp, 1)) < 0)
1389 if ((rc = snprint_json(buff, 0, "\n")) < 0 ||
1390 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1393 return get_strbuf_len(buff) - initial_len;
1396 int snprint_multipath_topology_json (struct strbuf *buff,
1397 const struct vectors * vecs)
1400 struct multipath * mpp;
1401 size_t initial_len = get_strbuf_len(buff);
1404 if ((rc = snprint_json_header(buff)) < 0 ||
1405 (rc = snprint_json(buff, 1, PRINT_JSON_START_MAPS)) < 0)
1408 vector_foreach_slot(vecs->mpvec, mpp, i) {
1409 if ((rc = snprint_multipath_fields_json(
1410 buff, mpp, i + 1 == VECTOR_SIZE(vecs->mpvec))) < 0)
1414 if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
1415 (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
1418 return get_strbuf_len(buff) - initial_len;
1422 snprint_hwentry (const struct config *conf,
1423 struct strbuf *buff, const struct hwentry * hwe)
1426 struct keyword * kw;
1427 struct keyword * rootkw;
1428 size_t initial_len = get_strbuf_len(buff);
1430 rootkw = find_keyword(conf->keywords, NULL, "devices");
1431 assert(rootkw && rootkw->sub);
1432 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1435 if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0)
1438 iterate_sub_keywords(rootkw, kw, i) {
1439 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, hwe)) < 0)
1442 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1444 return get_strbuf_len(buff) - initial_len;
1447 static int snprint_hwtable(const struct config *conf, struct strbuf *buff,
1448 const struct _vector *hwtable)
1451 struct hwentry * hwe;
1452 struct keyword * rootkw;
1453 size_t initial_len = get_strbuf_len(buff);
1455 rootkw = find_keyword(conf->keywords, NULL, "devices");
1458 if ((rc = append_strbuf_str(buff, "devices {\n")) < 0)
1461 vector_foreach_slot (hwtable, hwe, i) {
1462 if ((rc = snprint_hwentry(conf, buff, hwe)) < 0)
1466 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1469 return get_strbuf_len(buff) - initial_len;
1473 snprint_mpentry (const struct config *conf, struct strbuf *buff,
1474 const struct mpentry * mpe, const struct _vector *mpvec)
1477 struct keyword * kw;
1478 struct keyword * rootkw;
1479 struct multipath *mpp = NULL;
1480 size_t initial_len = get_strbuf_len(buff);
1482 if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
1485 rootkw = find_keyword(conf->keywords, NULL, "multipath");
1488 if ((rc = append_strbuf_str(buff, "\tmultipath {\n")) < 0)
1491 iterate_sub_keywords(rootkw, kw, i) {
1492 if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, mpe)) < 0)
1496 * This mpp doesn't have alias defined. Add the alias in a comment.
1498 if (mpp != NULL && strcmp(mpp->alias, mpp->wwid) &&
1499 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n", mpp->alias)) < 0)
1502 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1505 return get_strbuf_len(buff) - initial_len;
1508 static int snprint_mptable(const struct config *conf, struct strbuf *buff,
1509 const struct _vector *mpvec)
1512 struct mpentry * mpe;
1513 struct keyword * rootkw;
1514 size_t initial_len = get_strbuf_len(buff);
1516 rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1519 if ((rc = append_strbuf_str(buff, "multipaths {\n")) < 0)
1522 vector_foreach_slot (conf->mptable, mpe, i) {
1523 if ((rc = snprint_mpentry(conf, buff, mpe, mpvec)) < 0)
1526 if (mpvec != NULL) {
1527 struct multipath *mpp;
1529 vector_foreach_slot(mpvec, mpp, i) {
1530 if (find_mpe(conf->mptable, mpp->wwid) != NULL)
1533 if ((rc = print_strbuf(buff,
1534 "\tmultipath {\n\t\twwid \"%s\"\n",
1538 * This mpp doesn't have alias defined in
1539 * multipath.conf - otherwise find_mpe would have
1540 * found it. Add the alias in a comment.
1542 if (strcmp(mpp->alias, mpp->wwid) &&
1543 (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n",
1546 if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
1550 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1552 return get_strbuf_len(buff) - initial_len;
1555 static int snprint_overrides(const struct config *conf, struct strbuf *buff,
1556 const struct hwentry *overrides)
1559 struct keyword *rootkw;
1561 size_t initial_len = get_strbuf_len(buff);
1563 rootkw = find_keyword(conf->keywords, NULL, "overrides");
1566 if ((rc = append_strbuf_str(buff, "overrides {\n")) < 0)
1571 iterate_sub_keywords(rootkw, kw, i) {
1572 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1576 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1578 return get_strbuf_len(buff) - initial_len;
1581 static int snprint_defaults(const struct config *conf, struct strbuf *buff)
1584 struct keyword *rootkw;
1586 size_t initial_len = get_strbuf_len(buff);
1588 rootkw = find_keyword(conf->keywords, NULL, "defaults");
1591 if ((rc = append_strbuf_str(buff, "defaults {\n")) < 0)
1594 iterate_sub_keywords(rootkw, kw, i) {
1595 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
1598 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1600 return get_strbuf_len(buff) - initial_len;
1603 static int snprint_blacklist_group(struct strbuf *buff, vector *vec)
1605 struct blentry * ble;
1606 size_t initial_len = get_strbuf_len(buff);
1609 if (!VECTOR_SIZE(*vec)) {
1610 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1612 } else vector_foreach_slot (*vec, ble, i) {
1613 rc = print_strbuf(buff, " %s %s\n",
1614 ble->origin == ORIGIN_CONFIG ?
1615 "(config file rule)" :
1616 "(default rule) ", ble->str);
1621 return get_strbuf_len(buff) - initial_len;
1625 snprint_blacklist_devgroup (struct strbuf *buff, vector *vec)
1627 struct blentry_device * bled;
1628 size_t initial_len = get_strbuf_len(buff);
1631 if (!VECTOR_SIZE(*vec)) {
1632 if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
1634 } else vector_foreach_slot (*vec, bled, i) {
1635 rc = print_strbuf(buff, " %s %s:%s\n",
1636 bled->origin == ORIGIN_CONFIG ?
1637 "(config file rule)" :
1639 bled->vendor, bled->product);
1644 return get_strbuf_len(buff) - initial_len;
1647 int snprint_blacklist_report(struct config *conf, struct strbuf *buff)
1649 size_t initial_len = get_strbuf_len(buff);
1652 if ((rc = append_strbuf_str(buff, "device node rules:\n- blacklist:\n")) < 0)
1654 if ((rc = snprint_blacklist_group(buff, &conf->blist_devnode)) < 0)
1657 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1659 if ((rc = snprint_blacklist_group(buff, &conf->elist_devnode)) < 0)
1662 if ((rc = append_strbuf_str(buff, "udev property rules:\n- blacklist:\n")) < 0)
1664 if ((rc = snprint_blacklist_group(buff, &conf->blist_property)) < 0)
1667 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1669 if ((rc = snprint_blacklist_group(buff, &conf->elist_property)) < 0)
1672 if ((rc = append_strbuf_str(buff, "protocol rules:\n- blacklist:\n")) < 0)
1674 if ((rc = snprint_blacklist_group(buff, &conf->blist_protocol)) < 0)
1677 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1679 if ((rc = snprint_blacklist_group(buff, &conf->elist_protocol)) < 0)
1682 if ((rc = append_strbuf_str(buff, "wwid rules:\n- blacklist:\n")) < 0)
1684 if ((rc = snprint_blacklist_group(buff, &conf->blist_wwid)) < 0)
1687 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1689 if ((rc = snprint_blacklist_group(buff, &conf->elist_wwid)) < 0)
1692 if ((rc = append_strbuf_str(buff, "device rules:\n- blacklist:\n")) < 0)
1694 if ((rc = snprint_blacklist_devgroup(buff, &conf->blist_device)) < 0)
1697 if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
1699 if ((rc = snprint_blacklist_devgroup(buff, &conf->elist_device)) < 0)
1702 return get_strbuf_len(buff) - initial_len;
1705 static int snprint_blacklist(const struct config *conf, struct strbuf *buff)
1708 struct blentry * ble;
1709 struct blentry_device * bled;
1710 struct keyword *rootkw;
1711 struct keyword *kw, *pkw;
1712 size_t initial_len = get_strbuf_len(buff);
1714 rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1717 if ((rc = append_strbuf_str(buff, "blacklist {\n")) < 0)
1720 vector_foreach_slot (conf->blist_devnode, ble, i) {
1721 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1723 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1726 vector_foreach_slot (conf->blist_wwid, ble, i) {
1727 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1729 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1732 vector_foreach_slot (conf->blist_property, ble, i) {
1733 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1735 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1738 vector_foreach_slot (conf->blist_protocol, ble, i) {
1739 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1741 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
1745 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1747 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1748 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1751 vector_foreach_slot (conf->blist_device, bled, i) {
1752 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1755 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1760 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1762 return get_strbuf_len(buff) - initial_len;
1765 static int snprint_blacklist_except(const struct config *conf,
1766 struct strbuf *buff)
1769 struct blentry * ele;
1770 struct blentry_device * eled;
1771 struct keyword *rootkw;
1772 struct keyword *kw, *pkw;
1773 size_t initial_len = get_strbuf_len(buff);
1775 rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1778 if ((rc = append_strbuf_str(buff, "blacklist_exceptions {\n")) < 0)
1781 vector_foreach_slot (conf->elist_devnode, ele, i) {
1782 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1784 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1787 vector_foreach_slot (conf->elist_wwid, ele, i) {
1788 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1790 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1793 vector_foreach_slot (conf->elist_property, ele, i) {
1794 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1796 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1799 vector_foreach_slot (conf->elist_protocol, ele, i) {
1800 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1802 if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
1806 rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1808 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1809 pkw = find_keyword(conf->keywords, rootkw->sub, "product");
1812 vector_foreach_slot (conf->elist_device, eled, i) {
1813 if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
1816 if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
1821 if ((rc = append_strbuf_str(buff, "}\n")) < 0)
1823 return get_strbuf_len(buff) - initial_len;
1826 int __snprint_config(const struct config *conf, struct strbuf *buff,
1827 const struct _vector *hwtable, const struct _vector *mpvec)
1831 if ((rc = snprint_defaults(conf, buff)) < 0 ||
1832 (rc = snprint_blacklist(conf, buff)) < 0 ||
1833 (rc = snprint_blacklist_except(conf, buff)) < 0 ||
1834 (rc = snprint_hwtable(conf, buff,
1835 hwtable ? hwtable : conf->hwtable)) < 0 ||
1836 (rc = snprint_overrides(conf, buff, conf->overrides)) < 0)
1839 if (VECTOR_SIZE(conf->mptable) > 0 ||
1840 (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
1841 if ((rc = snprint_mptable(conf, buff, mpvec)) < 0)
1847 char *snprint_config(const struct config *conf, int *len,
1848 const struct _vector *hwtable, const struct _vector *mpvec)
1850 STRBUF_ON_STACK(buff);
1852 int rc = __snprint_config(conf, &buff, hwtable, mpvec);
1858 *len = get_strbuf_len(&buff);
1859 reply = steal_strbuf_str(&buff);
1864 int snprint_status(struct strbuf *buff, const struct vectors *vecs)
1867 unsigned int count[PATH_MAX_STATE] = {0};
1868 int monitored_count = 0;
1870 size_t initial_len = get_strbuf_len(buff);
1872 vector_foreach_slot (vecs->pathvec, pp, i) {
1875 if ((rc = append_strbuf_str(buff, "path checker states:\n")) < 0)
1877 for (i = 0; i < PATH_MAX_STATE; i++) {
1880 if ((rc = print_strbuf(buff, "%-20s%u\n",
1881 checker_state_name(i), count[i])) < 0)
1885 vector_foreach_slot(vecs->pathvec, pp, i)
1888 if ((rc = print_strbuf(buff, "\npaths: %d\nbusy: %s\n",
1890 is_uevent_busy()? "True" : "False")) < 0)
1893 return get_strbuf_len(buff) - initial_len;
1896 int snprint_devices(struct config *conf, struct strbuf *buff,
1897 const struct vectors *vecs)
1900 struct udev_enumerate *enm;
1901 struct udev_list_entry *item, *first;
1903 size_t initial_len = get_strbuf_len(buff);
1905 enm = udev_enumerate_new(udev);
1908 udev_enumerate_add_match_subsystem(enm, "block");
1910 if ((r = append_strbuf_str(buff, "available block devices:\n")) < 0)
1912 r = udev_enumerate_scan_devices(enm);
1916 first = udev_enumerate_get_list_entry(enm);
1917 udev_list_entry_foreach(item, first) {
1918 const char *path, *devname, *status;
1919 struct udev_device *u_dev;
1921 path = udev_list_entry_get_name(item);
1924 u_dev = udev_device_new_from_syspath(udev, path);
1927 devname = udev_device_get_sysname(u_dev);
1929 udev_device_unref(u_dev);
1933 pp = find_path_by_dev(vecs->pathvec, devname);
1937 hidden = udev_device_get_sysattr_value(u_dev,
1939 if (hidden && !strcmp(hidden, "1"))
1940 status = "hidden, unmonitored";
1941 else if (is_claimed_by_foreign(u_dev))
1942 status = "foreign, monitored";
1944 r = filter_devnode(conf->blist_devnode,
1945 conf->elist_devnode,
1948 status = "devnode blacklisted, unmonitored";
1950 status = "devnode whitelisted, unmonitored";
1953 status = " devnode whitelisted, monitored";
1955 r = print_strbuf(buff, " %s %s\n", devname, status);
1956 udev_device_unref(u_dev);
1961 udev_enumerate_unref(enm);
1965 return get_strbuf_len(buff) - initial_len;
1969 * stdout printing helpers
1971 static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
1975 STRBUF_ON_STACK(line);
1976 fieldwidth_t *width __attribute__((cleanup(cleanup_ucharp))) = NULL;
1978 if (!VECTOR_SIZE(pathvec)) {
1980 fprintf(stdout, "===== no paths =====\n");
1984 if ((width = alloc_path_layout()) == NULL)
1986 get_path_layout(pathvec, 1, width);
1989 append_strbuf_str(&line, "===== paths list =====\n");
1991 snprint_path_header(&line, fmt, width);
1993 vector_foreach_slot (pathvec, pp, i)
1994 snprint_path(&line, fmt, pp, width);
1996 printf("%s", get_strbuf_str(&line));
1999 void print_all_paths(vector pathvec, int banner)
2001 print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);