9da6a77c196ca5c8ac90e02883cf1e3d02da414e
[multipath-tools/.git] / libmultipath / print.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <string.h>
6 #include <libdevmapper.h>
7 #include <stdarg.h>
8 #include <sys/stat.h>
9 #include <dirent.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <libudev.h>
14
15 #include "checkers.h"
16 #include "vector.h"
17 #include "structs.h"
18 #include "structs_vec.h"
19 #include "dmparser.h"
20 #include "config.h"
21 #include "configure.h"
22 #include "pgpolicies.h"
23 #include "print.h"
24 #include "defaults.h"
25 #include "parser.h"
26 #include "blacklist.h"
27 #include "switchgroup.h"
28 #include "devmapper.h"
29 #include "uevent.h"
30 #include "debug.h"
31 #include "discovery.h"
32
33 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
34 #define MIN(x,y) (((x) > (y)) ? (y) : (x))
35 #define TAIL     (line + len - 1 - c)
36 #define NOPAD    s = c
37 #define PAD(x) \
38 do { \
39         while ((int)(c - s) < (x) && (c < (line + len - 1))) \
40                 *c++ = ' '; \
41         s = c; \
42 } while (0)
43
44 static char *
45 __endline(char *line, size_t len, char *c)
46 {
47         if (c > line) {
48                 if (c >= line + len)
49                         c = line + len - 1;
50                 *(c - 1) = '\n';
51                 *c = '\0';
52         }
53         return c;
54 }
55
56 #define PRINT(var, size, format, args...) \
57 do { \
58         fwd = snprintf(var, size, format, ##args); \
59         c += (fwd >= size) ? size : fwd; \
60 } while (0)
61
62 /*
63  * information printing helpers
64  */
65 static int
66 snprint_str (char * buff, size_t len, const char * str)
67 {
68         return snprintf(buff, len, "%s", str);
69 }
70
71 static int
72 snprint_int (char * buff, size_t len, int val)
73 {
74         return snprintf(buff, len, "%i", val);
75 }
76
77 static int
78 snprint_uint (char * buff, size_t len, unsigned int val)
79 {
80         return snprintf(buff, len, "%u", val);
81 }
82
83 static int
84 snprint_size (char * buff, size_t len, unsigned long long size)
85 {
86         float s = (float)(size >> 1); /* start with KB */
87         char units[] = {'K','M','G','T','P'};
88         char *u = units;
89
90         while (s >= 1024 && *u != 'P') {
91                 s = s / 1024;
92                 u++;
93         }
94
95         return snprintf(buff, len, "%.*f%c", s < 10, s, *u);
96 }
97
98 /*
99  * multipath info printing functions
100  */
101 static int
102 snprint_name (char * buff, size_t len, const struct multipath * mpp)
103 {
104         if (mpp->alias)
105                 return snprintf(buff, len, "%s", mpp->alias);
106         else
107                 return snprintf(buff, len, "%s", mpp->wwid);
108 }
109
110 static int
111 snprint_sysfs (char * buff, size_t len, const struct multipath * mpp)
112 {
113         if (mpp->dmi)
114                 return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
115         else
116                 return snprintf(buff, len, "undef");
117 }
118
119 static int
120 snprint_ro (char * buff, size_t len, const struct multipath * mpp)
121 {
122         if (!mpp->dmi)
123                 return snprintf(buff, len, "undef");
124         if (mpp->dmi->read_only)
125                 return snprintf(buff, len, "ro");
126         else
127                 return snprintf(buff, len, "rw");
128 }
129
130 static int
131 snprint_progress (char * buff, size_t len, int cur, int total)
132 {
133         char * c = buff;
134         char * end = buff + len;
135
136         if (total > 0) {
137                 int i = PROGRESS_LEN * cur / total;
138                 int j = PROGRESS_LEN - i;
139
140                 while (i-- > 0) {
141                         c += snprintf(c, len, "X");
142                         if ((len = (end - c)) <= 1) goto out;
143                 }
144
145                 while (j-- > 0) {
146                         c += snprintf(c, len,  ".");
147                         if ((len = (end - c)) <= 1) goto out;
148                 }
149         }
150
151         c += snprintf(c, len, " %i/%i", cur, total);
152
153 out:
154         buff[c - buff + 1] = '\0';
155         return (c - buff + 1);
156 }
157
158 static int
159 snprint_failback (char * buff, size_t len, const struct multipath * mpp)
160 {
161         if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
162                 return snprintf(buff, len, "immediate");
163         if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
164                 return snprintf(buff, len, "followover");
165
166         if (!mpp->failback_tick)
167                 return snprintf(buff, len, "-");
168         else
169                 return snprint_progress(buff, len, mpp->failback_tick,
170                                         mpp->pgfailback);
171 }
172
173 static int
174 snprint_queueing (char * buff, size_t len, const struct multipath * mpp)
175 {
176         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
177                 return snprintf(buff, len, "off");
178         else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
179                 return snprintf(buff, len, "on");
180         else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
181                 return snprintf(buff, len, "-");
182         else if (mpp->no_path_retry > 0) {
183                 if (mpp->retry_tick > 0)
184                         return snprintf(buff, len, "%i sec",
185                                         mpp->retry_tick);
186                 else if (mpp->retry_tick == 0 && mpp->nr_active > 0)
187                         return snprintf(buff, len, "%i chk",
188                                         mpp->no_path_retry);
189                 else
190                         return snprintf(buff, len, "off");
191         }
192         return 0;
193 }
194
195 static int
196 snprint_nb_paths (char * buff, size_t len, const struct multipath * mpp)
197 {
198         return snprint_int(buff, len, mpp->nr_active);
199 }
200
201 static int
202 snprint_dm_map_state (char * buff, size_t len, const struct multipath * mpp)
203 {
204         if (mpp->dmi && mpp->dmi->suspended)
205                 return snprintf(buff, len, "suspend");
206         else
207                 return snprintf(buff, len, "active");
208 }
209
210 static int
211 snprint_multipath_size (char * buff, size_t len, const struct multipath * mpp)
212 {
213         return snprint_size(buff, len, mpp->size);
214 }
215
216 static int
217 snprint_features (char * buff, size_t len, const struct multipath * mpp)
218 {
219         return snprint_str(buff, len, mpp->features);
220 }
221
222 static int
223 snprint_hwhandler (char * buff, size_t len, const struct multipath * mpp)
224 {
225         return snprint_str(buff, len, mpp->hwhandler);
226 }
227
228 static int
229 snprint_path_faults (char * buff, size_t len, const struct multipath * mpp)
230 {
231         return snprint_uint(buff, len, mpp->stat_path_failures);
232 }
233
234 static int
235 snprint_switch_grp (char * buff, size_t len, const struct multipath * mpp)
236 {
237         return snprint_uint(buff, len, mpp->stat_switchgroup);
238 }
239
240 static int
241 snprint_map_loads (char * buff, size_t len, const struct multipath * mpp)
242 {
243         return snprint_uint(buff, len, mpp->stat_map_loads);
244 }
245
246 static int
247 snprint_total_q_time (char * buff, size_t len, const struct multipath * mpp)
248 {
249         return snprint_uint(buff, len, mpp->stat_total_queueing_time);
250 }
251
252 static int
253 snprint_q_timeouts (char * buff, size_t len, const struct multipath * mpp)
254 {
255         return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
256 }
257
258 static int
259 snprint_map_failures (char * buff, size_t len, const struct multipath * mpp)
260 {
261         return snprint_uint(buff, len, mpp->stat_map_failures);
262 }
263
264 static int
265 snprint_multipath_uuid (char * buff, size_t len, const struct multipath * mpp)
266 {
267         return snprint_str(buff, len, mpp->wwid);
268 }
269
270 static int
271 snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp)
272 {
273         struct pathgroup * pgp;
274         struct path * pp;
275         int i, j;
276
277         vector_foreach_slot(mpp->pg, pgp, i) {
278                 if (!pgp)
279                         continue;
280                 vector_foreach_slot(pgp->paths, pp, j) {
281                         if (strlen(pp->vendor_id) && strlen(pp->product_id))
282                                 return snprintf(buff, len, "%s,%s",
283                                                 pp->vendor_id, pp->product_id);
284                 }
285         }
286         return snprintf(buff, len, "##,##");
287 }
288
289
290 static int
291 snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
292 {
293         struct pathgroup * pgp;
294         struct path * pp;
295         int i, j;
296
297         vector_foreach_slot(mpp->pg, pgp, i) {
298                 if (!pgp)
299                         continue;
300                 vector_foreach_slot(pgp->paths, pp, j) {
301                         if (strlen(pp->vendor_id))
302                                 return snprintf(buff, len, "%s", pp->vendor_id);
303                 }
304         }
305         return snprintf(buff, len, "##");
306 }
307
308 static int
309 snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
310 {
311         struct pathgroup * pgp;
312         struct path * pp;
313         int i, j;
314
315         vector_foreach_slot(mpp->pg, pgp, i) {
316                 if (!pgp)
317                         continue;
318                 vector_foreach_slot(pgp->paths, pp, j) {
319                         if (strlen(pp->product_id))
320                                 return snprintf(buff, len, "%s", pp->product_id);
321                 }
322         }
323         return snprintf(buff, len, "##");
324 }
325
326 static int
327 snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
328 {
329         struct pathgroup * pgp;
330         struct path * pp;
331         int i, j;
332
333         vector_foreach_slot(mpp->pg, pgp, i) {
334                 if (!pgp)
335                         continue;
336                 vector_foreach_slot(pgp->paths, pp, j) {
337                         if (strlen(pp->rev))
338                                 return snprintf(buff, len, "%s", pp->rev);
339                 }
340         }
341         return snprintf(buff, len, "##");
342 }
343
344 static int
345 snprint_multipath_foreign (char * buff, size_t len, const struct multipath * pp)
346 {
347         return snprintf(buff, len, "%s", "--");
348 }
349
350 static int
351 snprint_action (char * buff, size_t len, const struct multipath * mpp)
352 {
353         switch (mpp->action) {
354         case ACT_REJECT:
355                 return snprint_str(buff, len, ACT_REJECT_STR);
356         case ACT_RENAME:
357                 return snprint_str(buff, len, ACT_RENAME_STR);
358         case ACT_RELOAD:
359                 return snprint_str(buff, len, ACT_RELOAD_STR);
360         case ACT_CREATE:
361                 return snprint_str(buff, len, ACT_CREATE_STR);
362         case ACT_SWITCHPG:
363                 return snprint_str(buff, len, ACT_SWITCHPG_STR);
364         default:
365                 return 0;
366         }
367 }
368
369 /*
370  * path info printing functions
371  */
372 static int
373 snprint_path_uuid (char * buff, size_t len, const struct path * pp)
374 {
375         return snprint_str(buff, len, pp->wwid);
376 }
377
378 static int
379 snprint_hcil (char * buff, size_t len, const struct path * pp)
380 {
381         if (!pp || pp->sg_id.host_no < 0)
382                 return snprintf(buff, len, "#:#:#:#");
383
384         return snprintf(buff, len, "%i:%i:%i:%i",
385                         pp->sg_id.host_no,
386                         pp->sg_id.channel,
387                         pp->sg_id.scsi_id,
388                         pp->sg_id.lun);
389 }
390
391 static int
392 snprint_dev (char * buff, size_t len, const struct path * pp)
393 {
394         if (!pp || !strlen(pp->dev))
395                 return snprintf(buff, len, "-");
396         else
397                 return snprint_str(buff, len, pp->dev);
398 }
399
400 static int
401 snprint_dev_t (char * buff, size_t len, const struct path * pp)
402 {
403         if (!pp || !strlen(pp->dev))
404                 return snprintf(buff, len, "#:#");
405         else
406                 return snprint_str(buff, len, pp->dev_t);
407 }
408
409 static int
410 snprint_offline (char * buff, size_t len, const struct path * pp)
411 {
412         if (!pp || !pp->mpp)
413                 return snprintf(buff, len, "unknown");
414         else if (pp->offline)
415                 return snprintf(buff, len, "offline");
416         else
417                 return snprintf(buff, len, "running");
418 }
419
420 static int
421 snprint_chk_state (char * buff, size_t len, const struct path * pp)
422 {
423         if (!pp || !pp->mpp)
424                 return snprintf(buff, len, "undef");
425
426         switch (pp->state) {
427         case PATH_UP:
428                 return snprintf(buff, len, "ready");
429         case PATH_DOWN:
430                 return snprintf(buff, len, "faulty");
431         case PATH_SHAKY:
432                 return snprintf(buff, len, "shaky");
433         case PATH_GHOST:
434                 return snprintf(buff, len, "ghost");
435         case PATH_PENDING:
436                 return snprintf(buff, len, "i/o pending");
437         case PATH_TIMEOUT:
438                 return snprintf(buff, len, "i/o timeout");
439         case PATH_DELAYED:
440                 return snprintf(buff, len, "delayed");
441         default:
442                 return snprintf(buff, len, "undef");
443         }
444 }
445
446 static int
447 snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
448 {
449         if (!pp)
450                 return snprintf(buff, len, "undef");
451
452         switch (pp->dmstate) {
453         case PSTATE_ACTIVE:
454                 return snprintf(buff, len, "active");
455         case PSTATE_FAILED:
456                 return snprintf(buff, len, "failed");
457         default:
458                 return snprintf(buff, len, "undef");
459         }
460 }
461
462 static int
463 snprint_vpr (char * buff, size_t len, const struct path * pp)
464 {
465         return snprintf(buff, len, "%s,%s",
466                         pp->vendor_id, pp->product_id);
467 }
468
469 static int
470 snprint_next_check (char * buff, size_t len, const struct path * pp)
471 {
472         if (!pp || !pp->mpp)
473                 return snprintf(buff, len, "orphan");
474
475         return snprint_progress(buff, len, pp->tick, pp->checkint);
476 }
477
478 static int
479 snprint_pri (char * buff, size_t len, const struct path * pp)
480 {
481         return snprint_int(buff, len, pp ? pp->priority : -1);
482 }
483
484 static int
485 snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
486 {
487         const char *s = pgp->mpp->selector;
488
489         return snprint_str(buff, len, s ? s : "");
490 }
491
492 static int
493 snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
494 {
495         return snprint_int(buff, len, pgp->priority);
496 }
497
498 static int
499 snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
500 {
501         switch (pgp->status) {
502         case PGSTATE_ENABLED:
503                 return snprintf(buff, len, "enabled");
504         case PGSTATE_DISABLED:
505                 return snprintf(buff, len, "disabled");
506         case PGSTATE_ACTIVE:
507                 return snprintf(buff, len, "active");
508         default:
509                 return snprintf(buff, len, "undef");
510         }
511 }
512
513 static int
514 snprint_path_size (char * buff, size_t len, const struct path * pp)
515 {
516         return snprint_size(buff, len, pp->size);
517 }
518
519 int
520 snprint_path_serial (char * buff, size_t len, const struct path * pp)
521 {
522         return snprint_str(buff, len, pp->serial);
523 }
524
525 static int
526 snprint_path_mpp (char * buff, size_t len, const struct path * pp)
527 {
528         if (!pp->mpp)
529                 return snprintf(buff, len, "[orphan]");
530         if (!pp->mpp->alias)
531                 return snprintf(buff, len, "[unknown]");
532         return snprint_str(buff, len, pp->mpp->alias);
533 }
534
535 static int
536 snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
537 {
538         struct udev_device *host_dev = NULL;
539         char host_id[32];
540         const char *value = NULL;
541         int ret;
542
543         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
544                 return snprintf(buff, len, "[undef]");
545         sprintf(host_id, "host%d", pp->sg_id.host_no);
546         host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
547                                                           host_id);
548         if (!host_dev) {
549                 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
550                 goto out;
551         }
552         value = udev_device_get_sysattr_value(host_dev, attr);
553         if (value)
554                 ret = snprint_str(buff, len, value);
555         udev_device_unref(host_dev);
556 out:
557         if (!value)
558                 ret = snprintf(buff, len, "[unknown]");
559         return ret;
560 }
561
562 int
563 snprint_host_wwnn (char * buff, size_t len, const struct path * pp)
564 {
565         return snprint_host_attr(buff, len, pp, "node_name");
566 }
567
568 int
569 snprint_host_wwpn (char * buff, size_t len, const struct path * pp)
570 {
571         return snprint_host_attr(buff, len, pp, "port_name");
572 }
573
574 int
575 snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
576 {
577         struct udev_device *rport_dev = NULL;
578         char rport_id[32];
579         const char *value = NULL;
580         int ret;
581
582         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
583                 return snprintf(buff, len, "[undef]");
584         sprintf(rport_id, "rport-%d:%d-%d",
585                 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
586         rport_dev = udev_device_new_from_subsystem_sysname(udev,
587                                 "fc_remote_ports", rport_id);
588         if (!rport_dev) {
589                 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
590                         rport_id);
591                 goto out;
592         }
593         value = udev_device_get_sysattr_value(rport_dev, "port_name");
594         if (value)
595                 ret = snprint_str(buff, len, value);
596         udev_device_unref(rport_dev);
597 out:
598         if (!value)
599                 ret = snprintf(buff, len, "[unknown]");
600         return ret;
601 }
602
603
604 int
605 snprint_tgt_wwnn (char * buff, size_t len, const struct path * pp)
606 {
607         if (pp->tgt_node_name[0] == '\0')
608                 return snprintf(buff, len, "[undef]");
609         return snprint_str(buff, len, pp->tgt_node_name);
610 }
611
612 static int
613 snprint_host_adapter (char * buff, size_t len, const struct path * pp)
614 {
615         char adapter[SLOT_NAME_SIZE];
616
617         if (sysfs_get_host_adapter_name(pp, adapter))
618                 return snprintf(buff, len, "[undef]");
619         return snprint_str(buff, len, adapter);
620 }
621
622 static int
623 snprint_path_checker (char * buff, size_t len, const struct path * pp)
624 {
625         const struct checker * c = &pp->checker;
626         return snprint_str(buff, len, c->name);
627 }
628
629 static int
630 snprint_path_foreign (char * buff, size_t len, const struct path * pp)
631 {
632         return snprintf(buff, len, "%s", "--");
633 }
634
635 static int
636 snprint_path_failures(char * buff, size_t len, const struct path * pp)
637 {
638         return snprint_int(buff, len, pp->failcount);
639 }
640
641 /* if you add a protocol string bigger than "scsi:unspec" you must
642  * also change PROTOCOL_BUF_SIZE */
643 int
644 snprint_path_protocol(char * buff, size_t len, const struct path * pp)
645 {
646         switch (pp->bus) {
647         case SYSFS_BUS_SCSI:
648                 switch (pp->sg_id.proto_id) {
649                 case SCSI_PROTOCOL_FCP:
650                         return snprintf(buff, len, "scsi:fcp");
651                 case SCSI_PROTOCOL_SPI:
652                         return snprintf(buff, len, "scsi:spi");
653                 case SCSI_PROTOCOL_SSA:
654                         return snprintf(buff, len, "scsi:ssa");
655                 case SCSI_PROTOCOL_SBP:
656                         return snprintf(buff, len, "scsi:sbp");
657                 case SCSI_PROTOCOL_SRP:
658                         return snprintf(buff, len, "scsi:srp");
659                 case SCSI_PROTOCOL_ISCSI:
660                         return snprintf(buff, len, "scsi:iscsi");
661                 case SCSI_PROTOCOL_SAS:
662                         return snprintf(buff, len, "scsi:sas");
663                 case SCSI_PROTOCOL_ADT:
664                         return snprintf(buff, len, "scsi:adt");
665                 case SCSI_PROTOCOL_ATA:
666                         return snprintf(buff, len, "scsi:ata");
667                 case SCSI_PROTOCOL_UNSPEC:
668                 default:
669                         return snprintf(buff, len, "scsi:unspec");
670                 }
671         case SYSFS_BUS_CCW:
672                 return snprintf(buff, len, "ccw");
673         case SYSFS_BUS_CCISS:
674                 return snprintf(buff, len, "cciss");
675         case SYSFS_BUS_NVME:
676                 return snprintf(buff, len, "nvme");
677         case SYSFS_BUS_UNDEF:
678         default:
679                 return snprintf(buff, len, "undef");
680         }
681 }
682
683 struct multipath_data mpd[] = {
684         {'n', "name",          0, snprint_name},
685         {'w', "uuid",          0, snprint_multipath_uuid},
686         {'d', "sysfs",         0, snprint_sysfs},
687         {'F', "failback",      0, snprint_failback},
688         {'Q', "queueing",      0, snprint_queueing},
689         {'N', "paths",         0, snprint_nb_paths},
690         {'r', "write_prot",    0, snprint_ro},
691         {'t', "dm-st",         0, snprint_dm_map_state},
692         {'S', "size",          0, snprint_multipath_size},
693         {'f', "features",      0, snprint_features},
694         {'x', "failures",      0, snprint_map_failures},
695         {'h', "hwhandler",     0, snprint_hwhandler},
696         {'A', "action",        0, snprint_action},
697         {'0', "path_faults",   0, snprint_path_faults},
698         {'1', "switch_grp",    0, snprint_switch_grp},
699         {'2', "map_loads",     0, snprint_map_loads},
700         {'3', "total_q_time",  0, snprint_total_q_time},
701         {'4', "q_timeouts",    0, snprint_q_timeouts},
702         {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
703         {'v', "vend",          0, snprint_multipath_vend},
704         {'p', "prod",          0, snprint_multipath_prod},
705         {'e', "rev",           0, snprint_multipath_rev},
706         {'G', "foreign",       0, snprint_multipath_foreign},
707         {0, NULL, 0 , NULL}
708 };
709
710 struct path_data pd[] = {
711         {'w', "uuid",          0, snprint_path_uuid},
712         {'i', "hcil",          0, snprint_hcil},
713         {'d', "dev",           0, snprint_dev},
714         {'D', "dev_t",         0, snprint_dev_t},
715         {'t', "dm_st",         0, snprint_dm_path_state},
716         {'o', "dev_st",        0, snprint_offline},
717         {'T', "chk_st",        0, snprint_chk_state},
718         {'s', "vend/prod/rev", 0, snprint_vpr},
719         {'c', "checker",       0, snprint_path_checker},
720         {'C', "next_check",    0, snprint_next_check},
721         {'p', "pri",           0, snprint_pri},
722         {'S', "size",          0, snprint_path_size},
723         {'z', "serial",        0, snprint_path_serial},
724         {'m', "multipath",     0, snprint_path_mpp},
725         {'N', "host WWNN",     0, snprint_host_wwnn},
726         {'n', "target WWNN",   0, snprint_tgt_wwnn},
727         {'R', "host WWPN",     0, snprint_host_wwpn},
728         {'r', "target WWPN",   0, snprint_tgt_wwpn},
729         {'a', "host adapter",  0, snprint_host_adapter},
730         {'G', "foreign",       0, snprint_path_foreign},
731         {'0', "failures",      0, snprint_path_failures},
732         {'P', "protocol",      0, snprint_path_protocol},
733         {0, NULL, 0 , NULL}
734 };
735
736 struct pathgroup_data pgd[] = {
737         {'s', "selector",      0, snprint_pg_selector},
738         {'p', "pri",           0, snprint_pg_pri},
739         {'t', "dm_st",         0, snprint_pg_state},
740         {0, NULL, 0 , NULL}
741 };
742
743 int
744 snprint_wildcards (char * buff, int len)
745 {
746         int i, fwd = 0;
747
748         fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
749         for (i = 0; mpd[i].header; i++)
750                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
751                                 mpd[i].wildcard, mpd[i].header);
752         fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
753         for (i = 0; pd[i].header; i++)
754                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
755                                 pd[i].wildcard, pd[i].header);
756         fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
757         for (i = 0; pgd[i].header; i++)
758                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
759                                 pgd[i].wildcard, pgd[i].header);
760         return fwd;
761 }
762
763 void
764 get_path_layout(vector pathvec, int header)
765 {
766         vector gpvec = vector_convert(NULL, pathvec, struct path,
767                                       dm_path_to_gen);
768         _get_path_layout(gpvec,
769                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
770         vector_free(gpvec);
771 }
772
773 static void
774 reset_width(int *width, enum layout_reset reset, const char *header)
775 {
776         switch (reset) {
777         case LAYOUT_RESET_HEADER:
778                 *width = strlen(header);
779                 break;
780         case LAYOUT_RESET_ZERO:
781                 *width = 0;
782                 break;
783         default:
784                 /* don't reset */
785                 break;
786         }
787 }
788
789 void
790 _get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
791 {
792         int i, j;
793         char buff[MAX_FIELD_LEN];
794         const struct gen_path *gp;
795
796         for (j = 0; pd[j].header; j++) {
797
798                 reset_width(&pd[j].width, reset, pd[j].header);
799
800                 if (gpvec == NULL)
801                         continue;
802
803                 vector_foreach_slot (gpvec, gp, i) {
804                         gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
805                                          pd[j].wildcard);
806                         pd[j].width = MAX(pd[j].width, strlen(buff));
807                 }
808         }
809 }
810
811 static void
812 reset_multipath_layout (void)
813 {
814         int i;
815
816         for (i = 0; mpd[i].header; i++)
817                 mpd[i].width = 0;
818 }
819
820 void
821 get_multipath_layout (vector mpvec, int header) {
822         vector gmvec = vector_convert(NULL, mpvec, struct multipath,
823                                       dm_multipath_to_gen);
824         _get_multipath_layout(gmvec,
825                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
826         vector_free(gmvec);
827 }
828
829 void
830 _get_multipath_layout (const struct _vector *gmvec,
831                             enum layout_reset reset)
832 {
833         int i, j;
834         char buff[MAX_FIELD_LEN];
835         const struct gen_multipath * gm;
836
837         for (j = 0; mpd[j].header; j++) {
838
839                 reset_width(&mpd[j].width, reset, mpd[j].header);
840
841                 if (gmvec == NULL)
842                         continue;
843
844                 vector_foreach_slot (gmvec, gm, i) {
845                         gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
846                                          mpd[j].wildcard);
847                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
848                 }
849                 condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
850         }
851 }
852
853 static struct multipath_data *
854 mpd_lookup(char wildcard)
855 {
856         int i;
857
858         for (i = 0; mpd[i].header; i++)
859                 if (mpd[i].wildcard == wildcard)
860                         return &mpd[i];
861
862         return NULL;
863 }
864
865 int snprint_multipath_attr(const struct gen_multipath* gm,
866                            char *buf, int len, char wildcard)
867 {
868         const struct multipath *mpp = gen_multipath_to_dm(gm);
869         struct multipath_data *mpd = mpd_lookup(wildcard);
870
871         if (mpd == NULL)
872                 return 0;
873         return mpd->snprint(buf, len, mpp);
874 }
875
876 static struct path_data *
877 pd_lookup(char wildcard)
878 {
879         int i;
880
881         for (i = 0; pd[i].header; i++)
882                 if (pd[i].wildcard == wildcard)
883                         return &pd[i];
884
885         return NULL;
886 }
887
888 int snprint_path_attr(const struct gen_path* gp,
889                       char *buf, int len, char wildcard)
890 {
891         const struct path *pp = gen_path_to_dm(gp);
892         struct path_data *pd = pd_lookup(wildcard);
893
894         if (pd == NULL)
895                 return 0;
896         return pd->snprint(buf, len, pp);
897 }
898
899 static struct pathgroup_data *
900 pgd_lookup(char wildcard)
901 {
902         int i;
903
904         for (i = 0; pgd[i].header; i++)
905                 if (pgd[i].wildcard == wildcard)
906                         return &pgd[i];
907
908         return NULL;
909 }
910
911 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
912                            char *buf, int len, char wildcard)
913 {
914         const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
915         struct pathgroup_data *pdg = pgd_lookup(wildcard);
916
917         if (pdg == NULL)
918                 return 0;
919         return pdg->snprint(buf, len, pg);
920 }
921
922 int
923 snprint_multipath_header (char * line, int len, const char * format)
924 {
925         char * c = line;   /* line cursor */
926         char * s = line;   /* for padding */
927         const char * f = format; /* format string cursor */
928         int fwd;
929         struct multipath_data * data;
930
931         do {
932                 if (TAIL <= 0)
933                         break;
934
935                 if (*f != '%') {
936                         *c++ = *f;
937                         NOPAD;
938                         continue;
939                 }
940                 f++;
941
942                 if (!(data = mpd_lookup(*f)))
943                         continue; /* unknown wildcard */
944
945                 PRINT(c, TAIL, "%s", data->header);
946                 PAD(data->width);
947         } while (*f++);
948
949         __endline(line, len, c);
950         return (c - line);
951 }
952
953 int
954 _snprint_multipath (const struct gen_multipath * gmp,
955                     char * line, int len, const char * format, int pad)
956 {
957         char * c = line;   /* line cursor */
958         char * s = line;   /* for padding */
959         const char * f = format; /* format string cursor */
960         int fwd;
961         struct multipath_data * data;
962         char buff[MAX_FIELD_LEN] = {};
963
964         do {
965                 if (TAIL <= 0)
966                         break;
967
968                 if (*f != '%') {
969                         *c++ = *f;
970                         NOPAD;
971                         continue;
972                 }
973                 f++;
974
975                 if (!(data = mpd_lookup(*f)))
976                         continue;
977
978                 gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
979                 PRINT(c, TAIL, "%s", buff);
980                 if (pad)
981                         PAD(data->width);
982                 buff[0] = '\0';
983         } while (*f++);
984
985         __endline(line, len, c);
986         return (c - line);
987 }
988
989 int
990 snprint_path_header (char * line, int len, const char * format)
991 {
992         char * c = line;   /* line cursor */
993         char * s = line;   /* for padding */
994         const char * f = format; /* format string cursor */
995         int fwd;
996         struct path_data * data;
997
998         do {
999                 if (TAIL <= 0)
1000                         break;
1001
1002                 if (*f != '%') {
1003                         *c++ = *f;
1004                         NOPAD;
1005                         continue;
1006                 }
1007                 f++;
1008
1009                 if (!(data = pd_lookup(*f)))
1010                         continue; /* unknown wildcard */
1011
1012                 PRINT(c, TAIL, "%s", data->header);
1013                 PAD(data->width);
1014         } while (*f++);
1015
1016         __endline(line, len, c);
1017         return (c - line);
1018 }
1019
1020 int
1021 _snprint_path (const struct gen_path * gp, char * line, int len,
1022                const char * format, int pad)
1023 {
1024         char * c = line;   /* line cursor */
1025         char * s = line;   /* for padding */
1026         const char * f = format; /* format string cursor */
1027         int fwd;
1028         struct path_data * data;
1029         char buff[MAX_FIELD_LEN];
1030
1031         do {
1032                 if (TAIL <= 0)
1033                         break;
1034
1035                 if (*f != '%') {
1036                         *c++ = *f;
1037                         NOPAD;
1038                         continue;
1039                 }
1040                 f++;
1041
1042                 if (!(data = pd_lookup(*f)))
1043                         continue;
1044
1045                 gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
1046                 PRINT(c, TAIL, "%s", buff);
1047                 if (pad)
1048                         PAD(data->width);
1049         } while (*f++);
1050
1051         __endline(line, len, c);
1052         return (c - line);
1053 }
1054
1055 int
1056 _snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
1057                     char * format)
1058 {
1059         char * c = line;   /* line cursor */
1060         char * s = line;   /* for padding */
1061         char * f = format; /* format string cursor */
1062         int fwd;
1063         struct pathgroup_data * data;
1064         char buff[MAX_FIELD_LEN];
1065
1066         do {
1067                 if (TAIL <= 0)
1068                         break;
1069
1070                 if (*f != '%') {
1071                         *c++ = *f;
1072                         NOPAD;
1073                         continue;
1074                 }
1075                 f++;
1076
1077                 if (!(data = pgd_lookup(*f)))
1078                         continue;
1079
1080                 ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
1081                 PRINT(c, TAIL, "%s", buff);
1082                 PAD(data->width);
1083         } while (*f++);
1084
1085         __endline(line, len, c);
1086         return (c - line);
1087 }
1088 #define snprint_pathgroup(line, len, fmt, pgp) \
1089         _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
1090
1091 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1092 {
1093         int resize;
1094         char *buff = NULL;
1095         char *old = NULL;
1096         int len, maxlen = MAX_LINE_LEN * MAX_LINES;
1097
1098         buff = MALLOC(maxlen);
1099         do {
1100                 if (!buff) {
1101                         if (old)
1102                                 FREE(old);
1103                         condlog(0, "couldn't allocate memory for list: %s\n",
1104                                 strerror(errno));
1105                         return;
1106                 }
1107
1108                 len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
1109                 resize = (len == maxlen - 1);
1110
1111                 if (resize) {
1112                         maxlen *= 2;
1113                         old = buff;
1114                         buff = REALLOC(buff, maxlen);
1115                 }
1116         } while (resize);
1117         printf("%s", buff);
1118         FREE(buff);
1119 }
1120
1121 int
1122 snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
1123                         int verbosity)
1124 {
1125         int n;
1126         const struct multipath *mpp = gen_multipath_to_dm(gmp);
1127         bool need_action = (verbosity > 1 &&
1128                             mpp->action != ACT_NOTHING &&
1129                             mpp->action != ACT_UNDEF &&
1130                             mpp->action != ACT_IMPOSSIBLE);
1131         bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1132
1133         n = snprintf(style, len, "%s%s%s%s",
1134                      need_action ? "%A: " : "", "%n",
1135                      need_wwid ? " (%w)" : "", " %d %s");
1136         return MIN(n, len - 1);
1137 }
1138
1139 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1140                                 char *buff, int len, int verbosity)
1141 {
1142         int j, i, fwd = 0;
1143         const struct _vector *pgvec;
1144         const struct gen_pathgroup *gpg;
1145         char style[64];
1146         char * c = style;
1147         char fmt[64];
1148         char * f;
1149
1150         if (verbosity <= 0)
1151                 return fwd;
1152
1153         reset_multipath_layout();
1154
1155         if (verbosity == 1)
1156                 return _snprint_multipath(gmp, buff, len, "%n", 1);
1157
1158         if(isatty(1))
1159                 c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
1160
1161         c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
1162                              verbosity);
1163         if(isatty(1))
1164                 c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
1165
1166         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
1167         if (fwd >= len)
1168                 return len;
1169         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
1170                                   PRINT_MAP_PROPS, 1);
1171         if (fwd >= len)
1172                 return len;
1173
1174         pgvec = gmp->ops->get_pathgroups(gmp);
1175         if (pgvec == NULL)
1176                 return fwd;
1177
1178         vector_foreach_slot (pgvec, gpg, j) {
1179                 const struct _vector *pathvec;
1180                 struct gen_path *gp;
1181
1182                 f=fmt;
1183
1184                 if (j + 1 < VECTOR_SIZE(pgvec)) {
1185                         strcpy(f, "|-+- " PRINT_PG_INDENT);
1186                 } else
1187                         strcpy(f, "`-+- " PRINT_PG_INDENT);
1188                 fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
1189
1190                 if (fwd >= len) {
1191                         fwd = len;
1192                         break;
1193                 }
1194
1195                 pathvec = gpg->ops->get_paths(gpg);
1196                 if (pathvec == NULL)
1197                         continue;
1198
1199                 vector_foreach_slot (pathvec, gp, i) {
1200                         f=fmt;
1201                         if (*f != '|')
1202                                 *f=' ';
1203                         f++;
1204                         if (i + 1 < VECTOR_SIZE(pathvec))
1205                                 strcpy(f, " |- " PRINT_PATH_INDENT);
1206                         else
1207                                 strcpy(f, " `- " PRINT_PATH_INDENT);
1208                         fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
1209                         if (fwd >= len) {
1210                                 fwd = len;
1211                                 break;
1212                         }
1213                 }
1214                 gpg->ops->rel_paths(gpg, pathvec);
1215
1216                 if (fwd == len)
1217                         break;
1218         }
1219         gmp->ops->rel_pathgroups(gmp, pgvec);
1220         return fwd;
1221 }
1222
1223
1224 static int
1225 snprint_json (char * buff, int len, int indent, char *json_str)
1226 {
1227         int fwd = 0, i;
1228
1229         for (i = 0; i < indent; i++) {
1230                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1231                 if (fwd >= len)
1232                         return fwd;
1233         }
1234
1235         fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
1236         return fwd;
1237 }
1238
1239 static int
1240 snprint_json_header (char * buff, int len)
1241 {
1242         int fwd = 0;
1243
1244         fwd +=  snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
1245         if (fwd >= len)
1246                 return fwd;
1247
1248         fwd +=  snprintf(buff + fwd, len  - fwd, PRINT_JSON_START_VERSION,
1249                         PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1250         return fwd;
1251 }
1252
1253 static int
1254 snprint_json_elem_footer (char * buff, int len, int indent, int last)
1255 {
1256         int fwd = 0, i;
1257
1258         for (i = 0; i < indent; i++) {
1259                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1260                 if (fwd >= len)
1261                         return fwd;
1262         }
1263
1264         if (last == 1)
1265                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
1266         else
1267                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
1268         return fwd;
1269 }
1270
1271 static int
1272 snprint_multipath_fields_json (char * buff, int len,
1273                 const struct multipath * mpp, int last)
1274 {
1275         int i, j, fwd = 0;
1276         struct path *pp;
1277         struct pathgroup *pgp;
1278
1279         fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
1280         if (fwd >= len)
1281                 return fwd;
1282
1283         fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
1284         if (fwd >= len)
1285                 return fwd;
1286
1287         vector_foreach_slot (mpp->pg, pgp, i) {
1288
1289                 fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
1290                 if (fwd >= len)
1291                         return fwd;
1292
1293                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
1294                 if (fwd >= len)
1295                         return fwd;
1296
1297                 fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
1298                 if (fwd >= len)
1299                         return fwd;
1300
1301                 vector_foreach_slot (pgp->paths, pp, j) {
1302                         fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
1303                         if (fwd >= len)
1304                                 return fwd;
1305
1306                         fwd += snprint_json_elem_footer(buff + fwd,
1307                                         len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
1308                         if (fwd >= len)
1309                                 return fwd;
1310                 }
1311                 fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1312                 if (fwd >= len)
1313                         return fwd;
1314
1315                 fwd +=  snprint_json_elem_footer(buff + fwd,
1316                                 len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
1317                 if (fwd >= len)
1318                         return fwd;
1319         }
1320
1321         fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1322         if (fwd >= len)
1323                 return fwd;
1324
1325         fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
1326         return fwd;
1327 }
1328
1329 int
1330 snprint_multipath_map_json (char * buff, int len,
1331                 const struct multipath * mpp, int last){
1332         int fwd = 0;
1333
1334         fwd +=  snprint_json_header(buff, len);
1335         if (fwd >= len)
1336                 return len;
1337
1338         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
1339         if (fwd >= len)
1340                 return len;
1341
1342         fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
1343         if (fwd >= len)
1344                 return len;
1345
1346         fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n");
1347         if (fwd >= len)
1348                 return len;
1349
1350         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1351         if (fwd >= len)
1352                 return len;
1353         return fwd;
1354 }
1355
1356 int
1357 snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
1358 {
1359         int i, fwd = 0;
1360         struct multipath * mpp;
1361
1362         fwd +=  snprint_json_header(buff, len);
1363         if (fwd >= len)
1364                 return len;
1365
1366         fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);
1367         if (fwd >= len)
1368                 return len;
1369
1370         vector_foreach_slot(vecs->mpvec, mpp, i) {
1371                 fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
1372                                 mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
1373                 if (fwd >= len)
1374                         return len;
1375         }
1376
1377         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1378         if (fwd >= len)
1379                 return len;
1380
1381         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1382         if (fwd >= len)
1383                 return len;
1384         return fwd;
1385 }
1386
1387 static int
1388 snprint_hwentry (const struct config *conf,
1389                  char * buff, int len, const struct hwentry * hwe)
1390 {
1391         int i;
1392         int fwd = 0;
1393         struct keyword * kw;
1394         struct keyword * rootkw;
1395
1396         rootkw = find_keyword(conf->keywords, NULL, "devices");
1397
1398         if (!rootkw || !rootkw->sub)
1399                 return 0;
1400
1401         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1402
1403         if (!rootkw)
1404                 return 0;
1405
1406         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1407         if (fwd >= len)
1408                 return len;
1409         iterate_sub_keywords(rootkw, kw, i) {
1410                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1411                                 kw, hwe);
1412                 if (fwd >= len)
1413                         return len;
1414         }
1415         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1416         if (fwd >= len)
1417                 return len;
1418         return fwd;
1419 }
1420
1421 static int snprint_hwtable(const struct config *conf,
1422                            char *buff, int len,
1423                            const struct _vector *hwtable)
1424 {
1425         int fwd = 0;
1426         int i;
1427         struct hwentry * hwe;
1428         struct keyword * rootkw;
1429
1430         rootkw = find_keyword(conf->keywords, NULL, "devices");
1431         if (!rootkw)
1432                 return 0;
1433
1434         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
1435         if (fwd >= len)
1436                 return len;
1437         vector_foreach_slot (hwtable, hwe, i) {
1438                 fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
1439                 if (fwd >= len)
1440                         return len;
1441         }
1442         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1443         if (fwd >= len)
1444                 return len;
1445         return fwd;
1446 }
1447
1448 static int
1449 snprint_mpentry (const struct config *conf, char * buff, int len,
1450                  const struct mpentry * mpe, const struct _vector *mpvec)
1451 {
1452         int i;
1453         int fwd = 0;
1454         struct keyword * kw;
1455         struct keyword * rootkw;
1456         struct multipath *mpp = NULL;
1457
1458         if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
1459                 return 0;
1460
1461         rootkw = find_keyword(conf->keywords, NULL, "multipath");
1462         if (!rootkw)
1463                 return 0;
1464
1465         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
1466         if (fwd >= len)
1467                 return len;
1468         iterate_sub_keywords(rootkw, kw, i) {
1469                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1470                                 kw, mpe);
1471                 if (fwd >= len)
1472                         return len;
1473         }
1474         /*
1475          * This mpp doesn't have alias defined. Add the alias in a comment.
1476          */
1477         if (mpp != NULL && strcmp(mpp->alias, mpp->wwid)) {
1478                 fwd += snprintf(buff + fwd, len - fwd, "\t\t# alias \"%s\"\n",
1479                                 mpp->alias);
1480                 if (fwd >= len)
1481                         return len;
1482         }
1483         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1484         if (fwd >= len)
1485                 return len;
1486         return fwd;
1487 }
1488
1489 static int snprint_mptable(const struct config *conf,
1490                            char *buff, int len, const struct _vector *mpvec)
1491 {
1492         int fwd = 0;
1493         int i;
1494         struct mpentry * mpe;
1495         struct keyword * rootkw;
1496
1497         rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1498         if (!rootkw)
1499                 return 0;
1500
1501         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
1502         if (fwd >= len)
1503                 return len;
1504         vector_foreach_slot (conf->mptable, mpe, i) {
1505                 fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe, mpvec);
1506                 if (fwd >= len)
1507                         return len;
1508         }
1509         if (mpvec != NULL) {
1510                 struct multipath *mpp;
1511
1512                 vector_foreach_slot(mpvec, mpp, i) {
1513                         if (find_mpe(conf->mptable, mpp->wwid) != NULL)
1514                                 continue;
1515
1516                         fwd += snprintf(buff + fwd, len - fwd,
1517                                         "\tmultipath {\n");
1518                         if (fwd >= len)
1519                                 return len;
1520                         fwd += snprintf(buff + fwd, len - fwd,
1521                                         "\t\twwid \"%s\"\n", mpp->wwid);
1522                         if (fwd >= len)
1523                                 return len;
1524                         /*
1525                          * This mpp doesn't have alias defined in
1526                          * multipath.conf - otherwise find_mpe would have
1527                          * found it. Add the alias in a comment.
1528                          */
1529                         if (strcmp(mpp->alias, mpp->wwid)) {
1530                                 fwd += snprintf(buff + fwd, len - fwd,
1531                                                 "\t\t# alias \"%s\"\n",
1532                                                 mpp->alias);
1533                                 if (fwd >= len)
1534                                         return len;
1535                         }
1536                         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1537                         if (fwd >= len)
1538                                 return len;
1539                 }
1540         }
1541         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1542         if (fwd >= len)
1543                 return len;
1544         return fwd;
1545 }
1546
1547 static int snprint_overrides(const struct config *conf, char * buff, int len,
1548                              const struct hwentry *overrides)
1549 {
1550         int fwd = 0;
1551         int i;
1552         struct keyword *rootkw;
1553         struct keyword *kw;
1554
1555         rootkw = find_keyword(conf->keywords, NULL, "overrides");
1556         if (!rootkw)
1557                 return 0;
1558
1559         fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
1560         if (fwd >= len)
1561                 return len;
1562         if (!overrides)
1563                 goto out;
1564         iterate_sub_keywords(rootkw, kw, i) {
1565                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1566                                        kw, NULL);
1567                 if (fwd >= len)
1568                         return len;
1569         }
1570 out:
1571         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1572         if (fwd >= len)
1573                 return len;
1574         return fwd;
1575 }
1576
1577 static int snprint_defaults(const struct config *conf, char *buff, int len)
1578 {
1579         int fwd = 0;
1580         int i;
1581         struct keyword *rootkw;
1582         struct keyword *kw;
1583
1584         rootkw = find_keyword(conf->keywords, NULL, "defaults");
1585         if (!rootkw)
1586                 return 0;
1587
1588         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
1589         if (fwd >= len)
1590                 return len;
1591
1592         iterate_sub_keywords(rootkw, kw, i) {
1593                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1594                                 kw, NULL);
1595                 if (fwd >= len)
1596                         return len;
1597         }
1598         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1599         if (fwd >= len)
1600                 return len;
1601         return fwd;
1602 }
1603
1604 static int
1605 snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
1606 {
1607         int threshold = MAX_LINE_LEN;
1608         struct blentry * ble;
1609         int pos;
1610         int i;
1611
1612         pos = *fwd;
1613         if (!VECTOR_SIZE(*vec)) {
1614                 if ((len - pos - threshold) <= 0)
1615                         return 0;
1616                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1617         } else vector_foreach_slot (*vec, ble, i) {
1618                 if ((len - pos - threshold) <= 0)
1619                         return 0;
1620                 if (ble->origin == ORIGIN_CONFIG)
1621                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1622                 else if (ble->origin == ORIGIN_DEFAULT)
1623                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1624                 pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
1625         }
1626
1627         *fwd = pos;
1628         return pos;
1629 }
1630
1631 static int
1632 snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
1633 {
1634         int threshold = MAX_LINE_LEN;
1635         struct blentry_device * bled;
1636         int pos;
1637         int i;
1638
1639         pos = *fwd;
1640         if (!VECTOR_SIZE(*vec)) {
1641                 if ((len - pos - threshold) <= 0)
1642                         return 0;
1643                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1644         } else vector_foreach_slot (*vec, bled, i) {
1645                 if ((len - pos - threshold) <= 0)
1646                         return 0;
1647                 if (bled->origin == ORIGIN_CONFIG)
1648                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1649                 else if (bled->origin == ORIGIN_DEFAULT)
1650                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1651                 pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
1652         }
1653
1654         *fwd = pos;
1655         return pos;
1656 }
1657
1658 int snprint_blacklist_report(struct config *conf, char *buff, int len)
1659 {
1660         int threshold = MAX_LINE_LEN;
1661         int fwd = 0;
1662
1663         if ((len - fwd - threshold) <= 0)
1664                 return len;
1665         fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
1666                                                "- blacklist:\n");
1667         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
1668                 return len;
1669
1670         if ((len - fwd - threshold) <= 0)
1671                 return len;
1672         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1673         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
1674                 return len;
1675
1676         if ((len - fwd - threshold) <= 0)
1677                 return len;
1678         fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
1679                                                "- blacklist:\n");
1680         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
1681                 return len;
1682
1683         if ((len - fwd - threshold) <= 0)
1684                 return len;
1685         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1686         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
1687                 return len;
1688
1689         if ((len - fwd - threshold) <= 0)
1690                 return len;
1691         fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n"
1692                                                "- blacklist:\n");
1693         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol))
1694                 return len;
1695
1696         if ((len - fwd - threshold) <= 0)
1697                 return len;
1698         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1699         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0)
1700                 return len;
1701
1702         if ((len - fwd - threshold) <= 0)
1703                 return len;
1704         fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
1705                                                "- blacklist:\n");
1706         if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
1707                 return len;
1708
1709         if ((len - fwd - threshold) <= 0)
1710                 return len;
1711         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1712         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
1713                 return len;
1714
1715         if ((len - fwd - threshold) <= 0)
1716                 return len;
1717         fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
1718                                                "- blacklist:\n");
1719         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
1720                 return len;
1721
1722         if ((len - fwd - threshold) <= 0)
1723                 return len;
1724         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1725         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
1726                 return len;
1727
1728         if (fwd > len)
1729                 return len;
1730         return fwd;
1731 }
1732
1733 static int snprint_blacklist(const struct config *conf, char *buff, int len)
1734 {
1735         int i;
1736         struct blentry * ble;
1737         struct blentry_device * bled;
1738         int fwd = 0;
1739         struct keyword *rootkw;
1740         struct keyword *kw;
1741
1742         rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1743         if (!rootkw)
1744                 return 0;
1745
1746         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
1747         if (fwd >= len)
1748                 return len;
1749
1750         vector_foreach_slot (conf->blist_devnode, ble, i) {
1751                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1752                 if (!kw)
1753                         return 0;
1754                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1755                                        kw, ble);
1756                 if (fwd >= len)
1757                         return len;
1758         }
1759         vector_foreach_slot (conf->blist_wwid, ble, i) {
1760                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1761                 if (!kw)
1762                         return 0;
1763                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1764                                        kw, ble);
1765                 if (fwd >= len)
1766                         return len;
1767         }
1768         vector_foreach_slot (conf->blist_property, ble, i) {
1769                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1770                 if (!kw)
1771                         return 0;
1772                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1773                                        kw, ble);
1774                 if (fwd >= len)
1775                         return len;
1776         }
1777         vector_foreach_slot (conf->blist_protocol, ble, i) {
1778                 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1779                 if (!kw)
1780                         return 0;
1781                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1782                                        kw, ble);
1783                 if (fwd >= len)
1784                         return len;
1785         }
1786         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1787         if (!rootkw)
1788                 return 0;
1789
1790         vector_foreach_slot (conf->blist_device, bled, i) {
1791                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1792                 if (fwd >= len)
1793                         return len;
1794                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1795                 if (!kw)
1796                         return 0;
1797                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1798                                        kw, bled);
1799                 if (fwd >= len)
1800                         return len;
1801                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1802                 if (!kw)
1803                         return 0;
1804                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1805                                        kw, bled);
1806                 if (fwd >= len)
1807                         return len;
1808                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1809                 if (fwd >= len)
1810                         return len;
1811         }
1812         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1813         if (fwd >= len)
1814                 return len;
1815         return fwd;
1816 }
1817
1818 static int snprint_blacklist_except(const struct config *conf,
1819                                     char *buff, int len)
1820 {
1821         int i;
1822         struct blentry * ele;
1823         struct blentry_device * eled;
1824         int fwd = 0;
1825         struct keyword *rootkw;
1826         struct keyword *kw;
1827
1828         rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1829         if (!rootkw)
1830                 return 0;
1831
1832         fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
1833         if (fwd >= len)
1834                 return len;
1835
1836         vector_foreach_slot (conf->elist_devnode, ele, i) {
1837                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1838                 if (!kw)
1839                         return 0;
1840                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1841                                        kw, ele);
1842                 if (fwd >= len)
1843                         return len;
1844         }
1845         vector_foreach_slot (conf->elist_wwid, ele, i) {
1846                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1847                 if (!kw)
1848                         return 0;
1849                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1850                                        kw, ele);
1851                 if (fwd >= len)
1852                         return len;
1853         }
1854         vector_foreach_slot (conf->elist_property, ele, i) {
1855                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1856                 if (!kw)
1857                         return 0;
1858                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1859                                        kw, ele);
1860                 if (fwd >= len)
1861                         return len;
1862         }
1863         vector_foreach_slot (conf->elist_protocol, ele, i) {
1864                 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1865                 if (!kw)
1866                         return 0;
1867                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1868                                        kw, ele);
1869                 if (fwd >= len)
1870                         return len;
1871         }
1872         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1873         if (!rootkw)
1874                 return 0;
1875
1876         vector_foreach_slot (conf->elist_device, eled, i) {
1877                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1878                 if (fwd >= len)
1879                         return len;
1880                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1881                 if (!kw)
1882                         return 0;
1883                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1884                                        kw, eled);
1885                 if (fwd >= len)
1886                         return len;
1887                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1888                 if (!kw)
1889                         return 0;
1890                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1891                                        kw, eled);
1892                 if (fwd >= len)
1893                         return len;
1894                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1895                 if (fwd >= len)
1896                         return len;
1897         }
1898         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1899         if (fwd >= len)
1900                 return len;
1901         return fwd;
1902 }
1903
1904 char *snprint_config(const struct config *conf, int *len,
1905                      const struct _vector *hwtable, const struct _vector *mpvec)
1906 {
1907         char *reply;
1908         /* built-in config is >20kB already */
1909         unsigned int maxlen = 32768;
1910
1911         for (reply = NULL; maxlen <= UINT_MAX/2; maxlen *= 2) {
1912                 char *c, *tmp = reply;
1913
1914                 reply = REALLOC(reply, maxlen);
1915                 if (!reply) {
1916                         if (tmp)
1917                                 free(tmp);
1918                         return NULL;
1919                 }
1920
1921                 c = reply + snprint_defaults(conf, reply, maxlen);
1922                 if ((c - reply) == maxlen)
1923                         continue;
1924
1925                 c += snprint_blacklist(conf, c, reply + maxlen - c);
1926                 if ((c - reply) == maxlen)
1927                         continue;
1928
1929                 c += snprint_blacklist_except(conf, c, reply + maxlen - c);
1930                 if ((c - reply) == maxlen)
1931                         continue;
1932
1933                 c += snprint_hwtable(conf, c, reply + maxlen - c,
1934                                      hwtable ? hwtable : conf->hwtable);
1935                 if ((c - reply) == maxlen)
1936                         continue;
1937
1938                 c += snprint_overrides(conf, c, reply + maxlen - c,
1939                                        conf->overrides);
1940                 if ((c - reply) == maxlen)
1941                         continue;
1942
1943                 if (VECTOR_SIZE(conf->mptable) > 0 ||
1944                     (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
1945                         c += snprint_mptable(conf, c, reply + maxlen - c,
1946                                              mpvec);
1947
1948                 if ((c - reply) < maxlen) {
1949                         if (len)
1950                                 *len = c - reply;
1951                         return reply;
1952                 }
1953         }
1954
1955         free(reply);
1956         return NULL;
1957 }
1958
1959 int snprint_status(char *buff, int len, const struct vectors *vecs)
1960 {
1961         int fwd = 0;
1962         int i;
1963         unsigned int count[PATH_MAX_STATE] = {0};
1964         struct path * pp;
1965
1966         vector_foreach_slot (vecs->pathvec, pp, i) {
1967                 count[pp->state]++;
1968         }
1969         fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
1970         for (i=0; i<PATH_MAX_STATE; i++) {
1971                 if (!count[i])
1972                         continue;
1973                 fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
1974                                 checker_state_name(i), count[i]);
1975         }
1976
1977         int monitored_count = 0;
1978
1979         vector_foreach_slot(vecs->pathvec, pp, i)
1980                 if (pp->fd >= 0)
1981                         monitored_count++;
1982         fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
1983                         monitored_count, is_uevent_busy()? "True" : "False");
1984
1985         if (fwd >= len)
1986                 return len;
1987         return fwd;
1988 }
1989
1990 int snprint_devices(struct config *conf, char * buff, int len,
1991                     const struct vectors *vecs)
1992 {
1993         DIR *blkdir;
1994         struct dirent *blkdev;
1995         struct stat statbuf;
1996         char devpath[PATH_MAX];
1997         char *devptr;
1998         int threshold = MAX_LINE_LEN;
1999         int fwd = 0;
2000         int r;
2001
2002         struct path * pp;
2003
2004         if (!(blkdir = opendir("/sys/block")))
2005                 return 1;
2006
2007         if ((len - fwd - threshold) <= 0) {
2008                 closedir(blkdir);
2009                 return len;
2010         }
2011         fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
2012
2013         strcpy(devpath,"/sys/block/");
2014         while ((blkdev = readdir(blkdir)) != NULL) {
2015                 if ((strcmp(blkdev->d_name,".") == 0) ||
2016                     (strcmp(blkdev->d_name,"..") == 0))
2017                         continue;
2018
2019                 devptr = devpath + 11;
2020                 *devptr = '\0';
2021                 strncat(devptr, blkdev->d_name, PATH_MAX-12);
2022                 if (stat(devpath, &statbuf) < 0)
2023                         continue;
2024
2025                 if (S_ISDIR(statbuf.st_mode) == 0)
2026                         continue;
2027
2028                 if ((len - fwd - threshold)  <= 0) {
2029                         closedir(blkdir);
2030                         return len;
2031                 }
2032
2033                 fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
2034                 pp = find_path_by_dev(vecs->pathvec, devptr);
2035                 if (!pp) {
2036                         r = filter_devnode(conf->blist_devnode,
2037                                            conf->elist_devnode, devptr);
2038                         if (r > 0)
2039                                 fwd += snprintf(buff + fwd, len - fwd,
2040                                                 " devnode blacklisted, unmonitored");
2041                         else if (r <= 0)
2042                                 fwd += snprintf(buff + fwd, len - fwd,
2043                                                 " devnode whitelisted, unmonitored");
2044                 } else
2045                         fwd += snprintf(buff + fwd, len - fwd,
2046                                         " devnode whitelisted, monitored");
2047                 fwd += snprintf(buff + fwd, len - fwd, "\n");
2048         }
2049         closedir(blkdir);
2050
2051         if (fwd >= len)
2052                 return len;
2053         return fwd;
2054 }
2055
2056 /*
2057  * stdout printing helpers
2058  */
2059 void print_path(struct path *pp, char *style)
2060 {
2061         char line[MAX_LINE_LEN];
2062
2063         memset(&line[0], 0, MAX_LINE_LEN);
2064         snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
2065         printf("%s", line);
2066 }
2067
2068 void print_all_paths(vector pathvec, int banner)
2069 {
2070         print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
2071 }
2072
2073 void print_all_paths_custo(vector pathvec, int banner, char *fmt)
2074 {
2075         int i;
2076         struct path * pp;
2077         char line[MAX_LINE_LEN];
2078
2079         if (!VECTOR_SIZE(pathvec)) {
2080                 if (banner)
2081                         fprintf(stdout, "===== no paths =====\n");
2082                 return;
2083         }
2084
2085         if (banner)
2086                 fprintf(stdout, "===== paths list =====\n");
2087
2088         get_path_layout(pathvec, 1);
2089         snprint_path_header(line, MAX_LINE_LEN, fmt);
2090         fprintf(stdout, "%s", line);
2091
2092         vector_foreach_slot (pathvec, pp, i)
2093                 print_path(pp, fmt);
2094 }