libmultipath: Fix information not shown when first path is down.
[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 "print.h"
20 #include "dmparser.h"
21 #include "config.h"
22 #include "configure.h"
23 #include "pgpolicies.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
32 #define MAX(x,y) (x > y) ? x : y
33 #define TAIL     (line + len - 1 - c)
34 #define NOPAD    s = c
35 #define PAD(x)   while ((int)(c - s) < (x) && (c < (line + len - 1))) \
36                         *c++ = ' '; s = c
37 #define ENDLINE \
38                 if (c > line) \
39                         line[c - line - 1] = '\n'
40 #define PRINT(var, size, format, args...)      \
41                 fwd = snprintf(var, size, format, ##args); \
42                  c += (fwd >= size) ? size : fwd;
43
44 /*
45  * information printing helpers
46  */
47 static int
48 snprint_str (char * buff, size_t len, const char * str)
49 {
50         return snprintf(buff, len, "%s", str);
51 }
52
53 static int
54 snprint_int (char * buff, size_t len, int val)
55 {
56         return snprintf(buff, len, "%i", val);
57 }
58
59 static int
60 snprint_uint (char * buff, size_t len, unsigned int val)
61 {
62         return snprintf(buff, len, "%u", val);
63 }
64
65 static int
66 snprint_size (char * buff, size_t len, unsigned long long size)
67 {
68         float s = (float)(size >> 1); /* start with KB */
69         char fmt[6] = {};
70         char units[] = {'K','M','G','T','P'};
71         char *u = units;
72
73         while (s >= 1024 && *u != 'P') {
74                 s = s / 1024;
75                 u++;
76         }
77         if (s < 10)
78                 snprintf(fmt, 6, "%%.1f%c", *u);
79         else
80                 snprintf(fmt, 6, "%%.0f%c", *u);
81
82         return snprintf(buff, len, fmt, s);
83 }
84
85 /*
86  * multipath info printing functions
87  */
88 static int
89 snprint_name (char * buff, size_t len, struct multipath * mpp)
90 {
91         if (mpp->alias)
92                 return snprintf(buff, len, "%s", mpp->alias);
93         else
94                 return snprintf(buff, len, "%s", mpp->wwid);
95 }
96
97 static int
98 snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
99 {
100         if (mpp->dmi)
101                 return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
102         else
103                 return snprintf(buff, len, "undef");
104 }
105
106 static int
107 snprint_ro (char * buff, size_t len, struct multipath * mpp)
108 {
109         if (!mpp->dmi)
110                 return snprintf(buff, len, "undef");
111         if (mpp->dmi->read_only)
112                 return snprintf(buff, len, "ro");
113         else
114                 return snprintf(buff, len, "rw");
115 }
116
117 static int
118 snprint_progress (char * buff, size_t len, int cur, int total)
119 {
120         char * c = buff;
121         char * end = buff + len;
122
123         if (total > 0) {
124                 int i = PROGRESS_LEN * cur / total;
125                 int j = PROGRESS_LEN - i;
126
127                 while (i-- > 0) {
128                         c += snprintf(c, len, "X");
129                         if ((len = (end - c)) <= 1) goto out;
130                 }
131
132                 while (j-- > 0) {
133                         c += snprintf(c, len,  ".");
134                         if ((len = (end - c)) <= 1) goto out;
135                 }
136         }
137
138         c += snprintf(c, len, " %i/%i", cur, total);
139
140 out:
141         buff[c - buff + 1] = '\0';
142         return (c - buff + 1);
143 }
144
145 static int
146 snprint_failback (char * buff, size_t len, struct multipath * mpp)
147 {
148         if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
149                 return snprintf(buff, len, "immediate");
150         if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
151                 return snprintf(buff, len, "followover");
152
153         if (!mpp->failback_tick)
154                 return snprintf(buff, len, "-");
155         else
156                 return snprint_progress(buff, len, mpp->failback_tick,
157                                         mpp->pgfailback);
158 }
159
160 static int
161 snprint_queueing (char * buff, size_t len, struct multipath * mpp)
162 {
163         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
164                 return snprintf(buff, len, "off");
165         else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
166                 return snprintf(buff, len, "on");
167         else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
168                 return snprintf(buff, len, "-");
169         else if (mpp->no_path_retry > 0) {
170                 if (mpp->retry_tick)
171                         return snprintf(buff, len, "%i sec",
172                                         mpp->retry_tick);
173                 else
174                         return snprintf(buff, len, "%i chk",
175                                         mpp->no_path_retry);
176         }
177         return 0;
178 }
179
180 static int
181 snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
182 {
183         return snprint_int(buff, len, mpp->nr_active);
184 }
185
186 static int
187 snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
188 {
189         if (mpp->dmi && mpp->dmi->suspended)
190                 return snprintf(buff, len, "suspend");
191         else
192                 return snprintf(buff, len, "active");
193 }
194
195 static int
196 snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
197 {
198         return snprint_size(buff, len, mpp->size);
199 }
200
201 static int
202 snprint_features (char * buff, size_t len, struct multipath * mpp)
203 {
204         return snprint_str(buff, len, mpp->features);
205 }
206
207 static int
208 snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
209 {
210         return snprint_str(buff, len, mpp->hwhandler);
211 }
212
213 static int
214 snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
215 {
216         return snprint_uint(buff, len, mpp->stat_path_failures);
217 }
218
219 static int
220 snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
221 {
222         return snprint_uint(buff, len, mpp->stat_switchgroup);
223 }
224
225 static int
226 snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
227 {
228         return snprint_uint(buff, len, mpp->stat_map_loads);
229 }
230
231 static int
232 snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
233 {
234         return snprint_uint(buff, len, mpp->stat_total_queueing_time);
235 }
236
237 static int
238 snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
239 {
240         return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
241 }
242
243 static int
244 snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
245 {
246         return snprint_str(buff, len, mpp->wwid);
247 }
248
249 static int
250 snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
251 {
252         struct pathgroup * pgp;
253         struct path * pp;
254         int i, j;
255
256         vector_foreach_slot(mpp->pg, pgp, i) {
257                 if (!pgp)
258                         continue;
259                 vector_foreach_slot(pgp->paths, pp, j) {
260                         if (strlen(pp->vendor_id) && strlen(pp->product_id))
261                                 return snprintf(buff, len, "%s,%s",
262                                                 pp->vendor_id, pp->product_id);
263                 }
264         }
265         return snprintf(buff, len, "##,##");
266 }
267
268 static int
269 snprint_action (char * buff, size_t len, struct multipath * mpp)
270 {
271         switch (mpp->action) {
272         case ACT_REJECT:
273                 return snprint_str(buff, len, ACT_REJECT_STR);
274         case ACT_RENAME:
275                 return snprint_str(buff, len, ACT_RENAME_STR);
276         case ACT_RELOAD:
277                 return snprint_str(buff, len, ACT_RELOAD_STR);
278         case ACT_CREATE:
279                 return snprint_str(buff, len, ACT_CREATE_STR);
280         case ACT_SWITCHPG:
281                 return snprint_str(buff, len, ACT_SWITCHPG_STR);
282         default:
283                 return 0;
284         }
285 }
286
287 /*
288  * path info printing functions
289  */
290 static int
291 snprint_path_uuid (char * buff, size_t len, struct path * pp)
292 {
293         return snprint_str(buff, len, pp->wwid);
294 }
295
296 static int
297 snprint_hcil (char * buff, size_t len, struct path * pp)
298 {
299         if (!pp || pp->sg_id.host_no < 0)
300                 return snprintf(buff, len, "#:#:#:#");
301
302         return snprintf(buff, len, "%i:%i:%i:%i",
303                         pp->sg_id.host_no,
304                         pp->sg_id.channel,
305                         pp->sg_id.scsi_id,
306                         pp->sg_id.lun);
307 }
308
309 static int
310 snprint_dev (char * buff, size_t len, struct path * pp)
311 {
312         if (!pp || !strlen(pp->dev))
313                 return snprintf(buff, len, "-");
314         else
315                 return snprint_str(buff, len, pp->dev);
316 }
317
318 static int
319 snprint_dev_t (char * buff, size_t len, struct path * pp)
320 {
321         if (!pp || !strlen(pp->dev))
322                 return snprintf(buff, len, "#:#");
323         else
324                 return snprint_str(buff, len, pp->dev_t);
325 }
326
327 static int
328 snprint_offline (char * buff, size_t len, struct path * pp)
329 {
330         if (!pp)
331                 return snprintf(buff, len, "unknown");
332         else if (pp->offline)
333                 return snprintf(buff, len, "offline");
334         else
335                 return snprintf(buff, len, "running");
336 }
337
338 static int
339 snprint_chk_state (char * buff, size_t len, struct path * pp)
340 {
341         if (!pp)
342                 return snprintf(buff, len, "undef");
343
344         switch (pp->state) {
345         case PATH_UP:
346                 return snprintf(buff, len, "ready");
347         case PATH_DOWN:
348                 return snprintf(buff, len, "faulty");
349         case PATH_SHAKY:
350                 return snprintf(buff, len, "shaky");
351         case PATH_GHOST:
352                 return snprintf(buff, len, "ghost");
353         case PATH_PENDING:
354                 return snprintf(buff, len, "i/o pending");
355         case PATH_TIMEOUT:
356                 return snprintf(buff, len, "i/o timeout");
357         case PATH_DELAYED:
358                 return snprintf(buff, len, "delayed");
359         default:
360                 return snprintf(buff, len, "undef");
361         }
362 }
363
364 static int
365 snprint_dm_path_state (char * buff, size_t len, struct path * pp)
366 {
367         if (!pp)
368                 return snprintf(buff, len, "undef");
369
370         switch (pp->dmstate) {
371         case PSTATE_ACTIVE:
372                 return snprintf(buff, len, "active");
373         case PSTATE_FAILED:
374                 return snprintf(buff, len, "failed");
375         default:
376                 return snprintf(buff, len, "undef");
377         }
378 }
379
380 static int
381 snprint_vpr (char * buff, size_t len, struct path * pp)
382 {
383         return snprintf(buff, len, "%s,%s",
384                         pp->vendor_id, pp->product_id);
385 }
386
387 static int
388 snprint_next_check (char * buff, size_t len, struct path * pp)
389 {
390         if (!pp || !pp->mpp)
391                 return snprintf(buff, len, "orphan");
392
393         return snprint_progress(buff, len, pp->tick, pp->checkint);
394 }
395
396 static int
397 snprint_pri (char * buff, size_t len, struct path * pp)
398 {
399         return snprint_int(buff, len, pp ? pp->priority : -1);
400 }
401
402 static int
403 snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
404 {
405         return snprint_str(buff, len, pgp->selector);
406 }
407
408 static int
409 snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
410 {
411         /*
412          * path group priority is not updated for every path prio change,
413          * but only on switch group code path.
414          *
415          * Printing is another reason to update.
416          */
417         path_group_prio_update(pgp);
418         return snprint_int(buff, len, pgp->priority);
419 }
420
421 static int
422 snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
423 {
424         switch (pgp->status) {
425         case PGSTATE_ENABLED:
426                 return snprintf(buff, len, "enabled");
427         case PGSTATE_DISABLED:
428                 return snprintf(buff, len, "disabled");
429         case PGSTATE_ACTIVE:
430                 return snprintf(buff, len, "active");
431         default:
432                 return snprintf(buff, len, "undef");
433         }
434 }
435
436 static int
437 snprint_path_size (char * buff, size_t len, struct path * pp)
438 {
439         return snprint_size(buff, len, pp->size);
440 }
441
442 static int
443 snprint_path_serial (char * buff, size_t len, struct path * pp)
444 {
445         return snprint_str(buff, len, pp->serial);
446 }
447
448 static int
449 snprint_path_mpp (char * buff, size_t len, struct path * pp)
450 {
451         if (!pp->mpp)
452                 return snprintf(buff, len, "[orphan]");
453         if (!pp->mpp->alias)
454                 return snprintf(buff, len, "[unknown]");
455         return snprint_str(buff, len, pp->mpp->alias);
456 }
457
458 static int
459 snprint_host_attr (char * buff, size_t len, struct path * pp, char *attr)
460 {
461         struct udev_device *host_dev = NULL;
462         char host_id[32];
463         const char *value = NULL;
464         int ret;
465
466         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
467                 return snprintf(buff, len, "[undef]");
468         sprintf(host_id, "host%d", pp->sg_id.host_no);
469         host_dev = udev_device_new_from_subsystem_sysname(conf->udev, "fc_host",
470                                                           host_id);
471         if (!host_dev) {
472                 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
473                 goto out;
474         }
475         value = udev_device_get_sysattr_value(host_dev, attr);
476         if (value)
477                 ret = snprint_str(buff, len, value);
478         udev_device_unref(host_dev);
479 out:
480         if (!value)
481                 ret = snprintf(buff, len, "[unknown]");
482         return ret;
483 }
484
485 static int
486 snprint_host_wwnn (char * buff, size_t len, struct path * pp)
487 {
488         return snprint_host_attr(buff, len, pp, "node_name");
489 }
490
491 static int
492 snprint_host_wwpn (char * buff, size_t len, struct path * pp)
493 {
494         return snprint_host_attr(buff, len, pp, "port_name");
495 }
496
497 static int
498 snprint_tgt_wwpn (char * buff, size_t len, struct path * pp)
499 {
500         struct udev_device *rport_dev = NULL;
501         char rport_id[32];
502         const char *value = NULL;
503         int ret;
504
505         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
506                 return snprintf(buff, len, "[undef]");
507         sprintf(rport_id, "rport-%d:%d-%d",
508                 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
509         rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
510                                 "fc_remote_ports", rport_id);
511         if (!rport_dev) {
512                 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
513                         rport_id);
514                 goto out;
515         }
516         value = udev_device_get_sysattr_value(rport_dev, "port_name");
517         if (value)
518                 ret = snprint_str(buff, len, value);
519         udev_device_unref(rport_dev);
520 out:
521         if (!value)
522                 ret = snprintf(buff, len, "[unknown]");
523         return ret;
524 }
525
526
527 static int
528 snprint_tgt_wwnn (char * buff, size_t len, struct path * pp)
529 {
530         if (pp->tgt_node_name[0] == '\0')
531                 return snprintf(buff, len, "[undef]");
532         return snprint_str(buff, len, pp->tgt_node_name);
533 }
534
535 static int
536 snprint_host_adapter (char * buff, size_t len, struct path * pp)
537 {
538         char adapter[SLOT_NAME_SIZE];
539
540         if (sysfs_get_host_adapter_name(pp, adapter))
541                 return snprintf(buff, len, "[undef]");
542         return snprint_str(buff, len, adapter);
543 }
544
545 static int
546 snprint_path_checker (char * buff, size_t len, struct path * pp)
547 {
548         struct checker * c = &pp->checker;
549         return snprint_str(buff, len, c->name);
550 }
551
552 struct multipath_data mpd[] = {
553         {'n', "name",          0, snprint_name},
554         {'w', "uuid",          0, snprint_multipath_uuid},
555         {'d', "sysfs",         0, snprint_sysfs},
556         {'F', "failback",      0, snprint_failback},
557         {'Q', "queueing",      0, snprint_queueing},
558         {'N', "paths",         0, snprint_nb_paths},
559         {'r', "write_prot",    0, snprint_ro},
560         {'t', "dm-st",         0, snprint_dm_map_state},
561         {'S', "size",          0, snprint_multipath_size},
562         {'f', "features",      0, snprint_features},
563         {'h', "hwhandler",     0, snprint_hwhandler},
564         {'A', "action",        0, snprint_action},
565         {'0', "path_faults",   0, snprint_path_faults},
566         {'1', "switch_grp",    0, snprint_switch_grp},
567         {'2', "map_loads",     0, snprint_map_loads},
568         {'3', "total_q_time",  0, snprint_total_q_time},
569         {'4', "q_timeouts",    0, snprint_q_timeouts},
570         {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
571         {0, NULL, 0 , NULL}
572 };
573
574 struct path_data pd[] = {
575         {'w', "uuid",          0, snprint_path_uuid},
576         {'i', "hcil",          0, snprint_hcil},
577         {'d', "dev",           0, snprint_dev},
578         {'D', "dev_t",         0, snprint_dev_t},
579         {'t', "dm_st",         0, snprint_dm_path_state},
580         {'o', "dev_st",        0, snprint_offline},
581         {'T', "chk_st",        0, snprint_chk_state},
582         {'s', "vend/prod/rev", 0, snprint_vpr},
583         {'c', "checker",       0, snprint_path_checker},
584         {'C', "next_check",    0, snprint_next_check},
585         {'p', "pri",           0, snprint_pri},
586         {'S', "size",          0, snprint_path_size},
587         {'z', "serial",        0, snprint_path_serial},
588         {'m', "multipath",     0, snprint_path_mpp},
589         {'N', "host WWNN",     0, snprint_host_wwnn},
590         {'n', "target WWNN",   0, snprint_tgt_wwnn},
591         {'R', "host WWPN",     0, snprint_host_wwpn},
592         {'r', "target WWPN",   0, snprint_tgt_wwpn},
593         {'a', "host adapter",  0, snprint_host_adapter},
594         {0, NULL, 0 , NULL}
595 };
596
597 struct pathgroup_data pgd[] = {
598         {'s', "selector",      0, snprint_pg_selector},
599         {'p', "pri",           0, snprint_pg_pri},
600         {'t', "dm_st",         0, snprint_pg_state},
601         {0, NULL, 0 , NULL}
602 };
603
604 int
605 snprint_wildcards (char * buff, int len)
606 {
607         int i, fwd = 0;
608
609         fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
610         for (i = 0; mpd[i].header; i++)
611                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
612                                 mpd[i].wildcard, mpd[i].header);
613         fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
614         for (i = 0; pd[i].header; i++)
615                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
616                                 pd[i].wildcard, pd[i].header);
617         fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
618         for (i = 0; pgd[i].header; i++)
619                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
620                                 pgd[i].wildcard, pgd[i].header);
621         return fwd;
622 }
623
624 void
625 get_path_layout (vector pathvec, int header)
626 {
627         int i, j;
628         char buff[MAX_FIELD_LEN];
629         struct path * pp;
630
631         for (j = 0; pd[j].header; j++) {
632                 if (header)
633                         pd[j].width = strlen(pd[j].header);
634                 else
635                         pd[j].width = 0;
636
637                 vector_foreach_slot (pathvec, pp, i) {
638                         pd[j].snprint(buff, MAX_FIELD_LEN, pp);
639                         pd[j].width = MAX(pd[j].width, strlen(buff));
640                 }
641         }
642 }
643
644 static void
645 reset_multipath_layout (void)
646 {
647         int i;
648
649         for (i = 0; mpd[i].header; i++)
650                 mpd[i].width = 0;
651 }
652
653 void
654 get_multipath_layout (vector mpvec, int header)
655 {
656         int i, j;
657         char buff[MAX_FIELD_LEN];
658         struct multipath * mpp;
659
660         for (j = 0; mpd[j].header; j++) {
661                 if (header)
662                         mpd[j].width = strlen(mpd[j].header);
663                 else
664                         mpd[j].width = 0;
665
666                 vector_foreach_slot (mpvec, mpp, i) {
667                         mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
668                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
669                 }
670         }
671 }
672
673 static struct multipath_data *
674 mpd_lookup(char wildcard)
675 {
676         int i;
677
678         for (i = 0; mpd[i].header; i++)
679                 if (mpd[i].wildcard == wildcard)
680                         return &mpd[i];
681
682         return NULL;
683 }
684
685 static struct path_data *
686 pd_lookup(char wildcard)
687 {
688         int i;
689
690         for (i = 0; pd[i].header; i++)
691                 if (pd[i].wildcard == wildcard)
692                         return &pd[i];
693
694         return NULL;
695 }
696
697 static struct pathgroup_data *
698 pgd_lookup(char wildcard)
699 {
700         int i;
701
702         for (i = 0; pgd[i].header; i++)
703                 if (pgd[i].wildcard == wildcard)
704                         return &pgd[i];
705
706         return NULL;
707 }
708
709 int
710 snprint_multipath_header (char * line, int len, char * format)
711 {
712         char * c = line;   /* line cursor */
713         char * s = line;   /* for padding */
714         char * f = format; /* format string cursor */
715         int fwd;
716         struct multipath_data * data;
717
718         memset(line, 0, len);
719
720         do {
721                 if (!TAIL)
722                         break;
723
724                 if (*f != '%') {
725                         *c++ = *f;
726                         NOPAD;
727                         continue;
728                 }
729                 f++;
730
731                 if (!(data = mpd_lookup(*f)))
732                         continue; /* unknown wildcard */
733
734                 PRINT(c, TAIL, "%s", data->header);
735                 PAD(data->width);
736         } while (*f++);
737
738         ENDLINE;
739         return (c - line);
740 }
741
742 int
743 snprint_multipath (char * line, int len, char * format,
744              struct multipath * mpp)
745 {
746         char * c = line;   /* line cursor */
747         char * s = line;   /* for padding */
748         char * f = format; /* format string cursor */
749         int fwd;
750         struct multipath_data * data;
751         char buff[MAX_FIELD_LEN] = {};
752
753         memset(line, 0, len);
754
755         do {
756                 if (!TAIL)
757                         break;
758
759                 if (*f != '%') {
760                         *c++ = *f;
761                         NOPAD;
762                         continue;
763                 }
764                 f++;
765
766                 if (!(data = mpd_lookup(*f)))
767                         continue;
768
769                 data->snprint(buff, MAX_FIELD_LEN, mpp);
770                 PRINT(c, TAIL, "%s", buff);
771                 PAD(data->width);
772                 buff[0] = '\0';
773         } while (*f++);
774
775         ENDLINE;
776         return (c - line);
777 }
778
779 int
780 snprint_path_header (char * line, int len, char * format)
781 {
782         char * c = line;   /* line cursor */
783         char * s = line;   /* for padding */
784         char * f = format; /* format string cursor */
785         int fwd;
786         struct path_data * data;
787
788         memset(line, 0, len);
789
790         do {
791                 if (!TAIL)
792                         break;
793
794                 if (*f != '%') {
795                         *c++ = *f;
796                         NOPAD;
797                         continue;
798                 }
799                 f++;
800
801                 if (!(data = pd_lookup(*f)))
802                         continue; /* unknown wildcard */
803
804                 PRINT(c, TAIL, "%s", data->header);
805                 PAD(data->width);
806         } while (*f++);
807
808         ENDLINE;
809         return (c - line);
810 }
811
812 int
813 snprint_path (char * line, int len, char * format,
814              struct path * pp)
815 {
816         char * c = line;   /* line cursor */
817         char * s = line;   /* for padding */
818         char * f = format; /* format string cursor */
819         int fwd;
820         struct path_data * data;
821         char buff[MAX_FIELD_LEN];
822
823         memset(line, 0, len);
824
825         do {
826                 if (!TAIL)
827                         break;
828
829                 if (*f != '%') {
830                         *c++ = *f;
831                         NOPAD;
832                         continue;
833                 }
834                 f++;
835
836                 if (!(data = pd_lookup(*f)))
837                         continue;
838
839                 data->snprint(buff, MAX_FIELD_LEN, pp);
840                 PRINT(c, TAIL, "%s", buff);
841                 PAD(data->width);
842         } while (*f++);
843
844         ENDLINE;
845         return (c - line);
846 }
847
848 int
849 snprint_pathgroup (char * line, int len, char * format,
850                    struct pathgroup * pgp)
851 {
852         char * c = line;   /* line cursor */
853         char * s = line;   /* for padding */
854         char * f = format; /* format string cursor */
855         int fwd;
856         struct pathgroup_data * data;
857         char buff[MAX_FIELD_LEN];
858
859         memset(line, 0, len);
860
861         do {
862                 if (!TAIL)
863                         break;
864
865                 if (*f != '%') {
866                         *c++ = *f;
867                         NOPAD;
868                         continue;
869                 }
870                 f++;
871
872                 if (!(data = pgd_lookup(*f)))
873                         continue;
874
875                 data->snprint(buff, MAX_FIELD_LEN, pgp);
876                 PRINT(c, TAIL, "%s", buff);
877                 PAD(data->width);
878         } while (*f++);
879
880         ENDLINE;
881         return (c - line);
882 }
883
884 extern void
885 print_multipath_topology (struct multipath * mpp, int verbosity)
886 {
887         int resize;
888         char *buff = NULL;
889         char *old = NULL;
890         int len, maxlen = MAX_LINE_LEN * MAX_LINES;
891
892         buff = MALLOC(maxlen);
893         do {
894                 if (!buff) {
895                         if (old)
896                                 FREE(old);
897                         condlog(0, "couldn't allocate memory for list: %s\n",
898                                 strerror(errno));
899                         return;
900                 }
901
902                 len = snprint_multipath_topology(buff, maxlen, mpp, verbosity);
903                 resize = (len == maxlen - 1);
904
905                 if (resize) {
906                         maxlen *= 2;
907                         old = buff;
908                         buff = REALLOC(buff, maxlen);
909                 }
910         } while (resize);
911         printf("%s", buff);
912         FREE(buff);
913 }
914
915 extern int
916 snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
917                             int verbosity)
918 {
919         int j, i, fwd = 0;
920         struct path * pp = NULL;
921         struct pathgroup * pgp = NULL;
922         char style[64];
923         char * c = style;
924         char fmt[64];
925         char * f;
926
927         if (verbosity <= 0)
928                 return fwd;
929
930         reset_multipath_layout();
931
932         if (verbosity == 1)
933                 return snprint_multipath(buff, len, "%n", mpp);
934
935         if(isatty(1))
936                 c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
937
938         if (verbosity > 1 &&
939             mpp->action != ACT_NOTHING &&
940             mpp->action != ACT_UNDEF)
941                         c += sprintf(c, "%%A: ");
942
943         c += sprintf(c, "%%n");
944
945         if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
946                 c += sprintf(c, " (%%w)");
947
948         c += sprintf(c, " %%d %%s");
949         if(isatty(1))
950                 c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
951
952         fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
953         if (fwd > len)
954                 return len;
955         fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_MAP_PROPS, mpp);
956         if (fwd > len)
957                 return len;
958
959         if (!mpp->pg)
960                 return fwd;
961
962         vector_foreach_slot (mpp->pg, pgp, j) {
963                 f=fmt;
964                 pgp->selector = mpp->selector; /* hack */
965                 if (j + 1 < VECTOR_SIZE(mpp->pg)) {
966                         strcpy(f, "|-+- " PRINT_PG_INDENT);
967                 } else
968                         strcpy(f, "`-+- " PRINT_PG_INDENT);
969                 fwd += snprint_pathgroup(buff + fwd, len - fwd, fmt, pgp);
970                 if (fwd > len)
971                         return len;
972
973                 vector_foreach_slot (pgp->paths, pp, i) {
974                         f=fmt;
975                         if (*f != '|')
976                                 *f=' ';
977                         f++;
978                         if (i + 1 < VECTOR_SIZE(pgp->paths))
979                                 strcpy(f, " |- " PRINT_PATH_INDENT);
980                         else
981                                 strcpy(f, " `- " PRINT_PATH_INDENT);
982                         fwd += snprint_path(buff + fwd, len - fwd, fmt, pp);
983                         if (fwd > len)
984                                 return len;
985                 }
986         }
987         return fwd;
988 }
989
990 static int
991 snprint_hwentry (char * buff, int len, struct hwentry * hwe)
992 {
993         int i;
994         int fwd = 0;
995         struct keyword * kw;
996         struct keyword * rootkw;
997
998         rootkw = find_keyword(NULL, "devices");
999
1000         if (!rootkw || !rootkw->sub)
1001                 return 0;
1002
1003         rootkw = find_keyword(rootkw->sub, "device");
1004
1005         if (!rootkw)
1006                 return 0;
1007
1008         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1009         if (fwd > len)
1010                 return len;
1011         iterate_sub_keywords(rootkw, kw, i) {
1012                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1013                                 kw, hwe);
1014                 if (fwd > len)
1015                         return len;
1016         }
1017         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1018         if (fwd > len)
1019                 return len;
1020         return fwd;
1021 }
1022
1023 extern int
1024 snprint_hwtable (char * buff, int len, vector hwtable)
1025 {
1026         int fwd = 0;
1027         int i;
1028         struct hwentry * hwe;
1029         struct keyword * rootkw;
1030
1031         rootkw = find_keyword(NULL, "devices");
1032         if (!rootkw)
1033                 return 0;
1034
1035         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
1036         if (fwd > len)
1037                 return len;
1038         vector_foreach_slot (hwtable, hwe, i) {
1039                 fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
1040                 if (fwd > len)
1041                         return len;
1042         }
1043         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1044         if (fwd > len)
1045                 return len;
1046         return fwd;
1047 }
1048
1049 static int
1050 snprint_mpentry (char * buff, int len, struct mpentry * mpe)
1051 {
1052         int i;
1053         int fwd = 0;
1054         struct keyword * kw;
1055         struct keyword * rootkw;
1056
1057         rootkw = find_keyword(NULL, "multipath");
1058         if (!rootkw)
1059                 return 0;
1060
1061         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
1062         if (fwd > len)
1063                 return len;
1064         iterate_sub_keywords(rootkw, kw, i) {
1065                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1066                                 kw, mpe);
1067                 if (fwd > len)
1068                         return len;
1069         }
1070         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1071         if (fwd > len)
1072                 return len;
1073         return fwd;
1074 }
1075
1076 extern int
1077 snprint_mptable (char * buff, int len, vector mptable)
1078 {
1079         int fwd = 0;
1080         int i;
1081         struct mpentry * mpe;
1082         struct keyword * rootkw;
1083
1084         rootkw = find_keyword(NULL, "multipaths");
1085         if (!rootkw)
1086                 return 0;
1087
1088         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
1089         if (fwd > len)
1090                 return len;
1091         vector_foreach_slot (mptable, mpe, i) {
1092                 fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
1093                 if (fwd > len)
1094                         return len;
1095         }
1096         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1097         if (fwd > len)
1098                 return len;
1099         return fwd;
1100 }
1101
1102 extern int
1103 snprint_overrides (char * buff, int len, struct hwentry *overrides)
1104 {
1105         int fwd = 0;
1106         int i;
1107         struct keyword *rootkw;
1108         struct keyword *kw;
1109
1110         rootkw = find_keyword(NULL, "overrides");
1111         if (!rootkw)
1112                 return 0;
1113
1114         fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
1115         if (fwd > len)
1116                 return len;
1117         if (!overrides)
1118                 goto out;
1119         iterate_sub_keywords(rootkw, kw, i) {
1120                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1121                                        kw, NULL);
1122                 if (fwd > len)
1123                         return len;
1124         }
1125 out:
1126         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1127         if (fwd > len)
1128                 return len;
1129         return fwd;
1130 }
1131
1132 extern int
1133 snprint_defaults (char * buff, int len)
1134 {
1135         int fwd = 0;
1136         int i;
1137         struct keyword *rootkw;
1138         struct keyword *kw;
1139
1140         rootkw = find_keyword(NULL, "defaults");
1141         if (!rootkw)
1142                 return 0;
1143
1144         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
1145         if (fwd > len)
1146                 return len;
1147
1148         iterate_sub_keywords(rootkw, kw, i) {
1149                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1150                                 kw, NULL);
1151                 if (fwd > len)
1152                         return len;
1153         }
1154         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1155         if (fwd > len)
1156                 return len;
1157         return fwd;
1158 }
1159
1160 static int
1161 snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
1162 {
1163         int threshold = MAX_LINE_LEN;
1164         struct blentry * ble;
1165         int pos;
1166         int i;
1167
1168         pos = *fwd;
1169         if (!VECTOR_SIZE(*vec)) {
1170                 if ((len - pos - threshold) <= 0)
1171                         return 0;
1172                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1173         } else vector_foreach_slot (*vec, ble, i) {
1174                 if ((len - pos - threshold) <= 0)
1175                         return 0;
1176                 if (ble->origin == ORIGIN_CONFIG)
1177                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1178                 else if (ble->origin == ORIGIN_DEFAULT)
1179                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1180                 pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
1181         }
1182
1183         *fwd = pos;
1184         return pos;
1185 }
1186
1187 static int
1188 snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
1189 {
1190         int threshold = MAX_LINE_LEN;
1191         struct blentry_device * bled;
1192         int pos;
1193         int i;
1194
1195         pos = *fwd;
1196         if (!VECTOR_SIZE(*vec)) {
1197                 if ((len - pos - threshold) <= 0)
1198                         return 0;
1199                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1200         } else vector_foreach_slot (*vec, bled, i) {
1201                 if ((len - pos - threshold) <= 0)
1202                         return 0;
1203                 if (bled->origin == ORIGIN_CONFIG)
1204                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1205                 else if (bled->origin == ORIGIN_DEFAULT)
1206                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1207                 pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
1208         }
1209
1210         *fwd = pos;
1211         return pos;
1212 }
1213
1214 extern int
1215 snprint_blacklist_report (char * buff, int len)
1216 {
1217         int threshold = MAX_LINE_LEN;
1218         int fwd = 0;
1219
1220         if ((len - fwd - threshold) <= 0)
1221                 return len;
1222         fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
1223                                                "- blacklist:\n");
1224         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
1225                 return len;
1226
1227         if ((len - fwd - threshold) <= 0)
1228                 return len;
1229         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1230         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
1231                 return len;
1232
1233         if ((len - fwd - threshold) <= 0)
1234                 return len;
1235         fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
1236                                                "- blacklist:\n");
1237         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
1238                 return len;
1239
1240         if ((len - fwd - threshold) <= 0)
1241                 return len;
1242         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1243         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
1244                 return len;
1245
1246         if ((len - fwd - threshold) <= 0)
1247                 return len;
1248         fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
1249                                                "- blacklist:\n");
1250         if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
1251                 return len;
1252
1253         if ((len - fwd - threshold) <= 0)
1254                 return len;
1255         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1256         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
1257                 return len;
1258
1259         if ((len - fwd - threshold) <= 0)
1260                 return len;
1261         fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
1262                                                "- blacklist:\n");
1263         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
1264                 return len;
1265
1266         if ((len - fwd - threshold) <= 0)
1267                 return len;
1268         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1269         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
1270                 return len;
1271
1272         if (fwd > len)
1273                 return len;
1274         return fwd;
1275 }
1276
1277 extern int
1278 snprint_blacklist (char * buff, int len)
1279 {
1280         int i;
1281         struct blentry * ble;
1282         struct blentry_device * bled;
1283         int fwd = 0;
1284         struct keyword *rootkw;
1285         struct keyword *kw;
1286
1287         rootkw = find_keyword(NULL, "blacklist");
1288         if (!rootkw)
1289                 return 0;
1290
1291         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
1292         if (fwd > len)
1293                 return len;
1294
1295         vector_foreach_slot (conf->blist_devnode, ble, i) {
1296                 kw = find_keyword(rootkw->sub, "devnode");
1297                 if (!kw)
1298                         return 0;
1299                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1300                                        kw, ble);
1301                 if (fwd > len)
1302                         return len;
1303         }
1304         vector_foreach_slot (conf->blist_wwid, ble, i) {
1305                 kw = find_keyword(rootkw->sub, "wwid");
1306                 if (!kw)
1307                         return 0;
1308                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1309                                        kw, ble);
1310                 if (fwd > len)
1311                         return len;
1312         }
1313         vector_foreach_slot (conf->blist_property, ble, i) {
1314                 kw = find_keyword(rootkw->sub, "property");
1315                 if (!kw)
1316                         return 0;
1317                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1318                                        kw, ble);
1319                 if (fwd > len)
1320                         return len;
1321         }
1322         rootkw = find_keyword(rootkw->sub, "device");
1323         if (!rootkw)
1324                 return 0;
1325
1326         vector_foreach_slot (conf->blist_device, bled, i) {
1327                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1328                 if (fwd > len)
1329                         return len;
1330                 kw = find_keyword(rootkw->sub, "vendor");
1331                 if (!kw)
1332                         return 0;
1333                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1334                                        kw, bled);
1335                 if (fwd > len)
1336                         return len;
1337                 kw = find_keyword(rootkw->sub, "product");
1338                 if (!kw)
1339                         return 0;
1340                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1341                                        kw, bled);
1342                 if (fwd > len)
1343                         return len;
1344                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1345                 if (fwd > len)
1346                         return len;
1347         }
1348         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1349         if (fwd > len)
1350                 return len;
1351         return fwd;
1352 }
1353
1354 extern int
1355 snprint_blacklist_except (char * buff, int len)
1356 {
1357         int i;
1358         struct blentry * ele;
1359         struct blentry_device * eled;
1360         int fwd = 0;
1361         struct keyword *rootkw;
1362         struct keyword *kw;
1363
1364         rootkw = find_keyword(NULL, "blacklist_exceptions");
1365         if (!rootkw)
1366                 return 0;
1367
1368         fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
1369         if (fwd > len)
1370                 return len;
1371
1372         vector_foreach_slot (conf->elist_devnode, ele, i) {
1373                 kw = find_keyword(rootkw->sub, "devnode");
1374                 if (!kw)
1375                         return 0;
1376                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1377                                        kw, ele);
1378                 if (fwd > len)
1379                         return len;
1380         }
1381         vector_foreach_slot (conf->elist_wwid, ele, i) {
1382                 kw = find_keyword(rootkw->sub, "wwid");
1383                 if (!kw)
1384                         return 0;
1385                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1386                                        kw, ele);
1387                 if (fwd > len)
1388                         return len;
1389         }
1390         vector_foreach_slot (conf->elist_property, ele, i) {
1391                 kw = find_keyword(rootkw->sub, "property");
1392                 if (!kw)
1393                         return 0;
1394                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1395                                        kw, ele);
1396                 if (fwd > len)
1397                         return len;
1398         }
1399         rootkw = find_keyword(rootkw->sub, "device");
1400         if (!rootkw)
1401                 return 0;
1402
1403         vector_foreach_slot (conf->elist_device, eled, i) {
1404                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1405                 if (fwd > len)
1406                         return len;
1407                 kw = find_keyword(rootkw->sub, "vendor");
1408                 if (!kw)
1409                         return 0;
1410                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1411                                        kw, eled);
1412                 if (fwd > len)
1413                         return len;
1414                 kw = find_keyword(rootkw->sub, "product");
1415                 if (!kw)
1416                         return 0;
1417                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1418                                        kw, eled);
1419                 if (fwd > len)
1420                         return len;
1421                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1422                 if (fwd > len)
1423                         return len;
1424         }
1425         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1426         if (fwd > len)
1427                 return len;
1428         return fwd;
1429 }
1430
1431 extern int
1432 snprint_status (char * buff, int len, struct vectors *vecs)
1433 {
1434         int fwd = 0;
1435         int i;
1436         unsigned int count[PATH_MAX_STATE] = {0};
1437         struct path * pp;
1438
1439         vector_foreach_slot (vecs->pathvec, pp, i) {
1440                 count[pp->state]++;
1441         }
1442         fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
1443         for (i=0; i<PATH_MAX_STATE; i++) {
1444                 if (!count[i])
1445                         continue;
1446                 fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
1447                                 checker_state_name(i), count[i]);
1448         }
1449
1450         int monitored_count = 0;
1451
1452         vector_foreach_slot(vecs->pathvec, pp, i)
1453                 if (pp->fd != -1)
1454                         monitored_count++;
1455         fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
1456                         monitored_count, is_uevent_busy()? "True" : "False");
1457
1458         if (fwd > len)
1459                 return len;
1460         return fwd;
1461 }
1462
1463 extern int
1464 snprint_devices (char * buff, int len, struct vectors *vecs)
1465 {
1466         DIR *blkdir;
1467         struct dirent *blkdev;
1468         struct stat statbuf;
1469         char devpath[PATH_MAX];
1470         char *devptr;
1471         int threshold = MAX_LINE_LEN;
1472         int fwd = 0;
1473         int r;
1474
1475         struct path * pp;
1476
1477         if (!(blkdir = opendir("/sys/block")))
1478                 return 1;
1479
1480         if ((len - fwd - threshold) <= 0) {
1481                 closedir(blkdir);
1482                 return len;
1483         }
1484         fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
1485
1486         strcpy(devpath,"/sys/block/");
1487         while ((blkdev = readdir(blkdir)) != NULL) {
1488                 if ((strcmp(blkdev->d_name,".") == 0) ||
1489                     (strcmp(blkdev->d_name,"..") == 0))
1490                         continue;
1491
1492                 devptr = devpath + 11;
1493                 *devptr = '\0';
1494                 strncat(devptr, blkdev->d_name, PATH_MAX-12);
1495                 if (stat(devpath, &statbuf) < 0)
1496                         continue;
1497
1498                 if (S_ISDIR(statbuf.st_mode) == 0)
1499                         continue;
1500
1501                 if ((len - fwd - threshold)  <= 0) {
1502                         closedir(blkdir);
1503                         return len;
1504                 }
1505
1506                 fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
1507                 pp = find_path_by_dev(vecs->pathvec, devptr);
1508                 if (!pp) {
1509                         r = filter_devnode(conf->blist_devnode,
1510                                            conf->elist_devnode, devptr);
1511                         if (r > 0)
1512                                 fwd += snprintf(buff + fwd, len - fwd,
1513                                                 " devnode blacklisted, unmonitored");
1514                         else if (r < 0)
1515                                 fwd += snprintf(buff + fwd, len - fwd,
1516                                                 " devnode whitelisted, unmonitored");
1517                 } else
1518                         fwd += snprintf(buff + fwd, len - fwd,
1519                                         " devnode whitelisted, monitored");
1520                 fwd += snprintf(buff + fwd, len - fwd, "\n");
1521         }
1522         closedir(blkdir);
1523
1524         if (fwd > len)
1525                 return len;
1526         return fwd;
1527 }
1528
1529 extern int
1530 snprint_config (char * buff, int len)
1531 {
1532         return 0;
1533 }
1534
1535 /*
1536  * stdout printing helpers
1537  */
1538 extern void
1539 print_path (struct path * pp, char * style)
1540 {
1541         char line[MAX_LINE_LEN];
1542
1543         memset(&line[0], 0, MAX_LINE_LEN);
1544         snprint_path(&line[0], MAX_LINE_LEN, style, pp);
1545         printf("%s", line);
1546 }
1547
1548 extern void
1549 print_multipath (struct multipath * mpp, char * style)
1550 {
1551         char line[MAX_LINE_LEN];
1552
1553         memset(&line[0], 0, MAX_LINE_LEN);
1554         snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
1555         printf("%s", line);
1556 }
1557
1558 extern void
1559 print_pathgroup (struct pathgroup * pgp, char * style)
1560 {
1561         char line[MAX_LINE_LEN];
1562
1563         memset(&line[0], 0, MAX_LINE_LEN);
1564         snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
1565         printf("%s", line);
1566 }
1567
1568 extern void
1569 print_map (struct multipath * mpp, char * params)
1570 {
1571         if (mpp->size && params)
1572                 printf("0 %llu %s %s\n",
1573                          mpp->size, TGT_MPATH, params);
1574         return;
1575 }
1576
1577 extern void
1578 print_all_paths (vector pathvec, int banner)
1579 {
1580         print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
1581 }
1582
1583 extern void
1584 print_all_paths_custo (vector pathvec, int banner, char *fmt)
1585 {
1586         int i;
1587         struct path * pp;
1588         char line[MAX_LINE_LEN];
1589
1590         if (!VECTOR_SIZE(pathvec)) {
1591                 if (banner)
1592                         fprintf(stdout, "===== no paths =====\n");
1593                 return;
1594         }
1595
1596         if (banner)
1597                 fprintf(stdout, "===== paths list =====\n");
1598
1599         get_path_layout(pathvec, 1);
1600         snprint_path_header(line, MAX_LINE_LEN, fmt);
1601         fprintf(stdout, "%s", line);
1602
1603         vector_foreach_slot (pathvec, pp, i)
1604                 print_path(pp, fmt);
1605 }
1606