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