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