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