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