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