[build] minor compilation issues
[platform/upstream/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
9 #include <checkers.h>
10
11 #include "vector.h"
12 #include "structs.h"
13 #include "structs_vec.h"
14 #include "print.h"
15 #include "dmparser.h"
16 #include "config.h"
17 #include "configure.h"
18 #include "pgpolicies.h"
19 #include "defaults.h"
20 #include "parser.h"
21
22 #define MAX(x,y) (x > y) ? x : y
23 #define TAIL     (line + len - 1 - c)
24 #define NOPAD    s = c
25 #define PAD(x)   while ((int)(c - s) < (x) && (c < (line + len - 1))) \
26                         *c++ = ' '; s = c
27 #define PRINT(var, size, format, args...)      \
28                  fwd = snprintf(var, size, format, ##args); \
29                  c += (fwd >= size) ? size : fwd;
30
31 /*
32  * information printing helpers
33  */
34 static int
35 snprint_str (char * buff, size_t len, char * str)
36 {
37         return snprintf(buff, len, "%s", str);
38 }
39
40 static int
41 snprint_int (char * buff, size_t len, int val)
42 {
43         return snprintf(buff, len, "%i", val);
44 }
45
46 static int
47 snprint_uint (char * buff, size_t len, unsigned int val)
48 {
49         return snprintf(buff, len, "%u", val);
50 }
51
52 static int
53 snprint_size (char * buff, size_t len, unsigned long long size)
54 {
55         if (size < (1 << 11))
56                 return snprintf(buff, len, "%llu kB", size >> 1);
57         else if (size < (1 << 21))
58                 return snprintf(buff, len, "%llu MB", size >> 11);
59         else if (size < (1 << 31))
60                 return snprintf(buff, len, "%llu GB", size >> 21);
61         else
62                 return snprintf(buff, len, "%llu TB", size >> 31);
63 }
64
65 static int
66 snprint_name (char * buff, size_t len, struct multipath * mpp)
67 {
68         if (mpp->alias)
69                 return snprintf(buff, len, "%s", mpp->alias);
70         else
71                 return snprintf(buff, len, "%s", mpp->wwid);
72 }
73
74 static int
75 snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
76 {
77         if (mpp->dmi)
78                 return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
79
80         return 0;
81 }
82
83 static int
84 snprint_progress (char * buff, size_t len, int cur, int total)
85 {
86         int i = PROGRESS_LEN * cur / total;
87         int j = PROGRESS_LEN - i;
88         char * c = buff;
89         char * end = buff + len;
90         
91         while (i-- > 0) {
92                 c += snprintf(c, len, "X");
93                 if ((len = (end - c)) <= 1) goto out;
94         }
95
96         while (j-- > 0) {
97                 c += snprintf(c, len,  ".");
98                 if ((len = (end - c)) <= 1) goto out;
99         }
100
101         c += snprintf(c, len, " %i/%i", cur, total);
102
103 out:
104         buff[c - buff + 1] = '\0';
105         return (c - buff + 1);
106 }
107         
108 static int
109 snprint_failback (char * buff, size_t len, struct multipath * mpp)
110 {
111         if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
112                 return snprintf(buff, len, "immediate");
113
114         if (!mpp->failback_tick)
115                 return snprintf(buff, len, "-");
116         else
117                 return snprint_progress(buff, len, mpp->failback_tick,
118                                         mpp->pgfailback);
119 }
120
121 static int
122 snprint_queueing (char * buff, size_t len, struct multipath * mpp)
123 {
124         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
125                 return snprintf(buff, len, "off");
126         else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
127                 return snprintf(buff, len, "on");
128         else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
129                 return snprintf(buff, len, "-");
130         else if (mpp->no_path_retry > 0) {
131                 if (mpp->retry_tick)
132                         return snprintf(buff, len, "%i sec",
133                                         mpp->retry_tick);
134                 else
135                         return snprintf(buff, len, "%i chk",
136                                         mpp->no_path_retry);
137         }
138         return 0;
139 }
140
141 static int
142 snprint_nb_paths (char * buff, size_t len, struct multipath * mpp)
143 {
144         return snprint_int(buff, len, mpp->nr_active);
145 }
146
147 static int
148 snprint_dm_map_state (char * buff, size_t len, struct multipath * mpp)
149 {
150         if (mpp->dmi && mpp->dmi->suspended)
151                 return snprintf(buff, len, "suspend");
152         else
153                 return snprintf(buff, len, "active");
154 }
155
156 static int
157 snprint_multipath_size (char * buff, size_t len, struct multipath * mpp)
158 {
159         return snprint_size(buff, len, mpp->size);
160 }
161
162 static int
163 snprint_features (char * buff, size_t len, struct multipath * mpp)
164 {
165         return snprint_str(buff, len, mpp->features);
166 }
167
168 static int
169 snprint_hwhandler (char * buff, size_t len, struct multipath * mpp)
170 {
171         return snprint_str(buff, len, mpp->hwhandler);
172 }
173
174 static int
175 snprint_path_faults (char * buff, size_t len, struct multipath * mpp)
176 {
177         return snprint_uint(buff, len, mpp->stat_path_failures);
178 }
179
180 static int
181 snprint_switch_grp (char * buff, size_t len, struct multipath * mpp)
182 {
183         return snprint_uint(buff, len, mpp->stat_switchgroup);
184 }
185
186 static int
187 snprint_map_loads (char * buff, size_t len, struct multipath * mpp)
188 {
189         return snprint_uint(buff, len, mpp->stat_map_loads);
190 }
191
192 static int
193 snprint_total_q_time (char * buff, size_t len, struct multipath * mpp)
194 {
195         return snprint_uint(buff, len, mpp->stat_total_queueing_time);
196 }
197
198 static int
199 snprint_q_timeouts (char * buff, size_t len, struct multipath * mpp)
200 {
201         return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
202 }
203
204 static int
205 snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
206 {
207         return snprint_str(buff, len, mpp->wwid);
208 }
209
210 static int
211 snprint_action (char * buff, size_t len, struct multipath * mpp)
212 {
213         switch (mpp->action) {
214         case ACT_RELOAD:
215                 return snprint_str(buff, len, ACT_RELOAD_STR);
216         case ACT_CREATE:
217                 return snprint_str(buff, len, ACT_CREATE_STR);
218         case ACT_SWITCHPG:
219                 return snprint_str(buff, len, ACT_SWITCHPG_STR);
220         default:
221                 return 0;
222         }
223 }
224
225 static int
226 snprint_path_uuid (char * buff, size_t len, struct path * pp)
227 {
228         return snprint_str(buff, len, pp->wwid);
229 }
230
231 static int
232 snprint_hcil (char * buff, size_t len, struct path * pp)
233 {
234         if (pp->sg_id.host_no < 0)
235                 return snprintf(buff, len, "#:#:#:#");
236
237         return snprintf(buff, len, "%i:%i:%i:%i",
238                         pp->sg_id.host_no,
239                         pp->sg_id.channel,
240                         pp->sg_id.scsi_id,
241                         pp->sg_id.lun);
242 }
243
244 static int
245 snprint_dev (char * buff, size_t len, struct path * pp)
246 {
247         if (!strlen(pp->dev))
248                 return snprintf(buff, len, "-");
249         else
250                 return snprint_str(buff, len, pp->dev);
251 }
252
253 static int
254 snprint_dev_t (char * buff, size_t len, struct path * pp)
255 {
256         if (!strlen(pp->dev))
257                 return snprintf(buff, len, "#:#");
258         else
259                 return snprint_str(buff, len, pp->dev_t);
260 }
261
262 static int
263 snprint_chk_state (char * buff, size_t len, struct path * pp)
264 {
265         switch (pp->state) {
266         case PATH_UP:
267                 return snprintf(buff, len, "[ready]");
268         case PATH_DOWN:
269                 return snprintf(buff, len, "[faulty]");
270         case PATH_SHAKY:
271                 return snprintf(buff, len, "[shaky]");
272         case PATH_GHOST:
273                 return snprintf(buff, len, "[ghost]");
274         default:
275                 return snprintf(buff, len, "[undef]");
276         }
277 }
278
279 static int
280 snprint_dm_path_state (char * buff, size_t len, struct path * pp)
281 {
282         switch (pp->dmstate) {
283         case PSTATE_ACTIVE:
284                 return snprintf(buff, len, "[active]");
285         case PSTATE_FAILED:
286                 return snprintf(buff, len, "[failed]");
287         default:
288                 return snprintf(buff, len, "[undef]");
289         }
290 }
291
292 static int
293 snprint_vpr (char * buff, size_t len, struct path * pp)
294 {
295         return snprintf(buff, len, "%s/%s/%s",
296                         pp->vendor_id, pp->product_id, pp->rev);
297 }
298
299 static int
300 snprint_next_check (char * buff, size_t len, struct path * pp)
301 {
302         if (!pp->mpp)
303                 return snprintf(buff, len, "[orphan]");
304
305         return snprint_progress(buff, len, pp->tick, pp->checkint);
306 }
307
308 static int
309 snprint_pri (char * buff, size_t len, struct path * pp)
310 {
311         return snprint_int(buff, len, pp->priority);
312 }
313
314 static int
315 snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
316 {
317         return snprint_str(buff, len, pgp->selector);
318 }
319
320 static int
321 snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
322 {
323         return snprint_int(buff, len, pgp->priority);
324 }
325
326 static int
327 snprint_pg_state (char * buff, size_t len, struct pathgroup * pgp)
328 {
329         switch (pgp->status) {
330         case PGSTATE_ENABLED:
331                 return snprintf(buff, len, "[enabled]");
332         case PGSTATE_DISABLED:
333                 return snprintf(buff, len, "[disabled]");
334         case PGSTATE_ACTIVE:
335                 return snprintf(buff, len, "[active]");
336         default:
337                 return snprintf(buff, len, "[undef]");
338         }
339 }
340
341 static int
342 snprint_path_size (char * buff, size_t len, struct path * pp)
343 {
344         return snprint_size(buff, len, pp->size);
345 }
346
347 struct multipath_data mpd[] = {
348         {'n', "name",          0, snprint_name},
349         {'w', "uuid",          0, snprint_multipath_uuid},
350         {'d', "sysfs",         0, snprint_sysfs},
351         {'F', "failback",      0, snprint_failback},
352         {'Q', "queueing",      0, snprint_queueing},
353         {'N', "paths",         0, snprint_nb_paths},
354         {'t', "dm-st",         0, snprint_dm_map_state},
355         {'S', "size",          0, snprint_multipath_size},
356         {'f', "features",      0, snprint_features},
357         {'h', "hwhandler",     0, snprint_hwhandler},
358         {'A', "action",        0, snprint_action},
359         {'0', "path_faults",   0, snprint_path_faults},
360         {'1', "switch_grp",    0, snprint_switch_grp},
361         {'2', "map_loads",     0, snprint_map_loads},
362         {'3', "total_q_time",  0, snprint_total_q_time},
363         {'4', "q_timeouts",    0, snprint_q_timeouts},
364         {0, NULL, 0 , NULL}
365 };
366
367 struct path_data pd[] = {
368         {'w', "uuid",          0, snprint_path_uuid},
369         {'i', "hcil",          0, snprint_hcil},
370         {'d', "dev",           0, snprint_dev},
371         {'D', "dev_t",         0, snprint_dev_t},
372         {'t', "dm_st",         0, snprint_dm_path_state},
373         {'T', "chk_st",        0, snprint_chk_state},
374         {'s', "vend/prod/rev", 0, snprint_vpr},
375         {'C', "next_check",    0, snprint_next_check},
376         {'p', "pri",           0, snprint_pri},
377         {'S', "size",          0, snprint_path_size},
378         {0, NULL, 0 , NULL}
379 };
380
381 struct pathgroup_data pgd[] = {
382         {'s', "selector",      0, snprint_pg_selector},
383         {'p', "pri",           0, snprint_pg_pri},
384         {'t', "dm_st",         0, snprint_pg_state},
385 };
386
387 void
388 get_path_layout (vector pathvec)
389 {
390         int i, j;
391         char buff[MAX_FIELD_LEN];
392         struct path * pp;
393
394         for (j = 0; pd[j].header; j++) {
395                 pd[j].width = strlen(pd[j].header);
396
397                 vector_foreach_slot (pathvec, pp, i) {
398                         pd[j].snprint(buff, MAX_FIELD_LEN, pp);
399                         pd[j].width = MAX(pd[j].width, strlen(buff));
400                 }
401         }
402 }
403
404 void
405 get_multipath_layout (vector mpvec)
406 {
407         int i, j;
408         char buff[MAX_FIELD_LEN];
409         struct multipath * mpp;
410
411         for (j = 0; mpd[j].header; j++) {
412                 mpd[j].width = strlen(mpd[j].header);
413
414                 vector_foreach_slot (mpvec, mpp, i) {
415                         mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
416                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
417                 }
418         }
419 }
420
421 static struct multipath_data *
422 mpd_lookup(char wildcard)
423 {
424         int i;
425
426         for (i = 0; mpd[i].header; i++)
427                 if (mpd[i].wildcard == wildcard)
428                         return &mpd[i];
429
430         return NULL;
431 }
432
433 static struct path_data *
434 pd_lookup(char wildcard)
435 {
436         int i;
437
438         for (i = 0; pd[i].header; i++)
439                 if (pd[i].wildcard == wildcard)
440                         return &pd[i];
441
442         return NULL;
443 }
444
445 static struct pathgroup_data *
446 pgd_lookup(char wildcard)
447 {
448         int i;
449
450         for (i = 0; pgd[i].header; i++)
451                 if (pgd[i].wildcard == wildcard)
452                         return &pgd[i];
453
454         return NULL;
455 }
456
457 int
458 snprint_multipath_header (char * line, int len, char * format)
459 {
460         char * c = line;   /* line cursor */
461         char * s = line;   /* for padding */
462         char * f = format; /* format string cursor */
463         int fwd;
464         struct multipath_data * data;
465
466         do {
467                 if (!TAIL)
468                         break;
469
470                 if (*f != '%') {
471                         *c++ = *f;
472                         NOPAD;
473                         continue;
474                 }
475                 f++;
476                 
477                 if (!(data = mpd_lookup(*f)))
478                         break; /* unknown wildcard */
479                 
480                 PRINT(c, TAIL, data->header);
481                 PAD(data->width);
482         } while (*f++);
483
484         line[c - line - 1] = '\n';
485         line[c - line] = '\0';
486
487         return (c - line);
488 }
489
490 int
491 snprint_multipath (char * line, int len, char * format,
492              struct multipath * mpp)
493 {
494         char * c = line;   /* line cursor */
495         char * s = line;   /* for padding */
496         char * f = format; /* format string cursor */
497         int fwd;
498         struct multipath_data * data;
499         char buff[MAX_FIELD_LEN];
500
501         do {
502                 if (!TAIL)
503                         break;
504
505                 if (*f != '%') {
506                         *c++ = *f;
507                         NOPAD;
508                         continue;
509                 }
510                 f++;
511                 
512                 if (!(data = mpd_lookup(*f)))
513                         break;
514                 
515                 data->snprint(buff, MAX_FIELD_LEN, mpp);
516                 PRINT(c, TAIL, buff);
517                 PAD(data->width);
518         } while (*f++);
519
520         line[c - line - 1] = '\n';
521         line[c - line] = '\0';
522
523         return (c - line);
524 }
525
526 int
527 snprint_path_header (char * line, int len, char * format)
528 {
529         char * c = line;   /* line cursor */
530         char * s = line;   /* for padding */
531         char * f = format; /* format string cursor */
532         int fwd;
533         struct path_data * data;
534
535         do {
536                 if (!TAIL)
537                         break;
538
539                 if (*f != '%') {
540                         *c++ = *f;
541                         NOPAD;
542                         continue;
543                 }
544                 f++;
545                 
546                 if (!(data = pd_lookup(*f)))
547                         break; /* unknown wildcard */
548                 
549                 PRINT(c, TAIL, data->header);
550                 PAD(data->width);
551         } while (*f++);
552
553         line[c - line - 1] = '\n';
554         line[c - line] = '\0';
555
556         return (c - line);
557 }
558
559 int
560 snprint_path (char * line, int len, char * format,
561              struct path * pp)
562 {
563         char * c = line;   /* line cursor */
564         char * s = line;   /* for padding */
565         char * f = format; /* format string cursor */
566         int fwd;
567         struct path_data * data;
568         char buff[MAX_FIELD_LEN];
569
570         do {
571                 if (!TAIL)
572                         break;
573
574                 if (*f != '%') {
575                         *c++ = *f;
576                         NOPAD;
577                         continue;
578                 }
579                 f++;
580                 
581                 if (!(data = pd_lookup(*f)))
582                         break;
583                 
584                 data->snprint(buff, MAX_FIELD_LEN, pp);
585                 PRINT(c, TAIL, buff);
586                 PAD(data->width);
587         } while (*f++);
588
589         line[c - line - 1] = '\n';
590         line[c - line] = '\0';
591
592         return (c - line);
593 }
594
595 int
596 snprint_pathgroup (char * line, int len, char * format,
597                    struct pathgroup * pgp)
598 {
599         char * c = line;   /* line cursor */
600         char * s = line;   /* for padding */
601         char * f = format; /* format string cursor */
602         int fwd;
603         struct pathgroup_data * data;
604         char buff[MAX_FIELD_LEN];
605
606         do {
607                 if (!TAIL)
608                         break;
609
610                 if (*f != '%') {
611                         *c++ = *f;
612                         NOPAD;
613                         continue;
614                 }
615                 f++;
616                 
617                 if (!(data = pgd_lookup(*f)))
618                         break;
619                 
620                 data->snprint(buff, MAX_FIELD_LEN, pgp);
621                 PRINT(c, TAIL, buff);
622                 PAD(data->width);
623         } while (*f++);
624
625         line[c - line - 1] = '\n';
626         line[c - line] = '\0';
627
628         return (c - line);
629 }
630
631 extern void
632 print_multipath_topology (struct multipath * mpp, int verbosity)
633 {
634         char buff[MAX_LINE_LEN * MAX_LINES];
635
636         snprint_multipath_topology(&buff[0], MAX_LINE_LEN * MAX_LINES,
637                                    mpp, verbosity);
638         printf("%s", buff);
639 }
640
641 extern int
642 snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
643                             int verbosity)
644 {
645         int j, i, fwd = 0;
646         struct path * pp = NULL;
647         struct pathgroup * pgp = NULL;
648         char style[64];
649         char * c = style;
650
651         if (verbosity <= 0)
652                 return fwd;
653
654         if (verbosity == 1)
655                 return snprint_multipath(buff, len, "%n", mpp);
656
657         if (verbosity > 1 &&
658             mpp->action != ACT_NOTHING &&
659             mpp->action != ACT_UNDEF)
660                         c += sprintf(c, "%%A: ");
661
662         c += sprintf(c, "%%n");
663         
664         if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
665                 c += sprintf(c, " (%%w)");
666
667         fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
668         if (fwd > len)
669                 return len;
670         fwd += snprint_multipath(buff + fwd, len - fwd,
671                                  "[size=%S][features=%f][hwhandler=%h]", mpp);
672         if (fwd > len)
673                 return len;
674
675         if (!mpp->pg)
676                 return fwd;
677
678         vector_foreach_slot (mpp->pg, pgp, j) {
679                 pgp->selector = mpp->selector; /* hack */
680                 fwd += snprint_pathgroup(buff + fwd, len - fwd,
681                                          PRINT_PG_INDENT, pgp);
682                 if (fwd > len)
683                         return len;
684
685                 vector_foreach_slot (pgp->paths, pp, i) {
686                         fwd += snprint_path(buff + fwd, len - fwd,
687                                             PRINT_PATH_INDENT, pp);
688                         if (fwd > len)
689                                 return len;
690                 }
691         }
692         return fwd;
693 }
694
695 static int
696 snprint_hwentry (char * buff, int len, struct hwentry * hwe)
697 {
698         int i;
699         int fwd = 0;
700         struct keyword * kw;
701         struct keyword * rootkw;
702
703         rootkw = find_keyword(NULL, "devices");
704
705         if (!rootkw || !rootkw->sub)
706                 return 0;
707
708         rootkw = find_keyword(rootkw->sub, "device");
709
710         if (!rootkw)
711                 return 0;
712
713         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
714         if (fwd > len)
715                 return len;
716         iterate_sub_keywords(rootkw, kw, i) {
717                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
718                                 kw, hwe);
719                 if (fwd > len)
720                         return len;
721         }
722         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
723         if (fwd > len)
724                 return len;
725         return fwd;
726 }
727
728 extern int
729 snprint_hwtable (char * buff, int len, vector hwtable)
730 {
731         int fwd = 0;
732         int i;
733         struct hwentry * hwe;
734         struct keyword * rootkw;
735
736         rootkw = find_keyword(NULL, "devices");
737         if (!rootkw)
738                 return 0;
739
740         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
741         if (fwd > len)
742                 return len;
743         vector_foreach_slot (hwtable, hwe, i) {
744                 fwd += snprint_hwentry(buff + fwd, len - fwd, hwe);
745                 if (fwd > len)
746                         return len;
747         }
748         fwd += snprintf(buff + fwd, len - fwd, "}\n");
749         if (fwd > len)
750                 return len;
751         return fwd;
752 }
753
754 static int
755 snprint_mpentry (char * buff, int len, struct mpentry * mpe)
756 {
757         int i;
758         int fwd = 0;
759         struct keyword * kw;
760         struct keyword * rootkw;
761
762         rootkw = find_keyword(NULL, "multipath");
763         if (!rootkw)
764                 return 0;
765
766         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
767         if (fwd > len)
768                 return len;
769         iterate_sub_keywords(rootkw, kw, i) {
770                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
771                                 kw, mpe);
772                 if (fwd > len)
773                         return len;
774         }
775         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
776         if (fwd > len)
777                 return len;
778         return fwd;
779 }
780
781 extern int
782 snprint_mptable (char * buff, int len, vector mptable)
783 {
784         int fwd = 0;
785         int i;
786         struct mpentry * mpe;
787         struct keyword * rootkw;
788
789         rootkw = find_keyword(NULL, "multipaths");
790         if (!rootkw)
791                 return 0;
792
793         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
794         if (fwd > len)
795                 return len;
796         vector_foreach_slot (mptable, mpe, i) {
797                 fwd += snprint_mpentry(buff + fwd, len - fwd, mpe);
798                 if (fwd > len)
799                         return len;
800         }
801         fwd += snprintf(buff + fwd, len - fwd, "}\n");
802         if (fwd > len)
803                 return len;
804         return fwd;
805 }
806
807 extern int
808 snprint_defaults (char * buff, int len)
809 {
810         int fwd = 0;
811         int i;
812         struct keyword *rootkw;
813         struct keyword *kw;
814
815         rootkw = find_keyword(NULL, "defaults");
816         if (!rootkw)
817                 return 0;
818
819         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
820         if (fwd > len)
821                 return len;
822
823         iterate_sub_keywords(rootkw, kw, i) {
824                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
825                                 kw, NULL);
826                 if (fwd > len)
827                         return len;
828         }
829         fwd += snprintf(buff + fwd, len - fwd, "}\n");
830         if (fwd > len)
831                 return len;
832         return fwd;
833         
834 }
835
836 extern int
837 snprint_blacklist (char * buff, int len)
838 {
839         int i;
840         struct blentry * ble;
841         struct blentry_device * bled;
842         int fwd = 0;
843         struct keyword *rootkw;
844         struct keyword *kw;
845
846         rootkw = find_keyword(NULL, "blacklist");
847         if (!rootkw)
848                 return 0;
849
850         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
851         if (fwd > len)
852                 return len;
853
854         vector_foreach_slot (conf->blist_devnode, ble, i) {
855                 kw = find_keyword(rootkw->sub, "devnode");
856                 if (!kw)
857                         return 0;
858                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
859                                        kw, ble);
860                 if (fwd > len)
861                         return len;
862         }
863         vector_foreach_slot (conf->blist_wwid, ble, i) {
864                 kw = find_keyword(rootkw->sub, "wwid");
865                 if (!kw)
866                         return 0;
867                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
868                                        kw, ble);
869                 if (fwd > len)
870                         return len;
871         }
872         rootkw = find_keyword(rootkw->sub, "device");
873         if (!rootkw)
874                 return 0;
875
876         vector_foreach_slot (conf->blist_device, bled, i) {
877                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
878                 if (fwd > len)
879                         return len;
880                 kw = find_keyword(rootkw->sub, "vendor");
881                 if (!kw)
882                         return 0;
883                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
884                                        kw, bled);
885                 if (fwd > len)
886                         return len;
887                 kw = find_keyword(rootkw->sub, "product");
888                 if (!kw)
889                         return 0;
890                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
891                                        kw, bled);
892                 if (fwd > len)
893                         return len;
894                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
895                 if (fwd > len)
896                         return len;
897         }
898
899         fwd += snprintf(buff + fwd, len - fwd, "}\n");
900         if (fwd > len)
901                 return len;
902         return fwd;
903         
904 }
905
906 extern int
907 snprint_config (char * buff, int len)
908 {
909         return 0;
910 }
911
912 /*
913  * stdout printing helpers
914  */
915 extern void
916 print_path (struct path * pp, char * style)
917 {
918         char line[MAX_LINE_LEN];
919
920         snprint_path(&line[0], MAX_LINE_LEN, style, pp);
921         printf("%s", line);
922 }
923
924 extern void
925 print_multipath (struct multipath * mpp, char * style)
926 {
927         char line[MAX_LINE_LEN];
928
929         snprint_multipath(&line[0], MAX_LINE_LEN, style, mpp);
930         printf("%s", line);
931 }
932
933 extern void
934 print_pathgroup (struct pathgroup * pgp, char * style)
935 {
936         char line[MAX_LINE_LEN];
937
938         snprint_pathgroup(&line[0], MAX_LINE_LEN, style, pgp);
939         printf("%s", line);
940 }
941
942 extern void
943 print_map (struct multipath * mpp)
944 {
945         if (mpp->size && mpp->params)
946                 printf("0 %llu %s %s\n",
947                          mpp->size, DEFAULT_TARGET, mpp->params);
948         return;
949 }
950
951 extern void
952 print_all_paths (vector pathvec, int banner)
953 {
954         int i;
955         struct path * pp;
956         char line[MAX_LINE_LEN];
957
958         if (!VECTOR_SIZE(pathvec)) {
959                 if (banner)
960                         fprintf(stdout, "===== no paths =====\n");
961                 return;
962         }
963         
964         if (banner)
965                 fprintf(stdout, "===== paths list =====\n");
966
967         get_path_layout(pathvec);
968         snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
969         fprintf(stdout, "%s", line);
970
971         vector_foreach_slot (pathvec, pp, i)
972                 print_path(pp, PRINT_PATH_LONG);
973 }
974