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