libmultipath/checkers: cleanup class/instance model
[multipath-tools/.git] / libmultipath / print.c
index 2d159ed..fc40b0f 100644 (file)
 #include "vector.h"
 #include "structs.h"
 #include "structs_vec.h"
-#include "print.h"
 #include "dmparser.h"
 #include "config.h"
 #include "configure.h"
 #include "pgpolicies.h"
+#include "print.h"
 #include "defaults.h"
 #include "parser.h"
 #include "blacklist.h"
 #include "devmapper.h"
 #include "uevent.h"
 #include "debug.h"
+#include "discovery.h"
 
-#define MAX(x,y) (x > y) ? x : y
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MIN(x,y) (((x) > (y)) ? (y) : (x))
 #define TAIL     (line + len - 1 - c)
 #define NOPAD    s = c
 #define PAD(x) \
@@ -39,9 +41,18 @@ do { \
        s = c; \
 } while (0)
 
-#define ENDLINE \
-               if (c > line) \
-                       line[c - line - 1] = '\n'
+static char *
+__endline(char *line, size_t len, char *c)
+{
+       if (c > line) {
+               if (c >= line + len)
+                       c = line + len - 1;
+               *(c - 1) = '\n';
+               *c = '\0';
+       }
+       return c;
+}
+
 #define PRINT(var, size, format, args...) \
 do { \
        fwd = snprintf(var, size, format, ##args); \
@@ -73,7 +84,6 @@ static int
 snprint_size (char * buff, size_t len, unsigned long long size)
 {
        float s = (float)(size >> 1); /* start with KB */
-       char fmt[6] = {};
        char units[] = {'K','M','G','T','P'};
        char *u = units;
 
@@ -81,19 +91,15 @@ snprint_size (char * buff, size_t len, unsigned long long size)
                s = s / 1024;
                u++;
        }
-       if (s < 10)
-               snprintf(fmt, 6, "%%.1f%c", *u);
-       else
-               snprintf(fmt, 6, "%%.0f%c", *u);
 
-       return snprintf(buff, len, fmt, s);
+       return snprintf(buff, len, "%.*f%c", s < 10, s, *u);
 }
 
 /*
  * multipath info printing functions
  */
 static int
-snprint_name (char * buff, size_t len, struct multipath * mpp)
+snprint_name (char * buff, size_t len, const struct multipath * mpp)
 {
        if (mpp->alias)
                return snprintf(buff, len, "%s", mpp->alias);
@@ -102,7 +108,7 @@ snprint_name (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
+snprint_sysfs (char * buff, size_t len, const struct multipath * mpp)
 {
        if (mpp->dmi)
                return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
@@ -111,7 +117,7 @@ snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_ro (char * buff, size_t len, struct multipath * mpp)
+snprint_ro (char * buff, size_t len, const struct multipath * mpp)
 {
        if (!mpp->dmi)
                return snprintf(buff, len, "undef");
@@ -150,7 +156,7 @@ out:
 }
 
 static int
-snprint_failback (char * buff, size_t len, struct multipath * mpp)
+snprint_failback (char * buff, size_t len, const struct multipath * mpp)
 {
        if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
                return snprintf(buff, len, "immediate");
@@ -165,7 +171,7 @@ snprint_failback (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_queueing (char * buff, size_t len, struct multipath * mpp)
+snprint_queueing (char * buff, size_t len, const struct multipath * mpp)
 {
        if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
                return snprintf(buff, len, "off");
@@ -187,13 +193,13 @@ snprint_queueing (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
+snprint_nb_paths (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_int(buff, len, mpp->nr_active);
 }
 
 static int
-snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
+snprint_dm_map_state (char * buff, size_t len, const struct multipath * mpp)
 {
        if (mpp->dmi && mpp->dmi->suspended)
                return snprintf(buff, len, "suspend");
@@ -202,69 +208,73 @@ snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_size (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_size(buff, len, mpp->size);
 }
 
 static int
-snprint_features (char * buff, size_t len, struct multipath * mpp)
+snprint_features (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_str(buff, len, mpp->features);
 }
 
 static int
-snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
+snprint_hwhandler (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_str(buff, len, mpp->hwhandler);
 }
 
 static int
-snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
+snprint_path_faults (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_uint(buff, len, mpp->stat_path_failures);
 }
 
 static int
-snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
+snprint_switch_grp (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_uint(buff, len, mpp->stat_switchgroup);
 }
 
 static int
-snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
+snprint_map_loads (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_uint(buff, len, mpp->stat_map_loads);
 }
 
 static int
-snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
+snprint_total_q_time (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_uint(buff, len, mpp->stat_total_queueing_time);
 }
 
 static int
-snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
+snprint_q_timeouts (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
 }
 
 static int
-snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
+snprint_map_failures (char * buff, size_t len, const struct multipath * mpp)
+{
+       return snprint_uint(buff, len, mpp->stat_map_failures);
+}
+
+static int
+snprint_multipath_uuid (char * buff, size_t len, const struct multipath * mpp)
 {
        return snprint_str(buff, len, mpp->wwid);
 }
 
 static int
-snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp)
 {
        struct pathgroup * pgp;
        struct path * pp;
        int i, j;
 
        vector_foreach_slot(mpp->pg, pgp, i) {
-               if (!pgp)
-                       continue;
                vector_foreach_slot(pgp->paths, pp, j) {
                        if (strlen(pp->vendor_id) && strlen(pp->product_id))
                                return snprintf(buff, len, "%s,%s",
@@ -276,15 +286,13 @@ snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
 
 
 static int
-snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
 {
        struct pathgroup * pgp;
        struct path * pp;
        int i, j;
 
        vector_foreach_slot(mpp->pg, pgp, i) {
-               if (!pgp)
-                       continue;
                vector_foreach_slot(pgp->paths, pp, j) {
                        if (strlen(pp->vendor_id))
                                return snprintf(buff, len, "%s", pp->vendor_id);
@@ -294,15 +302,13 @@ snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
 {
        struct pathgroup * pgp;
        struct path * pp;
        int i, j;
 
        vector_foreach_slot(mpp->pg, pgp, i) {
-               if (!pgp)
-                       continue;
                vector_foreach_slot(pgp->paths, pp, j) {
                        if (strlen(pp->product_id))
                                return snprintf(buff, len, "%s", pp->product_id);
@@ -312,15 +318,13 @@ snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
 {
        struct pathgroup * pgp;
        struct path * pp;
        int i, j;
 
        vector_foreach_slot(mpp->pg, pgp, i) {
-               if (!pgp)
-                       continue;
                vector_foreach_slot(pgp->paths, pp, j) {
                        if (strlen(pp->rev))
                                return snprintf(buff, len, "%s", pp->rev);
@@ -330,7 +334,13 @@ snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
-snprint_action (char * buff, size_t len, struct multipath * mpp)
+snprint_multipath_foreign (char * buff, size_t len, const struct multipath * pp)
+{
+       return snprintf(buff, len, "%s", "--");
+}
+
+static int
+snprint_action (char * buff, size_t len, const struct multipath * mpp)
 {
        switch (mpp->action) {
        case ACT_REJECT:
@@ -352,13 +362,13 @@ snprint_action (char * buff, size_t len, struct multipath * mpp)
  * path info printing functions
  */
 static int
-snprint_path_uuid (char * buff, size_t len, struct path * pp)
+snprint_path_uuid (char * buff, size_t len, const struct path * pp)
 {
        return snprint_str(buff, len, pp->wwid);
 }
 
 static int
-snprint_hcil (char * buff, size_t len, struct path * pp)
+snprint_hcil (char * buff, size_t len, const struct path * pp)
 {
        if (!pp || pp->sg_id.host_no < 0)
                return snprintf(buff, len, "#:#:#:#");
@@ -371,7 +381,7 @@ snprint_hcil (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dev (char * buff, size_t len, struct path * pp)
+snprint_dev (char * buff, size_t len, const struct path * pp)
 {
        if (!pp || !strlen(pp->dev))
                return snprintf(buff, len, "-");
@@ -380,7 +390,7 @@ snprint_dev (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dev_t (char * buff, size_t len, struct path * pp)
+snprint_dev_t (char * buff, size_t len, const struct path * pp)
 {
        if (!pp || !strlen(pp->dev))
                return snprintf(buff, len, "#:#");
@@ -389,9 +399,9 @@ snprint_dev_t (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_offline (char * buff, size_t len, struct path * pp)
+snprint_offline (char * buff, size_t len, const struct path * pp)
 {
-       if (!pp)
+       if (!pp || !pp->mpp)
                return snprintf(buff, len, "unknown");
        else if (pp->offline)
                return snprintf(buff, len, "offline");
@@ -400,9 +410,9 @@ snprint_offline (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_chk_state (char * buff, size_t len, struct path * pp)
+snprint_chk_state (char * buff, size_t len, const struct path * pp)
 {
-       if (!pp)
+       if (!pp || !pp->mpp)
                return snprintf(buff, len, "undef");
 
        switch (pp->state) {
@@ -426,7 +436,7 @@ snprint_chk_state (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_dm_path_state (char * buff, size_t len, struct path * pp)
+snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
 {
        if (!pp)
                return snprintf(buff, len, "undef");
@@ -442,14 +452,14 @@ snprint_dm_path_state (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_vpr (char * buff, size_t len, struct path * pp)
+snprint_vpr (char * buff, size_t len, const struct path * pp)
 {
        return snprintf(buff, len, "%s,%s",
                        pp->vendor_id, pp->product_id);
 }
 
 static int
-snprint_next_check (char * buff, size_t len, struct path * pp)
+snprint_next_check (char * buff, size_t len, const struct path * pp)
 {
        if (!pp || !pp->mpp)
                return snprintf(buff, len, "orphan");
@@ -458,32 +468,27 @@ snprint_next_check (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_pri (char * buff, size_t len, struct path * pp)
+snprint_pri (char * buff, size_t len, const struct path * pp)
 {
        return snprint_int(buff, len, pp ? pp->priority : -1);
 }
 
 static int
-snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
 {
-       return snprint_str(buff, len, pgp->selector);
+       const char *s = pgp->mpp->selector;
+
+       return snprint_str(buff, len, s ? s : "");
 }
 
 static int
-snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
 {
-       /*
-        * path group priority is not updated for every path prio change,
-        * but only on switch group code path.
-        *
-        * Printing is another reason to update.
-        */
-       path_group_prio_update(pgp);
        return snprint_int(buff, len, pgp->priority);
 }
 
 static int
-snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
+snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
 {
        switch (pgp->status) {
        case PGSTATE_ENABLED:
@@ -498,19 +503,19 @@ snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
 }
 
 static int
-snprint_path_size (char * buff, size_t len, struct path * pp)
+snprint_path_size (char * buff, size_t len, const struct path * pp)
 {
        return snprint_size(buff, len, pp->size);
 }
 
-static int
-snprint_path_serial (char * buff, size_t len, struct path * pp)
+int
+snprint_path_serial (char * buff, size_t len, const struct path * pp)
 {
        return snprint_str(buff, len, pp->serial);
 }
 
 static int
-snprint_path_mpp (char * buff, size_t len, struct path * pp)
+snprint_path_mpp (char * buff, size_t len, const struct path * pp)
 {
        if (!pp->mpp)
                return snprintf(buff, len, "[orphan]");
@@ -520,7 +525,7 @@ snprint_path_mpp (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
+snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
 {
        struct udev_device *host_dev = NULL;
        char host_id[32];
@@ -530,7 +535,7 @@ snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
        if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
                return snprintf(buff, len, "[undef]");
        sprintf(host_id, "host%d", pp->sg_id.host_no);
-       host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host",
+       host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
                                                          host_id);
        if (!host_dev) {
                condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
@@ -547,19 +552,19 @@ out:
 }
 
 int
-snprint_host_wwnn (char * buff, size_t len, struct path * pp)
+snprint_host_wwnn (char * buff, size_t len, const struct path * pp)
 {
        return snprint_host_attr(buff, len, pp, "node_name");
 }
 
 int
-snprint_host_wwpn (char * buff, size_t len, struct path * pp)
+snprint_host_wwpn (char * buff, size_t len, const struct path * pp)
 {
        return snprint_host_attr(buff, len, pp, "port_name");
 }
 
 int
-snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
+snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
 {
        struct udev_device *rport_dev = NULL;
        char rport_id[32];
@@ -570,7 +575,7 @@ snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
                return snprintf(buff, len, "[undef]");
        sprintf(rport_id, "rport-%d:%d-%d",
                pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
-       rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+       rport_dev = udev_device_new_from_subsystem_sysname(udev,
                                "fc_remote_ports", rport_id);
        if (!rport_dev) {
                condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
@@ -589,7 +594,7 @@ out:
 
 
 int
-snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
+snprint_tgt_wwnn (char * buff, size_t len, const struct path * pp)
 {
        if (pp->tgt_node_name[0] == '\0')
                return snprintf(buff, len, "[undef]");
@@ -597,7 +602,7 @@ snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_host_adapter (char * buff, size_t len, struct path * pp)
+snprint_host_adapter (char * buff, size_t len, const struct path * pp)
 {
        char adapter[SLOT_NAME_SIZE];
 
@@ -607,10 +612,64 @@ snprint_host_adapter (char * buff, size_t len, struct path * pp)
 }
 
 static int
-snprint_path_checker (char * buff, size_t len, struct path * pp)
+snprint_path_checker (char * buff, size_t len, const struct path * pp)
 {
-       struct checker * c = &pp->checker;
-       return snprint_str(buff, len, c->name);
+       const struct checker * c = &pp->checker;
+       return snprint_str(buff, len, checker_name(c));
+}
+
+static int
+snprint_path_foreign (char * buff, size_t len, const struct path * pp)
+{
+       return snprintf(buff, len, "%s", "--");
+}
+
+static int
+snprint_path_failures(char * buff, size_t len, const struct path * pp)
+{
+       return snprint_int(buff, len, pp->failcount);
+}
+
+/* if you add a protocol string bigger than "scsi:unspec" you must
+ * also change PROTOCOL_BUF_SIZE */
+int
+snprint_path_protocol(char * buff, size_t len, const struct path * pp)
+{
+       switch (pp->bus) {
+       case SYSFS_BUS_SCSI:
+               switch (pp->sg_id.proto_id) {
+               case SCSI_PROTOCOL_FCP:
+                       return snprintf(buff, len, "scsi:fcp");
+               case SCSI_PROTOCOL_SPI:
+                       return snprintf(buff, len, "scsi:spi");
+               case SCSI_PROTOCOL_SSA:
+                       return snprintf(buff, len, "scsi:ssa");
+               case SCSI_PROTOCOL_SBP:
+                       return snprintf(buff, len, "scsi:sbp");
+               case SCSI_PROTOCOL_SRP:
+                       return snprintf(buff, len, "scsi:srp");
+               case SCSI_PROTOCOL_ISCSI:
+                       return snprintf(buff, len, "scsi:iscsi");
+               case SCSI_PROTOCOL_SAS:
+                       return snprintf(buff, len, "scsi:sas");
+               case SCSI_PROTOCOL_ADT:
+                       return snprintf(buff, len, "scsi:adt");
+               case SCSI_PROTOCOL_ATA:
+                       return snprintf(buff, len, "scsi:ata");
+               case SCSI_PROTOCOL_UNSPEC:
+               default:
+                       return snprintf(buff, len, "scsi:unspec");
+               }
+       case SYSFS_BUS_CCW:
+               return snprintf(buff, len, "ccw");
+       case SYSFS_BUS_CCISS:
+               return snprintf(buff, len, "cciss");
+       case SYSFS_BUS_NVME:
+               return snprintf(buff, len, "nvme");
+       case SYSFS_BUS_UNDEF:
+       default:
+               return snprintf(buff, len, "undef");
+       }
 }
 
 struct multipath_data mpd[] = {
@@ -624,6 +683,7 @@ struct multipath_data mpd[] = {
        {'t', "dm-st",         0, snprint_dm_map_state},
        {'S', "size",          0, snprint_multipath_size},
        {'f', "features",      0, snprint_features},
+       {'x', "failures",      0, snprint_map_failures},
        {'h', "hwhandler",     0, snprint_hwhandler},
        {'A', "action",        0, snprint_action},
        {'0', "path_faults",   0, snprint_path_faults},
@@ -635,6 +695,7 @@ struct multipath_data mpd[] = {
        {'v', "vend",          0, snprint_multipath_vend},
        {'p', "prod",          0, snprint_multipath_prod},
        {'e', "rev",           0, snprint_multipath_rev},
+       {'G', "foreign",       0, snprint_multipath_foreign},
        {0, NULL, 0 , NULL}
 };
 
@@ -658,6 +719,9 @@ struct path_data pd[] = {
        {'R', "host WWPN",     0, snprint_host_wwpn},
        {'r', "target WWPN",   0, snprint_tgt_wwpn},
        {'a', "host adapter",  0, snprint_host_adapter},
+       {'G', "foreign",       0, snprint_path_foreign},
+       {'0', "failures",      0, snprint_path_failures},
+       {'P', "protocol",      0, snprint_path_protocol},
        {0, NULL, 0 , NULL}
 };
 
@@ -689,20 +753,48 @@ snprint_wildcards (char * buff, int len)
 }
 
 void
-get_path_layout (vector pathvec, int header)
+get_path_layout(vector pathvec, int header)
+{
+       vector gpvec = vector_convert(NULL, pathvec, struct path,
+                                     dm_path_to_gen);
+       _get_path_layout(gpvec,
+                        header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+       vector_free(gpvec);
+}
+
+static void
+reset_width(int *width, enum layout_reset reset, const char *header)
+{
+       switch (reset) {
+       case LAYOUT_RESET_HEADER:
+               *width = strlen(header);
+               break;
+       case LAYOUT_RESET_ZERO:
+               *width = 0;
+               break;
+       default:
+               /* don't reset */
+               break;
+       }
+}
+
+void
+_get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
 {
        int i, j;
        char buff[MAX_FIELD_LEN];
-       struct path * pp;
+       const struct gen_path *gp;
 
        for (j = 0; pd[j].header; j++) {
-               if (header)
-                       pd[j].width = strlen(pd[j].header);
-               else
-                       pd[j].width = 0;
 
-               vector_foreach_slot (pathvec, pp, i) {
-                       pd[j].snprint(buff, MAX_FIELD_LEN, pp);
+               reset_width(&pd[j].width, reset, pd[j].header);
+
+               if (gpvec == NULL)
+                       continue;
+
+               vector_foreach_slot (gpvec, gp, i) {
+                       gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
+                                        pd[j].wildcard);
                        pd[j].width = MAX(pd[j].width, strlen(buff));
                }
        }
@@ -718,22 +810,35 @@ reset_multipath_layout (void)
 }
 
 void
-get_multipath_layout (vector mpvec, int header)
+get_multipath_layout (vector mpvec, int header) {
+       vector gmvec = vector_convert(NULL, mpvec, struct multipath,
+                                     dm_multipath_to_gen);
+       _get_multipath_layout(gmvec,
+                        header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
+       vector_free(gmvec);
+}
+
+void
+_get_multipath_layout (const struct _vector *gmvec,
+                           enum layout_reset reset)
 {
        int i, j;
        char buff[MAX_FIELD_LEN];
-       struct multipath * mpp;
+       const struct gen_multipath * gm;
 
        for (j = 0; mpd[j].header; j++) {
-               if (header)
-                       mpd[j].width = strlen(mpd[j].header);
-               else
-                       mpd[j].width = 0;
 
-               vector_foreach_slot (mpvec, mpp, i) {
-                       mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
+               reset_width(&mpd[j].width, reset, mpd[j].header);
+
+               if (gmvec == NULL)
+                       continue;
+
+               vector_foreach_slot (gmvec, gm, i) {
+                       gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
+                                        mpd[j].wildcard);
                        mpd[j].width = MAX(mpd[j].width, strlen(buff));
                }
+               condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
        }
 }
 
@@ -749,6 +854,17 @@ mpd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_multipath_attr(const struct gen_multipath* gm,
+                          char *buf, int len, char wildcard)
+{
+       const struct multipath *mpp = gen_multipath_to_dm(gm);
+       struct multipath_data *mpd = mpd_lookup(wildcard);
+
+       if (mpd == NULL)
+               return 0;
+       return mpd->snprint(buf, len, mpp);
+}
+
 static struct path_data *
 pd_lookup(char wildcard)
 {
@@ -761,6 +877,17 @@ pd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_path_attr(const struct gen_path* gp,
+                     char *buf, int len, char wildcard)
+{
+       const struct path *pp = gen_path_to_dm(gp);
+       struct path_data *pd = pd_lookup(wildcard);
+
+       if (pd == NULL)
+               return 0;
+       return pd->snprint(buf, len, pp);
+}
+
 static struct pathgroup_data *
 pgd_lookup(char wildcard)
 {
@@ -773,19 +900,28 @@ pgd_lookup(char wildcard)
        return NULL;
 }
 
+int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
+                          char *buf, int len, char wildcard)
+{
+       const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
+       struct pathgroup_data *pdg = pgd_lookup(wildcard);
+
+       if (pdg == NULL)
+               return 0;
+       return pdg->snprint(buf, len, pg);
+}
+
 int
-snprint_multipath_header (char * line, int len, char * format)
+snprint_multipath_header (char * line, int len, const char * format)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
-       char * f = format; /* format string cursor */
+       const char * f = format; /* format string cursor */
        int fwd;
        struct multipath_data * data;
 
-       memset(line, 0, len);
-
        do {
-               if (!TAIL)
+               if (TAIL <= 0)
                        break;
 
                if (*f != '%') {
@@ -802,25 +938,23 @@ snprint_multipath_header (char * line, int len, char * format)
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
 int
-snprint_multipath (char * line, int len, char * format,
-            struct multipath * mpp, int pad)
+_snprint_multipath (const struct gen_multipath * gmp,
+                   char * line, int len, const char * format, int pad)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
-       char * f = format; /* format string cursor */
+       const char * f = format; /* format string cursor */
        int fwd;
        struct multipath_data * data;
        char buff[MAX_FIELD_LEN] = {};
 
-       memset(line, 0, len);
-
        do {
-               if (!TAIL)
+               if (TAIL <= 0)
                        break;
 
                if (*f != '%') {
@@ -833,30 +967,28 @@ snprint_multipath (char * line, int len, char * format,
                if (!(data = mpd_lookup(*f)))
                        continue;
 
-               data->snprint(buff, MAX_FIELD_LEN, mpp);
+               gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
                PRINT(c, TAIL, "%s", buff);
                if (pad)
                        PAD(data->width);
                buff[0] = '\0';
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
 int
-snprint_path_header (char * line, int len, char * format)
+snprint_path_header (char * line, int len, const char * format)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
-       char * f = format; /* format string cursor */
+       const char * f = format; /* format string cursor */
        int fwd;
        struct path_data * data;
 
-       memset(line, 0, len);
-
        do {
-               if (!TAIL)
+               if (TAIL <= 0)
                        break;
 
                if (*f != '%') {
@@ -873,25 +1005,23 @@ snprint_path_header (char * line, int len, char * format)
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
 int
-snprint_path (char * line, int len, char * format,
-            struct path * pp, int pad)
+_snprint_path (const struct gen_path * gp, char * line, int len,
+              const char * format, int pad)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
-       char * f = format; /* format string cursor */
+       const char * f = format; /* format string cursor */
        int fwd;
        struct path_data * data;
        char buff[MAX_FIELD_LEN];
 
-       memset(line, 0, len);
-
        do {
-               if (!TAIL)
+               if (TAIL <= 0)
                        break;
 
                if (*f != '%') {
@@ -904,19 +1034,19 @@ snprint_path (char * line, int len, char * format,
                if (!(data = pd_lookup(*f)))
                        continue;
 
-               data->snprint(buff, MAX_FIELD_LEN, pp);
+               gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
                PRINT(c, TAIL, "%s", buff);
                if (pad)
                        PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
 
 int
-snprint_pathgroup (char * line, int len, char * format,
-                  struct pathgroup * pgp)
+_snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
+                   char * format)
 {
        char * c = line;   /* line cursor */
        char * s = line;   /* for padding */
@@ -925,10 +1055,8 @@ snprint_pathgroup (char * line, int len, char * format,
        struct pathgroup_data * data;
        char buff[MAX_FIELD_LEN];
 
-       memset(line, 0, len);
-
        do {
-               if (!TAIL)
+               if (TAIL <= 0)
                        break;
 
                if (*f != '%') {
@@ -941,17 +1069,18 @@ snprint_pathgroup (char * line, int len, char * format,
                if (!(data = pgd_lookup(*f)))
                        continue;
 
-               data->snprint(buff, MAX_FIELD_LEN, pgp);
+               ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
                PRINT(c, TAIL, "%s", buff);
                PAD(data->width);
        } while (*f++);
 
-       ENDLINE;
+       __endline(line, len, c);
        return (c - line);
 }
+#define snprint_pathgroup(line, len, fmt, pgp) \
+       _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
 
-extern void
-print_multipath_topology (struct multipath * mpp, int verbosity)
+void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
 {
        int resize;
        char *buff = NULL;
@@ -968,7 +1097,7 @@ print_multipath_topology (struct multipath * mpp, int verbosity)
                        return;
                }
 
-               len = snprint_multipath_topology(buff, maxlen, mpp, verbosity);
+               len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
                resize = (len == maxlen - 1);
 
                if (resize) {
@@ -981,13 +1110,30 @@ print_multipath_topology (struct multipath * mpp, int verbosity)
        FREE(buff);
 }
 
-extern int
-snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
-                           int verbosity)
+int
+snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
+                       int verbosity)
+{
+       int n;
+       const struct multipath *mpp = gen_multipath_to_dm(gmp);
+       bool need_action = (verbosity > 1 &&
+                           mpp->action != ACT_NOTHING &&
+                           mpp->action != ACT_UNDEF &&
+                           mpp->action != ACT_IMPOSSIBLE);
+       bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
+
+       n = snprintf(style, len, "%s%s%s%s",
+                    need_action ? "%A: " : "", "%n",
+                    need_wwid ? " (%w)" : "", " %d %s");
+       return MIN(n, len - 1);
+}
+
+int _snprint_multipath_topology(const struct gen_multipath *gmp,
+                               char *buff, int len, int verbosity)
 {
        int j, i, fwd = 0;
-       struct path * pp = NULL;
-       struct pathgroup * pgp = NULL;
+       const struct _vector *pgvec;
+       const struct gen_pathgroup *gpg;
        char style[64];
        char * c = style;
        char fmt[64];
@@ -999,64 +1145,74 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
        reset_multipath_layout();
 
        if (verbosity == 1)
-               return snprint_multipath(buff, len, "%n", mpp, 1);
+               return _snprint_multipath(gmp, buff, len, "%n", 1);
 
        if(isatty(1))
                c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
 
-       if (verbosity > 1 &&
-           mpp->action != ACT_NOTHING &&
-           mpp->action != ACT_UNDEF)
-                       c += sprintf(c, "%%A: ");
-
-       c += sprintf(c, "%%n");
-
-       if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
-               c += sprintf(c, " (%%w)");
-
-       c += sprintf(c, " %%d %%s");
+       c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
+                            verbosity);
        if(isatty(1))
                c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
 
-       fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp, 1);
-       if (fwd > len)
+       fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
+       if (fwd >= len)
                return len;
-       fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp,
-                                1);
-       if (fwd > len)
+       fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
+                                 PRINT_MAP_PROPS, 1);
+       if (fwd >= len)
                return len;
 
-       if (!mpp->pg)
+       pgvec = gmp->ops->get_pathgroups(gmp);
+       if (pgvec == NULL)
                return fwd;
 
-       vector_foreach_slot (mpp->pg, pgp, j) {
+       vector_foreach_slot (pgvec, gpg, j) {
+               const struct _vector *pathvec;
+               struct gen_path *gp;
+
                f=fmt;
-               pgp->selector = mpp->selector; /* hack */
-               if (j + 1 < VECTOR_SIZE(mpp->pg)) {
+
+               if (j + 1 < VECTOR_SIZE(pgvec)) {
                        strcpy(f, "|-+- " PRINT_PG_INDENT);
                } else
                        strcpy(f, "`-+- " PRINT_PG_INDENT);
-               fwd += snprint_pathgroup(buff + fwd, len - fwd, fmt, pgp);
-               if (fwd > len)
-                       return len;
+               fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
+
+               if (fwd >= len) {
+                       fwd = len;
+                       break;
+               }
 
-               vector_foreach_slot (pgp->paths, pp, i) {
+               pathvec = gpg->ops->get_paths(gpg);
+               if (pathvec == NULL)
+                       continue;
+
+               vector_foreach_slot (pathvec, gp, i) {
                        f=fmt;
                        if (*f != '|')
                                *f=' ';
                        f++;
-                       if (i + 1 < VECTOR_SIZE(pgp->paths))
+                       if (i + 1 < VECTOR_SIZE(pathvec))
                                strcpy(f, " |- " PRINT_PATH_INDENT);
                        else
                                strcpy(f, " `- " PRINT_PATH_INDENT);
-                       fwd += snprint_path(buff + fwd, len - fwd, fmt, pp, 1);
-                       if (fwd > len)
-                               return len;
+                       fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
+                       if (fwd >= len) {
+                               fwd = len;
+                               break;
+                       }
                }
+               gpg->ops->rel_paths(gpg, pathvec);
+
+               if (fwd == len)
+                       break;
        }
+       gmp->ops->rel_pathgroups(gmp, pgvec);
        return fwd;
 }
 
+
 static int
 snprint_json (char * buff, int len, int indent, char *json_str)
 {
@@ -1064,7 +1220,7 @@ snprint_json (char * buff, int len, int indent, char *json_str)
 
        for (i = 0; i < indent; i++) {
                fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
        }
 
@@ -1078,7 +1234,7 @@ snprint_json_header (char * buff, int len)
        int fwd = 0;
 
        fwd +=  snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
-       if (fwd > len)
+       if (fwd >= len)
                return fwd;
 
        fwd +=  snprintf(buff + fwd, len  - fwd, PRINT_JSON_START_VERSION,
@@ -1093,7 +1249,7 @@ snprint_json_elem_footer (char * buff, int len, int indent, int last)
 
        for (i = 0; i < indent; i++) {
                fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
        }
 
@@ -1106,57 +1262,56 @@ snprint_json_elem_footer (char * buff, int len, int indent, int last)
 
 static int
 snprint_multipath_fields_json (char * buff, int len,
-               struct multipath * mpp, int last)
+               const struct multipath * mpp, int last)
 {
        int i, j, fwd = 0;
        struct path *pp;
        struct pathgroup *pgp;
 
        fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
-       if (fwd > len)
+       if (fwd >= len)
                return fwd;
 
        fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
-       if (fwd > len)
+       if (fwd >= len)
                return fwd;
 
        vector_foreach_slot (mpp->pg, pgp, i) {
 
-               pgp->selector = mpp->selector;
                fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
 
                fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
 
                fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
 
                vector_foreach_slot (pgp->paths, pp, j) {
                        fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
-                       if (fwd > len)
+                       if (fwd >= len)
                                return fwd;
 
                        fwd += snprint_json_elem_footer(buff + fwd,
                                        len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
-                       if (fwd > len)
+                       if (fwd >= len)
                                return fwd;
                }
                fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
 
                fwd +=  snprint_json_elem_footer(buff + fwd,
                                len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
-               if (fwd > len)
+               if (fwd >= len)
                        return fwd;
        }
 
        fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
-       if (fwd > len)
+       if (fwd >= len)
                return fwd;
 
        fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
@@ -1165,228 +1320,275 @@ snprint_multipath_fields_json (char * buff, int len,
 
 int
 snprint_multipath_map_json (char * buff, int len,
-               struct multipath * mpp, int last){
+               const struct multipath * mpp, int last){
        int fwd = 0;
 
        fwd +=  snprint_json_header(buff, len);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
 int
-snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)
+snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
 {
        int i, fwd = 0;
        struct multipath * mpp;
 
        fwd +=  snprint_json_header(buff, len);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        vector_foreach_slot(vecs->mpvec, mpp, i) {
                fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
                                mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
 
        fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
 static int
-snprint_hwentry (char * buff, int len, struct hwentry * hwe)
+snprint_hwentry (const struct config *conf,
+                char * buff, int len, const struct hwentry * hwe)
 {
        int i;
        int fwd = 0;
        struct keyword * kw;
        struct keyword * rootkw;
 
-       rootkw = find_keyword(NULL, "devices");
+       rootkw = find_keyword(conf->keywords, NULL, "devices");
 
        if (!rootkw || !rootkw->sub)
                return 0;
 
-       rootkw = find_keyword(rootkw->sub, "device");
+       rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
 
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        iterate_sub_keywords(rootkw, kw, i) {
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                kw, hwe);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_hwtable (char * buff, int len, vector hwtable)
+static int snprint_hwtable(const struct config *conf,
+                          char *buff, int len,
+                          const struct _vector *hwtable)
 {
        int fwd = 0;
        int i;
        struct hwentry * hwe;
        struct keyword * rootkw;
 
-       rootkw = find_keyword(NULL, "devices");
+       rootkw = find_keyword(conf->keywords, NULL, "devices");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        vector_foreach_slot (hwtable, hwe, i) {
-               fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
-               if (fwd > len)
+               fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
 static int
-snprint_mpentry (char * buff, int len, struct mpentry * mpe)
+snprint_mpentry (const struct config *conf, char * buff, int len,
+                const struct mpentry * mpe, const struct _vector *mpvec)
 {
        int i;
        int fwd = 0;
        struct keyword * kw;
        struct keyword * rootkw;
+       struct multipath *mpp = NULL;
+
+       if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
+               return 0;
 
-       rootkw = find_keyword(NULL, "multipath");
+       rootkw = find_keyword(conf->keywords, NULL, "multipath");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        iterate_sub_keywords(rootkw, kw, i) {
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                kw, mpe);
-               if (fwd > len)
+               if (fwd >= len)
+                       return len;
+       }
+       /*
+        * This mpp doesn't have alias defined. Add the alias in a comment.
+        */
+       if (mpp != NULL && strcmp(mpp->alias, mpp->wwid)) {
+               fwd += snprintf(buff + fwd, len - fwd, "\t\t# alias \"%s\"\n",
+                               mpp->alias);
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_mptable (char * buff, int len, vector mptable)
+static int snprint_mptable(const struct config *conf,
+                          char *buff, int len, const struct _vector *mpvec)
 {
        int fwd = 0;
        int i;
        struct mpentry * mpe;
        struct keyword * rootkw;
 
-       rootkw = find_keyword(NULL, "multipaths");
+       rootkw = find_keyword(conf->keywords, NULL, "multipaths");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
-       vector_foreach_slot (mptable, mpe, i) {
-               fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
-               if (fwd > len)
+       vector_foreach_slot (conf->mptable, mpe, i) {
+               fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe, mpvec);
+               if (fwd >= len)
                        return len;
        }
+       if (mpvec != NULL) {
+               struct multipath *mpp;
+
+               vector_foreach_slot(mpvec, mpp, i) {
+                       if (find_mpe(conf->mptable, mpp->wwid) != NULL)
+                               continue;
+
+                       fwd += snprintf(buff + fwd, len - fwd,
+                                       "\tmultipath {\n");
+                       if (fwd >= len)
+                               return len;
+                       fwd += snprintf(buff + fwd, len - fwd,
+                                       "\t\twwid \"%s\"\n", mpp->wwid);
+                       if (fwd >= len)
+                               return len;
+                       /*
+                        * This mpp doesn't have alias defined in
+                        * multipath.conf - otherwise find_mpe would have
+                        * found it. Add the alias in a comment.
+                        */
+                       if (strcmp(mpp->alias, mpp->wwid)) {
+                               fwd += snprintf(buff + fwd, len - fwd,
+                                               "\t\t# alias \"%s\"\n",
+                                               mpp->alias);
+                               if (fwd >= len)
+                                       return len;
+                       }
+                       fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+                       if (fwd >= len)
+                               return len;
+               }
+       }
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_overrides (char * buff, int len, struct hwentry *overrides)
+static int snprint_overrides(const struct config *conf, char * buff, int len,
+                            const struct hwentry *overrides)
 {
        int fwd = 0;
        int i;
        struct keyword *rootkw;
        struct keyword *kw;
 
-       rootkw = find_keyword(NULL, "overrides");
+       rootkw = find_keyword(conf->keywords, NULL, "overrides");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        if (!overrides)
                goto out;
        iterate_sub_keywords(rootkw, kw, i) {
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, NULL);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
 out:
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_defaults (char * buff, int len)
+static int snprint_defaults(const struct config *conf, char *buff, int len)
 {
        int fwd = 0;
        int i;
        struct keyword *rootkw;
        struct keyword *kw;
 
-       rootkw = find_keyword(NULL, "defaults");
+       rootkw = find_keyword(conf->keywords, NULL, "defaults");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        iterate_sub_keywords(rootkw, kw, i) {
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                kw, NULL);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
@@ -1445,8 +1647,7 @@ snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
        return pos;
 }
 
-extern int
-snprint_blacklist_report (char * buff, int len)
+int snprint_blacklist_report(struct config *conf, char *buff, int len)
 {
        int threshold = MAX_LINE_LEN;
        int fwd = 0;
@@ -1477,6 +1678,19 @@ snprint_blacklist_report (char * buff, int len)
        if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
                return len;
 
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n"
+                                              "- blacklist:\n");
+       if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol))
+               return len;
+
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+       if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0)
+               return len;
+
        if ((len - fwd - threshold) <= 0)
                return len;
        fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
@@ -1508,8 +1722,7 @@ snprint_blacklist_report (char * buff, int len)
        return fwd;
 }
 
-extern int
-snprint_blacklist (char * buff, int len)
+static int snprint_blacklist(const struct config *conf, char *buff, int len)
 {
        int i;
        struct blentry * ble;
@@ -1518,75 +1731,84 @@ snprint_blacklist (char * buff, int len)
        struct keyword *rootkw;
        struct keyword *kw;
 
-       rootkw = find_keyword(NULL, "blacklist");
+       rootkw = find_keyword(conf->keywords, NULL, "blacklist");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        vector_foreach_slot (conf->blist_devnode, ble, i) {
-               kw = find_keyword(rootkw->sub, "devnode");
+               kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ble);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        vector_foreach_slot (conf->blist_wwid, ble, i) {
-               kw = find_keyword(rootkw->sub, "wwid");
+               kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ble);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        vector_foreach_slot (conf->blist_property, ble, i) {
-               kw = find_keyword(rootkw->sub, "property");
+               kw = find_keyword(conf->keywords, rootkw->sub, "property");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ble);
+               if (fwd >= len)
+                       return len;
+       }
+       vector_foreach_slot (conf->blist_protocol, ble, i) {
+               kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ble);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
-       rootkw = find_keyword(rootkw->sub, "device");
+       rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
        if (!rootkw)
                return 0;
 
        vector_foreach_slot (conf->blist_device, bled, i) {
                fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
-               kw = find_keyword(rootkw->sub, "vendor");
+               kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                       kw, bled);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
-               kw = find_keyword(rootkw->sub, "product");
+               kw = find_keyword(conf->keywords, rootkw->sub, "product");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                       kw, bled);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
                fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_blacklist_except (char * buff, int len)
+static int snprint_blacklist_except(const struct config *conf,
+                                   char *buff, int len)
 {
        int i;
        struct blentry * ele;
@@ -1595,75 +1817,138 @@ snprint_blacklist_except (char * buff, int len)
        struct keyword *rootkw;
        struct keyword *kw;
 
-       rootkw = find_keyword(NULL, "blacklist_exceptions");
+       rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
        if (!rootkw)
                return 0;
 
        fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
 
        vector_foreach_slot (conf->elist_devnode, ele, i) {
-               kw = find_keyword(rootkw->sub, "devnode");
+               kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ele);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        vector_foreach_slot (conf->elist_wwid, ele, i) {
-               kw = find_keyword(rootkw->sub, "wwid");
+               kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ele);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        vector_foreach_slot (conf->elist_property, ele, i) {
-               kw = find_keyword(rootkw->sub, "property");
+               kw = find_keyword(conf->keywords, rootkw->sub, "property");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ele);
+               if (fwd >= len)
+                       return len;
+       }
+       vector_foreach_slot (conf->elist_protocol, ele, i) {
+               kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
                                       kw, ele);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
-       rootkw = find_keyword(rootkw->sub, "device");
+       rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
        if (!rootkw)
                return 0;
 
        vector_foreach_slot (conf->elist_device, eled, i) {
                fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
-               kw = find_keyword(rootkw->sub, "vendor");
+               kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                       kw, eled);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
-               kw = find_keyword(rootkw->sub, "product");
+               kw = find_keyword(conf->keywords, rootkw->sub, "product");
                if (!kw)
                        return 0;
                fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
                                       kw, eled);
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
                fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
-               if (fwd > len)
+               if (fwd >= len)
                        return len;
        }
        fwd += snprintf(buff + fwd, len - fwd, "}\n");
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_status (char * buff, int len, struct vectors *vecs)
+char *snprint_config(const struct config *conf, int *len,
+                    const struct _vector *hwtable, const struct _vector *mpvec)
+{
+       char *reply;
+       /* built-in config is >20kB already */
+       unsigned int maxlen = 32768;
+
+       for (reply = NULL; maxlen <= UINT_MAX/2; maxlen *= 2) {
+               char *c, *tmp = reply;
+
+               reply = REALLOC(reply, maxlen);
+               if (!reply) {
+                       if (tmp)
+                               free(tmp);
+                       return NULL;
+               }
+
+               c = reply + snprint_defaults(conf, reply, maxlen);
+               if ((c - reply) == maxlen)
+                       continue;
+
+               c += snprint_blacklist(conf, c, reply + maxlen - c);
+               if ((c - reply) == maxlen)
+                       continue;
+
+               c += snprint_blacklist_except(conf, c, reply + maxlen - c);
+               if ((c - reply) == maxlen)
+                       continue;
+
+               c += snprint_hwtable(conf, c, reply + maxlen - c,
+                                    hwtable ? hwtable : conf->hwtable);
+               if ((c - reply) == maxlen)
+                       continue;
+
+               c += snprint_overrides(conf, c, reply + maxlen - c,
+                                      conf->overrides);
+               if ((c - reply) == maxlen)
+                       continue;
+
+               if (VECTOR_SIZE(conf->mptable) > 0 ||
+                   (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
+                       c += snprint_mptable(conf, c, reply + maxlen - c,
+                                            mpvec);
+
+               if ((c - reply) < maxlen) {
+                       if (len)
+                               *len = c - reply;
+                       return reply;
+               }
+       }
+
+       free(reply);
+       return NULL;
+}
+
+int snprint_status(char *buff, int len, const struct vectors *vecs)
 {
        int fwd = 0;
        int i;
@@ -1681,21 +1966,21 @@ snprint_status (char * buff, int len, struct vectors *vecs)
                                checker_state_name(i), count[i]);
        }
 
-        int monitored_count = 0;
+       int monitored_count = 0;
 
-        vector_foreach_slot(vecs->pathvec, pp, i)
-                if (pp->fd != -1)
-                        monitored_count++;
-        fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
+       vector_foreach_slot(vecs->pathvec, pp, i)
+               if (pp->fd >= 0)
+                       monitored_count++;
+       fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
                        monitored_count, is_uevent_busy()? "True" : "False");
 
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_devices (char * buff, int len, struct vectors *vecs)
+int snprint_devices(struct config *conf, char * buff, int len,
+                   const struct vectors *vecs)
 {
        DIR *blkdir;
        struct dirent *blkdev;
@@ -1755,22 +2040,15 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
        }
        closedir(blkdir);
 
-       if (fwd > len)
+       if (fwd >= len)
                return len;
        return fwd;
 }
 
-extern int
-snprint_config (char * buff, int len)
-{
-       return 0;
-}
-
 /*
  * stdout printing helpers
  */
-extern void
-print_path (struct path * pp, char * style)
+void print_path(struct path *pp, char *style)
 {
        char line[MAX_LINE_LEN];
 
@@ -1779,43 +2057,12 @@ print_path (struct path * pp, char * style)
        printf("%s", line);
 }
 
-extern void
-print_multipath (struct multipath * mpp, char * style)
-{
-       char line[MAX_LINE_LEN];
-
-       memset(&line[0], 0, MAX_LINE_LEN);
-       snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp, 1);
-       printf("%s", line);
-}
-
-extern void
-print_pathgroup (struct pathgroup * pgp, char * style)
-{
-       char line[MAX_LINE_LEN];
-
-       memset(&line[0], 0, MAX_LINE_LEN);
-       snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
-       printf("%s", line);
-}
-
-extern void
-print_map (struct multipath * mpp, char * params)
-{
-       if (mpp->size && params)
-               printf("0 %llu %s %s\n",
-                        mpp->size, TGT_MPATH, params);
-       return;
-}
-
-extern void
-print_all_paths (vector pathvec, int banner)
+void print_all_paths(vector pathvec, int banner)
 {
        print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
 }
 
-extern void
-print_all_paths_custo (vector pathvec, int banner, char *fmt)
+void print_all_paths_custo(vector pathvec, int banner, char *fmt)
 {
        int i;
        struct path * pp;
@@ -1837,4 +2084,3 @@ print_all_paths_custo (vector pathvec, int banner, char *fmt)
        vector_foreach_slot (pathvec, pp, i)
                print_path(pp, fmt);
 }
-