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