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