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