libmultipath: add marginal paths and groups infrastructure
[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                 vector_foreach_slot(pgp->paths, pp, j) {
279                         if (strlen(pp->vendor_id) && strlen(pp->product_id))
280                                 return snprintf(buff, len, "%s,%s",
281                                                 pp->vendor_id, pp->product_id);
282                 }
283         }
284         return snprintf(buff, len, "##,##");
285 }
286
287
288 static int
289 snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
290 {
291         struct pathgroup * pgp;
292         struct path * pp;
293         int i, j;
294
295         vector_foreach_slot(mpp->pg, pgp, i) {
296                 vector_foreach_slot(pgp->paths, pp, j) {
297                         if (strlen(pp->vendor_id))
298                                 return snprintf(buff, len, "%s", pp->vendor_id);
299                 }
300         }
301         return snprintf(buff, len, "##");
302 }
303
304 static int
305 snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
306 {
307         struct pathgroup * pgp;
308         struct path * pp;
309         int i, j;
310
311         vector_foreach_slot(mpp->pg, pgp, i) {
312                 vector_foreach_slot(pgp->paths, pp, j) {
313                         if (strlen(pp->product_id))
314                                 return snprintf(buff, len, "%s", pp->product_id);
315                 }
316         }
317         return snprintf(buff, len, "##");
318 }
319
320 static int
321 snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
322 {
323         struct pathgroup * pgp;
324         struct path * pp;
325         int i, j;
326
327         vector_foreach_slot(mpp->pg, pgp, i) {
328                 vector_foreach_slot(pgp->paths, pp, j) {
329                         if (strlen(pp->rev))
330                                 return snprintf(buff, len, "%s", pp->rev);
331                 }
332         }
333         return snprintf(buff, len, "##");
334 }
335
336 static int
337 snprint_multipath_foreign (char * buff, size_t len, const struct multipath * pp)
338 {
339         return snprintf(buff, len, "%s", "--");
340 }
341
342 static int
343 snprint_action (char * buff, size_t len, const struct multipath * mpp)
344 {
345         switch (mpp->action) {
346         case ACT_REJECT:
347                 return snprint_str(buff, len, ACT_REJECT_STR);
348         case ACT_RENAME:
349                 return snprint_str(buff, len, ACT_RENAME_STR);
350         case ACT_RELOAD:
351                 return snprint_str(buff, len, ACT_RELOAD_STR);
352         case ACT_CREATE:
353                 return snprint_str(buff, len, ACT_CREATE_STR);
354         case ACT_SWITCHPG:
355                 return snprint_str(buff, len, ACT_SWITCHPG_STR);
356         default:
357                 return 0;
358         }
359 }
360
361 /*
362  * path info printing functions
363  */
364 static int
365 snprint_path_uuid (char * buff, size_t len, const struct path * pp)
366 {
367         return snprint_str(buff, len, pp->wwid);
368 }
369
370 static int
371 snprint_hcil (char * buff, size_t len, const struct path * pp)
372 {
373         if (!pp || pp->sg_id.host_no < 0)
374                 return snprintf(buff, len, "#:#:#:#");
375
376         return snprintf(buff, len, "%i:%i:%i:%i",
377                         pp->sg_id.host_no,
378                         pp->sg_id.channel,
379                         pp->sg_id.scsi_id,
380                         pp->sg_id.lun);
381 }
382
383 static int
384 snprint_dev (char * buff, size_t len, const struct path * pp)
385 {
386         if (!pp || !strlen(pp->dev))
387                 return snprintf(buff, len, "-");
388         else
389                 return snprint_str(buff, len, pp->dev);
390 }
391
392 static int
393 snprint_dev_t (char * buff, size_t len, const struct path * pp)
394 {
395         if (!pp || !strlen(pp->dev))
396                 return snprintf(buff, len, "#:#");
397         else
398                 return snprint_str(buff, len, pp->dev_t);
399 }
400
401 static int
402 snprint_offline (char * buff, size_t len, const struct path * pp)
403 {
404         if (!pp || !pp->mpp)
405                 return snprintf(buff, len, "unknown");
406         else if (pp->offline)
407                 return snprintf(buff, len, "offline");
408         else
409                 return snprintf(buff, len, "running");
410 }
411
412 static int
413 snprint_chk_state (char * buff, size_t len, const struct path * pp)
414 {
415         if (!pp || !pp->mpp)
416                 return snprintf(buff, len, "undef");
417
418         switch (pp->state) {
419         case PATH_UP:
420                 return snprintf(buff, len, "ready");
421         case PATH_DOWN:
422                 return snprintf(buff, len, "faulty");
423         case PATH_SHAKY:
424                 return snprintf(buff, len, "shaky");
425         case PATH_GHOST:
426                 return snprintf(buff, len, "ghost");
427         case PATH_PENDING:
428                 return snprintf(buff, len, "i/o pending");
429         case PATH_TIMEOUT:
430                 return snprintf(buff, len, "i/o timeout");
431         case PATH_DELAYED:
432                 return snprintf(buff, len, "delayed");
433         default:
434                 return snprintf(buff, len, "undef");
435         }
436 }
437
438 static int
439 snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
440 {
441         if (!pp)
442                 return snprintf(buff, len, "undef");
443
444         switch (pp->dmstate) {
445         case PSTATE_ACTIVE:
446                 return snprintf(buff, len, "active");
447         case PSTATE_FAILED:
448                 return snprintf(buff, len, "failed");
449         default:
450                 return snprintf(buff, len, "undef");
451         }
452 }
453
454 static int
455 snprint_vpr (char * buff, size_t len, const struct path * pp)
456 {
457         return snprintf(buff, len, "%s,%s",
458                         pp->vendor_id, pp->product_id);
459 }
460
461 static int
462 snprint_next_check (char * buff, size_t len, const struct path * pp)
463 {
464         if (!pp || !pp->mpp)
465                 return snprintf(buff, len, "orphan");
466
467         return snprint_progress(buff, len, pp->tick, pp->checkint);
468 }
469
470 static int
471 snprint_pri (char * buff, size_t len, const struct path * pp)
472 {
473         return snprint_int(buff, len, pp ? pp->priority : -1);
474 }
475
476 static int
477 snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
478 {
479         const char *s = pgp->mpp->selector;
480
481         return snprint_str(buff, len, s ? s : "");
482 }
483
484 static int
485 snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
486 {
487         return snprint_int(buff, len, pgp->priority);
488 }
489
490 static int
491 snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
492 {
493         switch (pgp->status) {
494         case PGSTATE_ENABLED:
495                 return snprintf(buff, len, "enabled");
496         case PGSTATE_DISABLED:
497                 return snprintf(buff, len, "disabled");
498         case PGSTATE_ACTIVE:
499                 return snprintf(buff, len, "active");
500         default:
501                 return snprintf(buff, len, "undef");
502         }
503 }
504
505 static int
506 snprint_pg_marginal (char * buff, size_t len, const struct pathgroup * pgp)
507 {
508         if (pgp->marginal)
509                 return snprintf(buff, len, "marginal");
510         return snprintf(buff, len, "normal");
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, checker_name(c));
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 int
684 snprint_path_marginal(char * buff, size_t len, const struct path * pp)
685 {
686         if (pp->marginal)
687                 return snprintf(buff, len, "marginal");
688         return snprintf(buff, len, "normal");
689 }
690
691 struct multipath_data mpd[] = {
692         {'n', "name",          0, snprint_name},
693         {'w', "uuid",          0, snprint_multipath_uuid},
694         {'d', "sysfs",         0, snprint_sysfs},
695         {'F', "failback",      0, snprint_failback},
696         {'Q', "queueing",      0, snprint_queueing},
697         {'N', "paths",         0, snprint_nb_paths},
698         {'r', "write_prot",    0, snprint_ro},
699         {'t', "dm-st",         0, snprint_dm_map_state},
700         {'S', "size",          0, snprint_multipath_size},
701         {'f', "features",      0, snprint_features},
702         {'x', "failures",      0, snprint_map_failures},
703         {'h', "hwhandler",     0, snprint_hwhandler},
704         {'A', "action",        0, snprint_action},
705         {'0', "path_faults",   0, snprint_path_faults},
706         {'1', "switch_grp",    0, snprint_switch_grp},
707         {'2', "map_loads",     0, snprint_map_loads},
708         {'3', "total_q_time",  0, snprint_total_q_time},
709         {'4', "q_timeouts",    0, snprint_q_timeouts},
710         {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
711         {'v', "vend",          0, snprint_multipath_vend},
712         {'p', "prod",          0, snprint_multipath_prod},
713         {'e', "rev",           0, snprint_multipath_rev},
714         {'G', "foreign",       0, snprint_multipath_foreign},
715         {0, NULL, 0 , NULL}
716 };
717
718 struct path_data pd[] = {
719         {'w', "uuid",          0, snprint_path_uuid},
720         {'i', "hcil",          0, snprint_hcil},
721         {'d', "dev",           0, snprint_dev},
722         {'D', "dev_t",         0, snprint_dev_t},
723         {'t', "dm_st",         0, snprint_dm_path_state},
724         {'o', "dev_st",        0, snprint_offline},
725         {'T', "chk_st",        0, snprint_chk_state},
726         {'s', "vend/prod/rev", 0, snprint_vpr},
727         {'c', "checker",       0, snprint_path_checker},
728         {'C', "next_check",    0, snprint_next_check},
729         {'p', "pri",           0, snprint_pri},
730         {'S', "size",          0, snprint_path_size},
731         {'z', "serial",        0, snprint_path_serial},
732         {'M', "marginal_st",   0, snprint_path_marginal},
733         {'m', "multipath",     0, snprint_path_mpp},
734         {'N', "host WWNN",     0, snprint_host_wwnn},
735         {'n', "target WWNN",   0, snprint_tgt_wwnn},
736         {'R', "host WWPN",     0, snprint_host_wwpn},
737         {'r', "target WWPN",   0, snprint_tgt_wwpn},
738         {'a', "host adapter",  0, snprint_host_adapter},
739         {'G', "foreign",       0, snprint_path_foreign},
740         {'0', "failures",      0, snprint_path_failures},
741         {'P', "protocol",      0, snprint_path_protocol},
742         {0, NULL, 0 , NULL}
743 };
744
745 struct pathgroup_data pgd[] = {
746         {'s', "selector",      0, snprint_pg_selector},
747         {'p', "pri",           0, snprint_pg_pri},
748         {'t', "dm_st",         0, snprint_pg_state},
749         {'M', "marginal_st",   0, snprint_pg_marginal},
750         {0, NULL, 0 , NULL}
751 };
752
753 int
754 snprint_wildcards (char * buff, int len)
755 {
756         int i, fwd = 0;
757
758         fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
759         for (i = 0; mpd[i].header; i++)
760                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
761                                 mpd[i].wildcard, mpd[i].header);
762         fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
763         for (i = 0; pd[i].header; i++)
764                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
765                                 pd[i].wildcard, pd[i].header);
766         fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
767         for (i = 0; pgd[i].header; i++)
768                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
769                                 pgd[i].wildcard, pgd[i].header);
770         return fwd;
771 }
772
773 void
774 get_path_layout(vector pathvec, int header)
775 {
776         vector gpvec = vector_convert(NULL, pathvec, struct path,
777                                       dm_path_to_gen);
778         _get_path_layout(gpvec,
779                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
780         vector_free(gpvec);
781 }
782
783 static void
784 reset_width(int *width, enum layout_reset reset, const char *header)
785 {
786         switch (reset) {
787         case LAYOUT_RESET_HEADER:
788                 *width = strlen(header);
789                 break;
790         case LAYOUT_RESET_ZERO:
791                 *width = 0;
792                 break;
793         default:
794                 /* don't reset */
795                 break;
796         }
797 }
798
799 void
800 _get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
801 {
802         int i, j;
803         char buff[MAX_FIELD_LEN];
804         const struct gen_path *gp;
805
806         for (j = 0; pd[j].header; j++) {
807
808                 reset_width(&pd[j].width, reset, pd[j].header);
809
810                 if (gpvec == NULL)
811                         continue;
812
813                 vector_foreach_slot (gpvec, gp, i) {
814                         gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
815                                          pd[j].wildcard);
816                         pd[j].width = MAX(pd[j].width, strlen(buff));
817                 }
818         }
819 }
820
821 static void
822 reset_multipath_layout (void)
823 {
824         int i;
825
826         for (i = 0; mpd[i].header; i++)
827                 mpd[i].width = 0;
828 }
829
830 void
831 get_multipath_layout (vector mpvec, int header) {
832         vector gmvec = vector_convert(NULL, mpvec, struct multipath,
833                                       dm_multipath_to_gen);
834         _get_multipath_layout(gmvec,
835                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
836         vector_free(gmvec);
837 }
838
839 void
840 _get_multipath_layout (const struct _vector *gmvec,
841                             enum layout_reset reset)
842 {
843         int i, j;
844         char buff[MAX_FIELD_LEN];
845         const struct gen_multipath * gm;
846
847         for (j = 0; mpd[j].header; j++) {
848
849                 reset_width(&mpd[j].width, reset, mpd[j].header);
850
851                 if (gmvec == NULL)
852                         continue;
853
854                 vector_foreach_slot (gmvec, gm, i) {
855                         gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
856                                          mpd[j].wildcard);
857                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
858                 }
859                 condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
860         }
861 }
862
863 static struct multipath_data *
864 mpd_lookup(char wildcard)
865 {
866         int i;
867
868         for (i = 0; mpd[i].header; i++)
869                 if (mpd[i].wildcard == wildcard)
870                         return &mpd[i];
871
872         return NULL;
873 }
874
875 int snprint_multipath_attr(const struct gen_multipath* gm,
876                            char *buf, int len, char wildcard)
877 {
878         const struct multipath *mpp = gen_multipath_to_dm(gm);
879         struct multipath_data *mpd = mpd_lookup(wildcard);
880
881         if (mpd == NULL)
882                 return 0;
883         return mpd->snprint(buf, len, mpp);
884 }
885
886 static struct path_data *
887 pd_lookup(char wildcard)
888 {
889         int i;
890
891         for (i = 0; pd[i].header; i++)
892                 if (pd[i].wildcard == wildcard)
893                         return &pd[i];
894
895         return NULL;
896 }
897
898 int snprint_path_attr(const struct gen_path* gp,
899                       char *buf, int len, char wildcard)
900 {
901         const struct path *pp = gen_path_to_dm(gp);
902         struct path_data *pd = pd_lookup(wildcard);
903
904         if (pd == NULL)
905                 return 0;
906         return pd->snprint(buf, len, pp);
907 }
908
909 static struct pathgroup_data *
910 pgd_lookup(char wildcard)
911 {
912         int i;
913
914         for (i = 0; pgd[i].header; i++)
915                 if (pgd[i].wildcard == wildcard)
916                         return &pgd[i];
917
918         return NULL;
919 }
920
921 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
922                            char *buf, int len, char wildcard)
923 {
924         const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
925         struct pathgroup_data *pdg = pgd_lookup(wildcard);
926
927         if (pdg == NULL)
928                 return 0;
929         return pdg->snprint(buf, len, pg);
930 }
931
932 int
933 snprint_multipath_header (char * line, int len, const char * format)
934 {
935         char * c = line;   /* line cursor */
936         char * s = line;   /* for padding */
937         const char * f = format; /* format string cursor */
938         int fwd;
939         struct multipath_data * data;
940
941         do {
942                 if (TAIL <= 0)
943                         break;
944
945                 if (*f != '%') {
946                         *c++ = *f;
947                         NOPAD;
948                         continue;
949                 }
950                 f++;
951
952                 if (!(data = mpd_lookup(*f)))
953                         continue; /* unknown wildcard */
954
955                 PRINT(c, TAIL, "%s", data->header);
956                 PAD(data->width);
957         } while (*f++);
958
959         __endline(line, len, c);
960         return (c - line);
961 }
962
963 int
964 _snprint_multipath (const struct gen_multipath * gmp,
965                     char * line, int len, const char * format, int pad)
966 {
967         char * c = line;   /* line cursor */
968         char * s = line;   /* for padding */
969         const char * f = format; /* format string cursor */
970         int fwd;
971         struct multipath_data * data;
972         char buff[MAX_FIELD_LEN] = {};
973
974         do {
975                 if (TAIL <= 0)
976                         break;
977
978                 if (*f != '%') {
979                         *c++ = *f;
980                         NOPAD;
981                         continue;
982                 }
983                 f++;
984
985                 if (!(data = mpd_lookup(*f)))
986                         continue;
987
988                 gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
989                 PRINT(c, TAIL, "%s", buff);
990                 if (pad)
991                         PAD(data->width);
992                 buff[0] = '\0';
993         } while (*f++);
994
995         __endline(line, len, c);
996         return (c - line);
997 }
998
999 int
1000 snprint_path_header (char * line, int len, const char * format)
1001 {
1002         char * c = line;   /* line cursor */
1003         char * s = line;   /* for padding */
1004         const char * f = format; /* format string cursor */
1005         int fwd;
1006         struct path_data * data;
1007
1008         do {
1009                 if (TAIL <= 0)
1010                         break;
1011
1012                 if (*f != '%') {
1013                         *c++ = *f;
1014                         NOPAD;
1015                         continue;
1016                 }
1017                 f++;
1018
1019                 if (!(data = pd_lookup(*f)))
1020                         continue; /* unknown wildcard */
1021
1022                 PRINT(c, TAIL, "%s", data->header);
1023                 PAD(data->width);
1024         } while (*f++);
1025
1026         __endline(line, len, c);
1027         return (c - line);
1028 }
1029
1030 int
1031 _snprint_path (const struct gen_path * gp, char * line, int len,
1032                const char * format, int pad)
1033 {
1034         char * c = line;   /* line cursor */
1035         char * s = line;   /* for padding */
1036         const char * f = format; /* format string cursor */
1037         int fwd;
1038         struct path_data * data;
1039         char buff[MAX_FIELD_LEN];
1040
1041         do {
1042                 if (TAIL <= 0)
1043                         break;
1044
1045                 if (*f != '%') {
1046                         *c++ = *f;
1047                         NOPAD;
1048                         continue;
1049                 }
1050                 f++;
1051
1052                 if (!(data = pd_lookup(*f)))
1053                         continue;
1054
1055                 gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
1056                 PRINT(c, TAIL, "%s", buff);
1057                 if (pad)
1058                         PAD(data->width);
1059         } while (*f++);
1060
1061         __endline(line, len, c);
1062         return (c - line);
1063 }
1064
1065 int
1066 _snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
1067                     char * format)
1068 {
1069         char * c = line;   /* line cursor */
1070         char * s = line;   /* for padding */
1071         char * f = format; /* format string cursor */
1072         int fwd;
1073         struct pathgroup_data * data;
1074         char buff[MAX_FIELD_LEN];
1075
1076         do {
1077                 if (TAIL <= 0)
1078                         break;
1079
1080                 if (*f != '%') {
1081                         *c++ = *f;
1082                         NOPAD;
1083                         continue;
1084                 }
1085                 f++;
1086
1087                 if (!(data = pgd_lookup(*f)))
1088                         continue;
1089
1090                 ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
1091                 PRINT(c, TAIL, "%s", buff);
1092                 PAD(data->width);
1093         } while (*f++);
1094
1095         __endline(line, len, c);
1096         return (c - line);
1097 }
1098 #define snprint_pathgroup(line, len, fmt, pgp) \
1099         _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
1100
1101 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1102 {
1103         int resize;
1104         char *buff = NULL;
1105         char *old = NULL;
1106         int len, maxlen = MAX_LINE_LEN * MAX_LINES;
1107
1108         buff = MALLOC(maxlen);
1109         do {
1110                 if (!buff) {
1111                         if (old)
1112                                 FREE(old);
1113                         condlog(0, "couldn't allocate memory for list: %s\n",
1114                                 strerror(errno));
1115                         return;
1116                 }
1117
1118                 len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
1119                 resize = (len == maxlen - 1);
1120
1121                 if (resize) {
1122                         maxlen *= 2;
1123                         old = buff;
1124                         buff = REALLOC(buff, maxlen);
1125                 }
1126         } while (resize);
1127         printf("%s", buff);
1128         FREE(buff);
1129 }
1130
1131 int
1132 snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
1133                         int verbosity)
1134 {
1135         int n;
1136         const struct multipath *mpp = gen_multipath_to_dm(gmp);
1137         bool need_action = (verbosity > 1 &&
1138                             mpp->action != ACT_NOTHING &&
1139                             mpp->action != ACT_UNDEF &&
1140                             mpp->action != ACT_IMPOSSIBLE);
1141         bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1142
1143         n = snprintf(style, len, "%s%s%s%s",
1144                      need_action ? "%A: " : "", "%n",
1145                      need_wwid ? " (%w)" : "", " %d %s");
1146         return MIN(n, len - 1);
1147 }
1148
1149 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1150                                 char *buff, int len, int verbosity)
1151 {
1152         int j, i, fwd = 0;
1153         const struct _vector *pgvec;
1154         const struct gen_pathgroup *gpg;
1155         char style[64];
1156         char * c = style;
1157         char fmt[64];
1158         char * f;
1159
1160         if (verbosity <= 0)
1161                 return fwd;
1162
1163         reset_multipath_layout();
1164
1165         if (verbosity == 1)
1166                 return _snprint_multipath(gmp, buff, len, "%n", 1);
1167
1168         if(isatty(1))
1169                 c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
1170
1171         c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
1172                              verbosity);
1173         if(isatty(1))
1174                 c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
1175
1176         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
1177         if (fwd >= len)
1178                 return len;
1179         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
1180                                   PRINT_MAP_PROPS, 1);
1181         if (fwd >= len)
1182                 return len;
1183
1184         pgvec = gmp->ops->get_pathgroups(gmp);
1185         if (pgvec == NULL)
1186                 return fwd;
1187
1188         vector_foreach_slot (pgvec, gpg, j) {
1189                 const struct _vector *pathvec;
1190                 struct gen_path *gp;
1191
1192                 f=fmt;
1193
1194                 if (j + 1 < VECTOR_SIZE(pgvec)) {
1195                         strcpy(f, "|-+- " PRINT_PG_INDENT);
1196                 } else
1197                         strcpy(f, "`-+- " PRINT_PG_INDENT);
1198                 fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
1199
1200                 if (fwd >= len) {
1201                         fwd = len;
1202                         break;
1203                 }
1204
1205                 pathvec = gpg->ops->get_paths(gpg);
1206                 if (pathvec == NULL)
1207                         continue;
1208
1209                 vector_foreach_slot (pathvec, gp, i) {
1210                         f=fmt;
1211                         if (*f != '|')
1212                                 *f=' ';
1213                         f++;
1214                         if (i + 1 < VECTOR_SIZE(pathvec))
1215                                 strcpy(f, " |- " PRINT_PATH_INDENT);
1216                         else
1217                                 strcpy(f, " `- " PRINT_PATH_INDENT);
1218                         fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
1219                         if (fwd >= len) {
1220                                 fwd = len;
1221                                 break;
1222                         }
1223                 }
1224                 gpg->ops->rel_paths(gpg, pathvec);
1225
1226                 if (fwd == len)
1227                         break;
1228         }
1229         gmp->ops->rel_pathgroups(gmp, pgvec);
1230         return fwd;
1231 }
1232
1233
1234 static int
1235 snprint_json (char * buff, int len, int indent, char *json_str)
1236 {
1237         int fwd = 0, i;
1238
1239         for (i = 0; i < indent; i++) {
1240                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1241                 if (fwd >= len)
1242                         return fwd;
1243         }
1244
1245         fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
1246         return fwd;
1247 }
1248
1249 static int
1250 snprint_json_header (char * buff, int len)
1251 {
1252         int fwd = 0;
1253
1254         fwd +=  snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
1255         if (fwd >= len)
1256                 return fwd;
1257
1258         fwd +=  snprintf(buff + fwd, len  - fwd, PRINT_JSON_START_VERSION,
1259                         PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1260         return fwd;
1261 }
1262
1263 static int
1264 snprint_json_elem_footer (char * buff, int len, int indent, int last)
1265 {
1266         int fwd = 0, i;
1267
1268         for (i = 0; i < indent; i++) {
1269                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1270                 if (fwd >= len)
1271                         return fwd;
1272         }
1273
1274         if (last == 1)
1275                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
1276         else
1277                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
1278         return fwd;
1279 }
1280
1281 static int
1282 snprint_multipath_fields_json (char * buff, int len,
1283                 const struct multipath * mpp, int last)
1284 {
1285         int i, j, fwd = 0;
1286         struct path *pp;
1287         struct pathgroup *pgp;
1288
1289         fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
1290         if (fwd >= len)
1291                 return fwd;
1292
1293         fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
1294         if (fwd >= len)
1295                 return fwd;
1296
1297         vector_foreach_slot (mpp->pg, pgp, i) {
1298
1299                 fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
1300                 if (fwd >= len)
1301                         return fwd;
1302
1303                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
1304                 if (fwd >= len)
1305                         return fwd;
1306
1307                 fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
1308                 if (fwd >= len)
1309                         return fwd;
1310
1311                 vector_foreach_slot (pgp->paths, pp, j) {
1312                         fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
1313                         if (fwd >= len)
1314                                 return fwd;
1315
1316                         fwd += snprint_json_elem_footer(buff + fwd,
1317                                         len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
1318                         if (fwd >= len)
1319                                 return fwd;
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,
1326                                 len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
1327                 if (fwd >= len)
1328                         return fwd;
1329         }
1330
1331         fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1332         if (fwd >= len)
1333                 return fwd;
1334
1335         fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
1336         return fwd;
1337 }
1338
1339 int
1340 snprint_multipath_map_json (char * buff, int len,
1341                 const struct multipath * mpp, int last){
1342         int fwd = 0;
1343
1344         fwd +=  snprint_json_header(buff, len);
1345         if (fwd >= len)
1346                 return len;
1347
1348         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
1349         if (fwd >= len)
1350                 return len;
1351
1352         fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
1353         if (fwd >= len)
1354                 return len;
1355
1356         fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n");
1357         if (fwd >= len)
1358                 return len;
1359
1360         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1361         if (fwd >= len)
1362                 return len;
1363         return fwd;
1364 }
1365
1366 int
1367 snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
1368 {
1369         int i, fwd = 0;
1370         struct multipath * mpp;
1371
1372         fwd +=  snprint_json_header(buff, len);
1373         if (fwd >= len)
1374                 return len;
1375
1376         fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);
1377         if (fwd >= len)
1378                 return len;
1379
1380         vector_foreach_slot(vecs->mpvec, mpp, i) {
1381                 fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
1382                                 mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
1383                 if (fwd >= len)
1384                         return len;
1385         }
1386
1387         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1388         if (fwd >= len)
1389                 return len;
1390
1391         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1392         if (fwd >= len)
1393                 return len;
1394         return fwd;
1395 }
1396
1397 static int
1398 snprint_hwentry (const struct config *conf,
1399                  char * buff, int len, const struct hwentry * hwe)
1400 {
1401         int i;
1402         int fwd = 0;
1403         struct keyword * kw;
1404         struct keyword * rootkw;
1405
1406         rootkw = find_keyword(conf->keywords, NULL, "devices");
1407
1408         if (!rootkw || !rootkw->sub)
1409                 return 0;
1410
1411         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1412
1413         if (!rootkw)
1414                 return 0;
1415
1416         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1417         if (fwd >= len)
1418                 return len;
1419         iterate_sub_keywords(rootkw, kw, i) {
1420                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1421                                 kw, hwe);
1422                 if (fwd >= len)
1423                         return len;
1424         }
1425         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1426         if (fwd >= len)
1427                 return len;
1428         return fwd;
1429 }
1430
1431 static int snprint_hwtable(const struct config *conf,
1432                            char *buff, int len,
1433                            const struct _vector *hwtable)
1434 {
1435         int fwd = 0;
1436         int i;
1437         struct hwentry * hwe;
1438         struct keyword * rootkw;
1439
1440         rootkw = find_keyword(conf->keywords, NULL, "devices");
1441         if (!rootkw)
1442                 return 0;
1443
1444         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
1445         if (fwd >= len)
1446                 return len;
1447         vector_foreach_slot (hwtable, hwe, i) {
1448                 fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
1449                 if (fwd >= len)
1450                         return len;
1451         }
1452         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1453         if (fwd >= len)
1454                 return len;
1455         return fwd;
1456 }
1457
1458 static int
1459 snprint_mpentry (const struct config *conf, char * buff, int len,
1460                  const struct mpentry * mpe, const struct _vector *mpvec)
1461 {
1462         int i;
1463         int fwd = 0;
1464         struct keyword * kw;
1465         struct keyword * rootkw;
1466         struct multipath *mpp = NULL;
1467
1468         if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
1469                 return 0;
1470
1471         rootkw = find_keyword(conf->keywords, NULL, "multipath");
1472         if (!rootkw)
1473                 return 0;
1474
1475         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
1476         if (fwd >= len)
1477                 return len;
1478         iterate_sub_keywords(rootkw, kw, i) {
1479                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1480                                 kw, mpe);
1481                 if (fwd >= len)
1482                         return len;
1483         }
1484         /*
1485          * This mpp doesn't have alias defined. Add the alias in a comment.
1486          */
1487         if (mpp != NULL && strcmp(mpp->alias, mpp->wwid)) {
1488                 fwd += snprintf(buff + fwd, len - fwd, "\t\t# alias \"%s\"\n",
1489                                 mpp->alias);
1490                 if (fwd >= len)
1491                         return len;
1492         }
1493         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1494         if (fwd >= len)
1495                 return len;
1496         return fwd;
1497 }
1498
1499 static int snprint_mptable(const struct config *conf,
1500                            char *buff, int len, const struct _vector *mpvec)
1501 {
1502         int fwd = 0;
1503         int i;
1504         struct mpentry * mpe;
1505         struct keyword * rootkw;
1506
1507         rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1508         if (!rootkw)
1509                 return 0;
1510
1511         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
1512         if (fwd >= len)
1513                 return len;
1514         vector_foreach_slot (conf->mptable, mpe, i) {
1515                 fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe, mpvec);
1516                 if (fwd >= len)
1517                         return len;
1518         }
1519         if (mpvec != NULL) {
1520                 struct multipath *mpp;
1521
1522                 vector_foreach_slot(mpvec, mpp, i) {
1523                         if (find_mpe(conf->mptable, mpp->wwid) != NULL)
1524                                 continue;
1525
1526                         fwd += snprintf(buff + fwd, len - fwd,
1527                                         "\tmultipath {\n");
1528                         if (fwd >= len)
1529                                 return len;
1530                         fwd += snprintf(buff + fwd, len - fwd,
1531                                         "\t\twwid \"%s\"\n", mpp->wwid);
1532                         if (fwd >= len)
1533                                 return len;
1534                         /*
1535                          * This mpp doesn't have alias defined in
1536                          * multipath.conf - otherwise find_mpe would have
1537                          * found it. Add the alias in a comment.
1538                          */
1539                         if (strcmp(mpp->alias, mpp->wwid)) {
1540                                 fwd += snprintf(buff + fwd, len - fwd,
1541                                                 "\t\t# alias \"%s\"\n",
1542                                                 mpp->alias);
1543                                 if (fwd >= len)
1544                                         return len;
1545                         }
1546                         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1547                         if (fwd >= len)
1548                                 return len;
1549                 }
1550         }
1551         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1552         if (fwd >= len)
1553                 return len;
1554         return fwd;
1555 }
1556
1557 static int snprint_overrides(const struct config *conf, char * buff, int len,
1558                              const struct hwentry *overrides)
1559 {
1560         int fwd = 0;
1561         int i;
1562         struct keyword *rootkw;
1563         struct keyword *kw;
1564
1565         rootkw = find_keyword(conf->keywords, NULL, "overrides");
1566         if (!rootkw)
1567                 return 0;
1568
1569         fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
1570         if (fwd >= len)
1571                 return len;
1572         if (!overrides)
1573                 goto out;
1574         iterate_sub_keywords(rootkw, kw, i) {
1575                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1576                                        kw, NULL);
1577                 if (fwd >= len)
1578                         return len;
1579         }
1580 out:
1581         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1582         if (fwd >= len)
1583                 return len;
1584         return fwd;
1585 }
1586
1587 static int snprint_defaults(const struct config *conf, char *buff, int len)
1588 {
1589         int fwd = 0;
1590         int i;
1591         struct keyword *rootkw;
1592         struct keyword *kw;
1593
1594         rootkw = find_keyword(conf->keywords, NULL, "defaults");
1595         if (!rootkw)
1596                 return 0;
1597
1598         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
1599         if (fwd >= len)
1600                 return len;
1601
1602         iterate_sub_keywords(rootkw, kw, i) {
1603                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1604                                 kw, NULL);
1605                 if (fwd >= len)
1606                         return len;
1607         }
1608         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1609         if (fwd >= len)
1610                 return len;
1611         return fwd;
1612 }
1613
1614 static int
1615 snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
1616 {
1617         int threshold = MAX_LINE_LEN;
1618         struct blentry * ble;
1619         int pos;
1620         int i;
1621
1622         pos = *fwd;
1623         if (!VECTOR_SIZE(*vec)) {
1624                 if ((len - pos - threshold) <= 0)
1625                         return 0;
1626                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1627         } else vector_foreach_slot (*vec, ble, i) {
1628                 if ((len - pos - threshold) <= 0)
1629                         return 0;
1630                 if (ble->origin == ORIGIN_CONFIG)
1631                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1632                 else if (ble->origin == ORIGIN_DEFAULT)
1633                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1634                 pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
1635         }
1636
1637         *fwd = pos;
1638         return pos;
1639 }
1640
1641 static int
1642 snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
1643 {
1644         int threshold = MAX_LINE_LEN;
1645         struct blentry_device * bled;
1646         int pos;
1647         int i;
1648
1649         pos = *fwd;
1650         if (!VECTOR_SIZE(*vec)) {
1651                 if ((len - pos - threshold) <= 0)
1652                         return 0;
1653                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1654         } else vector_foreach_slot (*vec, bled, i) {
1655                 if ((len - pos - threshold) <= 0)
1656                         return 0;
1657                 if (bled->origin == ORIGIN_CONFIG)
1658                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1659                 else if (bled->origin == ORIGIN_DEFAULT)
1660                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1661                 pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
1662         }
1663
1664         *fwd = pos;
1665         return pos;
1666 }
1667
1668 int snprint_blacklist_report(struct config *conf, char *buff, int len)
1669 {
1670         int threshold = MAX_LINE_LEN;
1671         int fwd = 0;
1672
1673         if ((len - fwd - threshold) <= 0)
1674                 return len;
1675         fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
1676                                                "- blacklist:\n");
1677         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
1678                 return len;
1679
1680         if ((len - fwd - threshold) <= 0)
1681                 return len;
1682         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1683         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
1684                 return len;
1685
1686         if ((len - fwd - threshold) <= 0)
1687                 return len;
1688         fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
1689                                                "- blacklist:\n");
1690         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
1691                 return len;
1692
1693         if ((len - fwd - threshold) <= 0)
1694                 return len;
1695         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1696         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
1697                 return len;
1698
1699         if ((len - fwd - threshold) <= 0)
1700                 return len;
1701         fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n"
1702                                                "- blacklist:\n");
1703         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol))
1704                 return len;
1705
1706         if ((len - fwd - threshold) <= 0)
1707                 return len;
1708         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1709         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0)
1710                 return len;
1711
1712         if ((len - fwd - threshold) <= 0)
1713                 return len;
1714         fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
1715                                                "- blacklist:\n");
1716         if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
1717                 return len;
1718
1719         if ((len - fwd - threshold) <= 0)
1720                 return len;
1721         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1722         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
1723                 return len;
1724
1725         if ((len - fwd - threshold) <= 0)
1726                 return len;
1727         fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
1728                                                "- blacklist:\n");
1729         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
1730                 return len;
1731
1732         if ((len - fwd - threshold) <= 0)
1733                 return len;
1734         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1735         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
1736                 return len;
1737
1738         if (fwd > len)
1739                 return len;
1740         return fwd;
1741 }
1742
1743 static int snprint_blacklist(const struct config *conf, char *buff, int len)
1744 {
1745         int i;
1746         struct blentry * ble;
1747         struct blentry_device * bled;
1748         int fwd = 0;
1749         struct keyword *rootkw;
1750         struct keyword *kw;
1751
1752         rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1753         if (!rootkw)
1754                 return 0;
1755
1756         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
1757         if (fwd >= len)
1758                 return len;
1759
1760         vector_foreach_slot (conf->blist_devnode, ble, i) {
1761                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1762                 if (!kw)
1763                         return 0;
1764                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1765                                        kw, ble);
1766                 if (fwd >= len)
1767                         return len;
1768         }
1769         vector_foreach_slot (conf->blist_wwid, ble, i) {
1770                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1771                 if (!kw)
1772                         return 0;
1773                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1774                                        kw, ble);
1775                 if (fwd >= len)
1776                         return len;
1777         }
1778         vector_foreach_slot (conf->blist_property, ble, i) {
1779                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1780                 if (!kw)
1781                         return 0;
1782                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1783                                        kw, ble);
1784                 if (fwd >= len)
1785                         return len;
1786         }
1787         vector_foreach_slot (conf->blist_protocol, ble, i) {
1788                 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1789                 if (!kw)
1790                         return 0;
1791                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1792                                        kw, ble);
1793                 if (fwd >= len)
1794                         return len;
1795         }
1796         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1797         if (!rootkw)
1798                 return 0;
1799
1800         vector_foreach_slot (conf->blist_device, bled, i) {
1801                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1802                 if (fwd >= len)
1803                         return len;
1804                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1805                 if (!kw)
1806                         return 0;
1807                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1808                                        kw, bled);
1809                 if (fwd >= len)
1810                         return len;
1811                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1812                 if (!kw)
1813                         return 0;
1814                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1815                                        kw, bled);
1816                 if (fwd >= len)
1817                         return len;
1818                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1819                 if (fwd >= len)
1820                         return len;
1821         }
1822         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1823         if (fwd >= len)
1824                 return len;
1825         return fwd;
1826 }
1827
1828 static int snprint_blacklist_except(const struct config *conf,
1829                                     char *buff, int len)
1830 {
1831         int i;
1832         struct blentry * ele;
1833         struct blentry_device * eled;
1834         int fwd = 0;
1835         struct keyword *rootkw;
1836         struct keyword *kw;
1837
1838         rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1839         if (!rootkw)
1840                 return 0;
1841
1842         fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
1843         if (fwd >= len)
1844                 return len;
1845
1846         vector_foreach_slot (conf->elist_devnode, ele, i) {
1847                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1848                 if (!kw)
1849                         return 0;
1850                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1851                                        kw, ele);
1852                 if (fwd >= len)
1853                         return len;
1854         }
1855         vector_foreach_slot (conf->elist_wwid, ele, i) {
1856                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1857                 if (!kw)
1858                         return 0;
1859                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1860                                        kw, ele);
1861                 if (fwd >= len)
1862                         return len;
1863         }
1864         vector_foreach_slot (conf->elist_property, ele, i) {
1865                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1866                 if (!kw)
1867                         return 0;
1868                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1869                                        kw, ele);
1870                 if (fwd >= len)
1871                         return len;
1872         }
1873         vector_foreach_slot (conf->elist_protocol, ele, i) {
1874                 kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
1875                 if (!kw)
1876                         return 0;
1877                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1878                                        kw, ele);
1879                 if (fwd >= len)
1880                         return len;
1881         }
1882         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1883         if (!rootkw)
1884                 return 0;
1885
1886         vector_foreach_slot (conf->elist_device, eled, i) {
1887                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1888                 if (fwd >= len)
1889                         return len;
1890                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1891                 if (!kw)
1892                         return 0;
1893                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1894                                        kw, eled);
1895                 if (fwd >= len)
1896                         return len;
1897                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1898                 if (!kw)
1899                         return 0;
1900                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1901                                        kw, eled);
1902                 if (fwd >= len)
1903                         return len;
1904                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1905                 if (fwd >= len)
1906                         return len;
1907         }
1908         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1909         if (fwd >= len)
1910                 return len;
1911         return fwd;
1912 }
1913
1914 char *snprint_config(const struct config *conf, int *len,
1915                      const struct _vector *hwtable, const struct _vector *mpvec)
1916 {
1917         char *reply;
1918         /* built-in config is >20kB already */
1919         unsigned int maxlen = 32768;
1920
1921         for (reply = NULL; maxlen <= UINT_MAX/2; maxlen *= 2) {
1922                 char *c, *tmp = reply;
1923
1924                 reply = REALLOC(reply, maxlen);
1925                 if (!reply) {
1926                         if (tmp)
1927                                 free(tmp);
1928                         return NULL;
1929                 }
1930
1931                 c = reply + snprint_defaults(conf, reply, maxlen);
1932                 if ((c - reply) == maxlen)
1933                         continue;
1934
1935                 c += snprint_blacklist(conf, c, reply + maxlen - c);
1936                 if ((c - reply) == maxlen)
1937                         continue;
1938
1939                 c += snprint_blacklist_except(conf, c, reply + maxlen - c);
1940                 if ((c - reply) == maxlen)
1941                         continue;
1942
1943                 c += snprint_hwtable(conf, c, reply + maxlen - c,
1944                                      hwtable ? hwtable : conf->hwtable);
1945                 if ((c - reply) == maxlen)
1946                         continue;
1947
1948                 c += snprint_overrides(conf, c, reply + maxlen - c,
1949                                        conf->overrides);
1950                 if ((c - reply) == maxlen)
1951                         continue;
1952
1953                 if (VECTOR_SIZE(conf->mptable) > 0 ||
1954                     (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
1955                         c += snprint_mptable(conf, c, reply + maxlen - c,
1956                                              mpvec);
1957
1958                 if ((c - reply) < maxlen) {
1959                         if (len)
1960                                 *len = c - reply;
1961                         return reply;
1962                 }
1963         }
1964
1965         free(reply);
1966         return NULL;
1967 }
1968
1969 int snprint_status(char *buff, int len, const struct vectors *vecs)
1970 {
1971         int fwd = 0;
1972         int i;
1973         unsigned int count[PATH_MAX_STATE] = {0};
1974         struct path * pp;
1975
1976         vector_foreach_slot (vecs->pathvec, pp, i) {
1977                 count[pp->state]++;
1978         }
1979         fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
1980         for (i=0; i<PATH_MAX_STATE; i++) {
1981                 if (!count[i])
1982                         continue;
1983                 fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
1984                                 checker_state_name(i), count[i]);
1985         }
1986
1987         int monitored_count = 0;
1988
1989         vector_foreach_slot(vecs->pathvec, pp, i)
1990                 if (pp->fd >= 0)
1991                         monitored_count++;
1992         fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
1993                         monitored_count, is_uevent_busy()? "True" : "False");
1994
1995         if (fwd >= len)
1996                 return len;
1997         return fwd;
1998 }
1999
2000 int snprint_devices(struct config *conf, char * buff, int len,
2001                     const struct vectors *vecs)
2002 {
2003         DIR *blkdir;
2004         struct dirent *blkdev;
2005         struct stat statbuf;
2006         char devpath[PATH_MAX];
2007         char *devptr;
2008         int threshold = MAX_LINE_LEN;
2009         int fwd = 0;
2010         int r;
2011
2012         struct path * pp;
2013
2014         if (!(blkdir = opendir("/sys/block")))
2015                 return 1;
2016
2017         if ((len - fwd - threshold) <= 0) {
2018                 closedir(blkdir);
2019                 return len;
2020         }
2021         fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
2022
2023         strcpy(devpath,"/sys/block/");
2024         while ((blkdev = readdir(blkdir)) != NULL) {
2025                 if ((strcmp(blkdev->d_name,".") == 0) ||
2026                     (strcmp(blkdev->d_name,"..") == 0))
2027                         continue;
2028
2029                 devptr = devpath + 11;
2030                 *devptr = '\0';
2031                 strncat(devptr, blkdev->d_name, PATH_MAX-12);
2032                 if (stat(devpath, &statbuf) < 0)
2033                         continue;
2034
2035                 if (S_ISDIR(statbuf.st_mode) == 0)
2036                         continue;
2037
2038                 if ((len - fwd - threshold)  <= 0) {
2039                         closedir(blkdir);
2040                         return len;
2041                 }
2042
2043                 fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
2044                 pp = find_path_by_dev(vecs->pathvec, devptr);
2045                 if (!pp) {
2046                         r = filter_devnode(conf->blist_devnode,
2047                                            conf->elist_devnode, devptr);
2048                         if (r > 0)
2049                                 fwd += snprintf(buff + fwd, len - fwd,
2050                                                 " devnode blacklisted, unmonitored");
2051                         else if (r <= 0)
2052                                 fwd += snprintf(buff + fwd, len - fwd,
2053                                                 " devnode whitelisted, unmonitored");
2054                 } else
2055                         fwd += snprintf(buff + fwd, len - fwd,
2056                                         " devnode whitelisted, monitored");
2057                 fwd += snprintf(buff + fwd, len - fwd, "\n");
2058         }
2059         closedir(blkdir);
2060
2061         if (fwd >= len)
2062                 return len;
2063         return fwd;
2064 }
2065
2066 /*
2067  * stdout printing helpers
2068  */
2069 void print_path(struct path *pp, char *style)
2070 {
2071         char line[MAX_LINE_LEN];
2072
2073         memset(&line[0], 0, MAX_LINE_LEN);
2074         snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
2075         printf("%s", line);
2076 }
2077
2078 void print_all_paths(vector pathvec, int banner)
2079 {
2080         print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
2081 }
2082
2083 void print_all_paths_custo(vector pathvec, int banner, char *fmt)
2084 {
2085         int i;
2086         struct path * pp;
2087         char line[MAX_LINE_LEN];
2088
2089         if (!VECTOR_SIZE(pathvec)) {
2090                 if (banner)
2091                         fprintf(stdout, "===== no paths =====\n");
2092                 return;
2093         }
2094
2095         if (banner)
2096                 fprintf(stdout, "===== paths list =====\n");
2097
2098         get_path_layout(pathvec, 1);
2099         snprint_path_header(line, MAX_LINE_LEN, fmt);
2100         fprintf(stdout, "%s", line);
2101
2102         vector_foreach_slot (pathvec, pp, i)
2103                 print_path(pp, fmt);
2104 }