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