libmultipath/print: add "%G - foreign" wildcard
[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 #include <libudev.h>
14
15 #include "checkers.h"
16 #include "vector.h"
17 #include "structs.h"
18 #include "structs_vec.h"
19 #include "dmparser.h"
20 #include "config.h"
21 #include "configure.h"
22 #include "pgpolicies.h"
23 #include "print.h"
24 #include "defaults.h"
25 #include "parser.h"
26 #include "blacklist.h"
27 #include "switchgroup.h"
28 #include "devmapper.h"
29 #include "uevent.h"
30 #include "debug.h"
31 #include "discovery.h"
32
33 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
34 #define MIN(x,y) (((x) > (y)) ? (y) : (x))
35 #define TAIL     (line + len - 1 - c)
36 #define NOPAD    s = c
37 #define PAD(x) \
38 do { \
39         while ((int)(c - s) < (x) && (c < (line + len - 1))) \
40                 *c++ = ' '; \
41         s = c; \
42 } while (0)
43
44 static char *
45 __endline(char *line, size_t len, char *c)
46 {
47         if (c > line) {
48                 if (c >= line + len)
49                         c = line + len - 1;
50                 *(c - 1) = '\n';
51                 *c = '\0';
52         }
53         return c;
54 }
55
56 #define PRINT(var, size, format, args...) \
57 do { \
58         fwd = snprintf(var, size, format, ##args); \
59         c += (fwd >= size) ? size : fwd; \
60 } while (0)
61
62 /*
63  * information printing helpers
64  */
65 static int
66 snprint_str (char * buff, size_t len, const char * str)
67 {
68         return snprintf(buff, len, "%s", str);
69 }
70
71 static int
72 snprint_int (char * buff, size_t len, int val)
73 {
74         return snprintf(buff, len, "%i", val);
75 }
76
77 static int
78 snprint_uint (char * buff, size_t len, unsigned int val)
79 {
80         return snprintf(buff, len, "%u", val);
81 }
82
83 static int
84 snprint_size (char * buff, size_t len, unsigned long long size)
85 {
86         float s = (float)(size >> 1); /* start with KB */
87         char units[] = {'K','M','G','T','P'};
88         char *u = units;
89
90         while (s >= 1024 && *u != 'P') {
91                 s = s / 1024;
92                 u++;
93         }
94
95         return snprintf(buff, len, "%.*f%c", s < 10, s, *u);
96 }
97
98 /*
99  * multipath info printing functions
100  */
101 static int
102 snprint_name (char * buff, size_t len, const struct multipath * mpp)
103 {
104         if (mpp->alias)
105                 return snprintf(buff, len, "%s", mpp->alias);
106         else
107                 return snprintf(buff, len, "%s", mpp->wwid);
108 }
109
110 static int
111 snprint_sysfs (char * buff, size_t len, const struct multipath * mpp)
112 {
113         if (mpp->dmi)
114                 return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
115         else
116                 return snprintf(buff, len, "undef");
117 }
118
119 static int
120 snprint_ro (char * buff, size_t len, const struct multipath * mpp)
121 {
122         if (!mpp->dmi)
123                 return snprintf(buff, len, "undef");
124         if (mpp->dmi->read_only)
125                 return snprintf(buff, len, "ro");
126         else
127                 return snprintf(buff, len, "rw");
128 }
129
130 static int
131 snprint_progress (char * buff, size_t len, int cur, int total)
132 {
133         char * c = buff;
134         char * end = buff + len;
135
136         if (total > 0) {
137                 int i = PROGRESS_LEN * cur / total;
138                 int j = PROGRESS_LEN - i;
139
140                 while (i-- > 0) {
141                         c += snprintf(c, len, "X");
142                         if ((len = (end - c)) <= 1) goto out;
143                 }
144
145                 while (j-- > 0) {
146                         c += snprintf(c, len,  ".");
147                         if ((len = (end - c)) <= 1) goto out;
148                 }
149         }
150
151         c += snprintf(c, len, " %i/%i", cur, total);
152
153 out:
154         buff[c - buff + 1] = '\0';
155         return (c - buff + 1);
156 }
157
158 static int
159 snprint_failback (char * buff, size_t len, const struct multipath * mpp)
160 {
161         if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
162                 return snprintf(buff, len, "immediate");
163         if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
164                 return snprintf(buff, len, "followover");
165
166         if (!mpp->failback_tick)
167                 return snprintf(buff, len, "-");
168         else
169                 return snprint_progress(buff, len, mpp->failback_tick,
170                                         mpp->pgfailback);
171 }
172
173 static int
174 snprint_queueing (char * buff, size_t len, const struct multipath * mpp)
175 {
176         if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
177                 return snprintf(buff, len, "off");
178         else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
179                 return snprintf(buff, len, "on");
180         else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
181                 return snprintf(buff, len, "-");
182         else if (mpp->no_path_retry > 0) {
183                 if (mpp->retry_tick > 0)
184                         return snprintf(buff, len, "%i sec",
185                                         mpp->retry_tick);
186                 else if (mpp->retry_tick == 0 && mpp->nr_active > 0)
187                         return snprintf(buff, len, "%i chk",
188                                         mpp->no_path_retry);
189                 else
190                         return snprintf(buff, len, "off");
191         }
192         return 0;
193 }
194
195 static int
196 snprint_nb_paths (char * buff, size_t len, const struct multipath * mpp)
197 {
198         return snprint_int(buff, len, mpp->nr_active);
199 }
200
201 static int
202 snprint_dm_map_state (char * buff, size_t len, const struct multipath * mpp)
203 {
204         if (mpp->dmi && mpp->dmi->suspended)
205                 return snprintf(buff, len, "suspend");
206         else
207                 return snprintf(buff, len, "active");
208 }
209
210 static int
211 snprint_multipath_size (char * buff, size_t len, const struct multipath * mpp)
212 {
213         return snprint_size(buff, len, mpp->size);
214 }
215
216 static int
217 snprint_features (char * buff, size_t len, const struct multipath * mpp)
218 {
219         return snprint_str(buff, len, mpp->features);
220 }
221
222 static int
223 snprint_hwhandler (char * buff, size_t len, const struct multipath * mpp)
224 {
225         return snprint_str(buff, len, mpp->hwhandler);
226 }
227
228 static int
229 snprint_path_faults (char * buff, size_t len, const struct multipath * mpp)
230 {
231         return snprint_uint(buff, len, mpp->stat_path_failures);
232 }
233
234 static int
235 snprint_switch_grp (char * buff, size_t len, const struct multipath * mpp)
236 {
237         return snprint_uint(buff, len, mpp->stat_switchgroup);
238 }
239
240 static int
241 snprint_map_loads (char * buff, size_t len, const struct multipath * mpp)
242 {
243         return snprint_uint(buff, len, mpp->stat_map_loads);
244 }
245
246 static int
247 snprint_total_q_time (char * buff, size_t len, const struct multipath * mpp)
248 {
249         return snprint_uint(buff, len, mpp->stat_total_queueing_time);
250 }
251
252 static int
253 snprint_q_timeouts (char * buff, size_t len, const struct multipath * mpp)
254 {
255         return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
256 }
257
258 static int
259 snprint_map_failures (char * buff, size_t len, const struct multipath * mpp)
260 {
261         return snprint_uint(buff, len, mpp->stat_map_failures);
262 }
263
264 static int
265 snprint_multipath_uuid (char * buff, size_t len, const struct multipath * mpp)
266 {
267         return snprint_str(buff, len, mpp->wwid);
268 }
269
270 static int
271 snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp)
272 {
273         struct pathgroup * pgp;
274         struct path * pp;
275         int i, j;
276
277         vector_foreach_slot(mpp->pg, pgp, i) {
278                 if (!pgp)
279                         continue;
280                 vector_foreach_slot(pgp->paths, pp, j) {
281                         if (strlen(pp->vendor_id) && strlen(pp->product_id))
282                                 return snprintf(buff, len, "%s,%s",
283                                                 pp->vendor_id, pp->product_id);
284                 }
285         }
286         return snprintf(buff, len, "##,##");
287 }
288
289
290 static int
291 snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
292 {
293         struct pathgroup * pgp;
294         struct path * pp;
295         int i, j;
296
297         vector_foreach_slot(mpp->pg, pgp, i) {
298                 if (!pgp)
299                         continue;
300                 vector_foreach_slot(pgp->paths, pp, j) {
301                         if (strlen(pp->vendor_id))
302                                 return snprintf(buff, len, "%s", pp->vendor_id);
303                 }
304         }
305         return snprintf(buff, len, "##");
306 }
307
308 static int
309 snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
310 {
311         struct pathgroup * pgp;
312         struct path * pp;
313         int i, j;
314
315         vector_foreach_slot(mpp->pg, pgp, i) {
316                 if (!pgp)
317                         continue;
318                 vector_foreach_slot(pgp->paths, pp, j) {
319                         if (strlen(pp->product_id))
320                                 return snprintf(buff, len, "%s", pp->product_id);
321                 }
322         }
323         return snprintf(buff, len, "##");
324 }
325
326 static int
327 snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
328 {
329         struct pathgroup * pgp;
330         struct path * pp;
331         int i, j;
332
333         vector_foreach_slot(mpp->pg, pgp, i) {
334                 if (!pgp)
335                         continue;
336                 vector_foreach_slot(pgp->paths, pp, j) {
337                         if (strlen(pp->rev))
338                                 return snprintf(buff, len, "%s", pp->rev);
339                 }
340         }
341         return snprintf(buff, len, "##");
342 }
343
344 static int
345 snprint_multipath_foreign (char * buff, size_t len, const struct multipath * pp)
346 {
347         return snprintf(buff, len, "%s", "--");
348 }
349
350 static int
351 snprint_action (char * buff, size_t len, const struct multipath * mpp)
352 {
353         switch (mpp->action) {
354         case ACT_REJECT:
355                 return snprint_str(buff, len, ACT_REJECT_STR);
356         case ACT_RENAME:
357                 return snprint_str(buff, len, ACT_RENAME_STR);
358         case ACT_RELOAD:
359                 return snprint_str(buff, len, ACT_RELOAD_STR);
360         case ACT_CREATE:
361                 return snprint_str(buff, len, ACT_CREATE_STR);
362         case ACT_SWITCHPG:
363                 return snprint_str(buff, len, ACT_SWITCHPG_STR);
364         default:
365                 return 0;
366         }
367 }
368
369 /*
370  * path info printing functions
371  */
372 static int
373 snprint_path_uuid (char * buff, size_t len, const struct path * pp)
374 {
375         return snprint_str(buff, len, pp->wwid);
376 }
377
378 static int
379 snprint_hcil (char * buff, size_t len, const struct path * pp)
380 {
381         if (!pp || pp->sg_id.host_no < 0)
382                 return snprintf(buff, len, "#:#:#:#");
383
384         return snprintf(buff, len, "%i:%i:%i:%i",
385                         pp->sg_id.host_no,
386                         pp->sg_id.channel,
387                         pp->sg_id.scsi_id,
388                         pp->sg_id.lun);
389 }
390
391 static int
392 snprint_dev (char * buff, size_t len, const struct path * pp)
393 {
394         if (!pp || !strlen(pp->dev))
395                 return snprintf(buff, len, "-");
396         else
397                 return snprint_str(buff, len, pp->dev);
398 }
399
400 static int
401 snprint_dev_t (char * buff, size_t len, const struct path * pp)
402 {
403         if (!pp || !strlen(pp->dev))
404                 return snprintf(buff, len, "#:#");
405         else
406                 return snprint_str(buff, len, pp->dev_t);
407 }
408
409 static int
410 snprint_offline (char * buff, size_t len, const struct path * pp)
411 {
412         if (!pp || !pp->mpp)
413                 return snprintf(buff, len, "unknown");
414         else if (pp->offline)
415                 return snprintf(buff, len, "offline");
416         else
417                 return snprintf(buff, len, "running");
418 }
419
420 static int
421 snprint_chk_state (char * buff, size_t len, const struct path * pp)
422 {
423         if (!pp || !pp->mpp)
424                 return snprintf(buff, len, "undef");
425
426         switch (pp->state) {
427         case PATH_UP:
428                 return snprintf(buff, len, "ready");
429         case PATH_DOWN:
430                 return snprintf(buff, len, "faulty");
431         case PATH_SHAKY:
432                 return snprintf(buff, len, "shaky");
433         case PATH_GHOST:
434                 return snprintf(buff, len, "ghost");
435         case PATH_PENDING:
436                 return snprintf(buff, len, "i/o pending");
437         case PATH_TIMEOUT:
438                 return snprintf(buff, len, "i/o timeout");
439         case PATH_DELAYED:
440                 return snprintf(buff, len, "delayed");
441         default:
442                 return snprintf(buff, len, "undef");
443         }
444 }
445
446 static int
447 snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
448 {
449         if (!pp)
450                 return snprintf(buff, len, "undef");
451
452         switch (pp->dmstate) {
453         case PSTATE_ACTIVE:
454                 return snprintf(buff, len, "active");
455         case PSTATE_FAILED:
456                 return snprintf(buff, len, "failed");
457         default:
458                 return snprintf(buff, len, "undef");
459         }
460 }
461
462 static int
463 snprint_vpr (char * buff, size_t len, const struct path * pp)
464 {
465         return snprintf(buff, len, "%s,%s",
466                         pp->vendor_id, pp->product_id);
467 }
468
469 static int
470 snprint_next_check (char * buff, size_t len, const struct path * pp)
471 {
472         if (!pp || !pp->mpp)
473                 return snprintf(buff, len, "orphan");
474
475         return snprint_progress(buff, len, pp->tick, pp->checkint);
476 }
477
478 static int
479 snprint_pri (char * buff, size_t len, const struct path * pp)
480 {
481         return snprint_int(buff, len, pp ? pp->priority : -1);
482 }
483
484 static int
485 snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
486 {
487         const char *s = pgp->mpp->selector;
488
489         return snprint_str(buff, len, s ? s : "");
490 }
491
492 static int
493 snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
494 {
495         return snprint_int(buff, len, pgp->priority);
496 }
497
498 static int
499 snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
500 {
501         switch (pgp->status) {
502         case PGSTATE_ENABLED:
503                 return snprintf(buff, len, "enabled");
504         case PGSTATE_DISABLED:
505                 return snprintf(buff, len, "disabled");
506         case PGSTATE_ACTIVE:
507                 return snprintf(buff, len, "active");
508         default:
509                 return snprintf(buff, len, "undef");
510         }
511 }
512
513 static int
514 snprint_path_size (char * buff, size_t len, const struct path * pp)
515 {
516         return snprint_size(buff, len, pp->size);
517 }
518
519 int
520 snprint_path_serial (char * buff, size_t len, const struct path * pp)
521 {
522         return snprint_str(buff, len, pp->serial);
523 }
524
525 static int
526 snprint_path_mpp (char * buff, size_t len, const struct path * pp)
527 {
528         if (!pp->mpp)
529                 return snprintf(buff, len, "[orphan]");
530         if (!pp->mpp->alias)
531                 return snprintf(buff, len, "[unknown]");
532         return snprint_str(buff, len, pp->mpp->alias);
533 }
534
535 static int
536 snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
537 {
538         struct udev_device *host_dev = NULL;
539         char host_id[32];
540         const char *value = NULL;
541         int ret;
542
543         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
544                 return snprintf(buff, len, "[undef]");
545         sprintf(host_id, "host%d", pp->sg_id.host_no);
546         host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
547                                                           host_id);
548         if (!host_dev) {
549                 condlog(1, "%s: No fc_host device for '%s'", pp->dev, host_id);
550                 goto out;
551         }
552         value = udev_device_get_sysattr_value(host_dev, attr);
553         if (value)
554                 ret = snprint_str(buff, len, value);
555         udev_device_unref(host_dev);
556 out:
557         if (!value)
558                 ret = snprintf(buff, len, "[unknown]");
559         return ret;
560 }
561
562 int
563 snprint_host_wwnn (char * buff, size_t len, const struct path * pp)
564 {
565         return snprint_host_attr(buff, len, pp, "node_name");
566 }
567
568 int
569 snprint_host_wwpn (char * buff, size_t len, const struct path * pp)
570 {
571         return snprint_host_attr(buff, len, pp, "port_name");
572 }
573
574 int
575 snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
576 {
577         struct udev_device *rport_dev = NULL;
578         char rport_id[32];
579         const char *value = NULL;
580         int ret;
581
582         if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
583                 return snprintf(buff, len, "[undef]");
584         sprintf(rport_id, "rport-%d:%d-%d",
585                 pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
586         rport_dev = udev_device_new_from_subsystem_sysname(udev,
587                                 "fc_remote_ports", rport_id);
588         if (!rport_dev) {
589                 condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
590                         rport_id);
591                 goto out;
592         }
593         value = udev_device_get_sysattr_value(rport_dev, "port_name");
594         if (value)
595                 ret = snprint_str(buff, len, value);
596         udev_device_unref(rport_dev);
597 out:
598         if (!value)
599                 ret = snprintf(buff, len, "[unknown]");
600         return ret;
601 }
602
603
604 int
605 snprint_tgt_wwnn (char * buff, size_t len, const struct path * pp)
606 {
607         if (pp->tgt_node_name[0] == '\0')
608                 return snprintf(buff, len, "[undef]");
609         return snprint_str(buff, len, pp->tgt_node_name);
610 }
611
612 static int
613 snprint_host_adapter (char * buff, size_t len, const struct path * pp)
614 {
615         char adapter[SLOT_NAME_SIZE];
616
617         if (sysfs_get_host_adapter_name(pp, adapter))
618                 return snprintf(buff, len, "[undef]");
619         return snprint_str(buff, len, adapter);
620 }
621
622 static int
623 snprint_path_checker (char * buff, size_t len, const struct path * pp)
624 {
625         const struct checker * c = &pp->checker;
626         return snprint_str(buff, len, c->name);
627 }
628
629 static int
630 snprint_path_foreign (char * buff, size_t len, const struct path * pp)
631 {
632         return snprintf(buff, len, "%s", "--");
633 }
634
635 struct multipath_data mpd[] = {
636         {'n', "name",          0, snprint_name},
637         {'w', "uuid",          0, snprint_multipath_uuid},
638         {'d', "sysfs",         0, snprint_sysfs},
639         {'F', "failback",      0, snprint_failback},
640         {'Q', "queueing",      0, snprint_queueing},
641         {'N', "paths",         0, snprint_nb_paths},
642         {'r', "write_prot",    0, snprint_ro},
643         {'t', "dm-st",         0, snprint_dm_map_state},
644         {'S', "size",          0, snprint_multipath_size},
645         {'f', "features",      0, snprint_features},
646         {'x', "failures",      0, snprint_map_failures},
647         {'h', "hwhandler",     0, snprint_hwhandler},
648         {'A', "action",        0, snprint_action},
649         {'0', "path_faults",   0, snprint_path_faults},
650         {'1', "switch_grp",    0, snprint_switch_grp},
651         {'2', "map_loads",     0, snprint_map_loads},
652         {'3', "total_q_time",  0, snprint_total_q_time},
653         {'4', "q_timeouts",    0, snprint_q_timeouts},
654         {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
655         {'v', "vend",          0, snprint_multipath_vend},
656         {'p', "prod",          0, snprint_multipath_prod},
657         {'e', "rev",           0, snprint_multipath_rev},
658         {'G', "foreign",       0, snprint_multipath_foreign},
659         {0, NULL, 0 , NULL}
660 };
661
662 struct path_data pd[] = {
663         {'w', "uuid",          0, snprint_path_uuid},
664         {'i', "hcil",          0, snprint_hcil},
665         {'d', "dev",           0, snprint_dev},
666         {'D', "dev_t",         0, snprint_dev_t},
667         {'t', "dm_st",         0, snprint_dm_path_state},
668         {'o', "dev_st",        0, snprint_offline},
669         {'T', "chk_st",        0, snprint_chk_state},
670         {'s', "vend/prod/rev", 0, snprint_vpr},
671         {'c', "checker",       0, snprint_path_checker},
672         {'C', "next_check",    0, snprint_next_check},
673         {'p', "pri",           0, snprint_pri},
674         {'S', "size",          0, snprint_path_size},
675         {'z', "serial",        0, snprint_path_serial},
676         {'m', "multipath",     0, snprint_path_mpp},
677         {'N', "host WWNN",     0, snprint_host_wwnn},
678         {'n', "target WWNN",   0, snprint_tgt_wwnn},
679         {'R', "host WWPN",     0, snprint_host_wwpn},
680         {'r', "target WWPN",   0, snprint_tgt_wwpn},
681         {'a', "host adapter",  0, snprint_host_adapter},
682         {'G', "foreign",       0, snprint_path_foreign},
683         {0, NULL, 0 , NULL}
684 };
685
686 struct pathgroup_data pgd[] = {
687         {'s', "selector",      0, snprint_pg_selector},
688         {'p', "pri",           0, snprint_pg_pri},
689         {'t', "dm_st",         0, snprint_pg_state},
690         {0, NULL, 0 , NULL}
691 };
692
693 int
694 snprint_wildcards (char * buff, int len)
695 {
696         int i, fwd = 0;
697
698         fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
699         for (i = 0; mpd[i].header; i++)
700                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
701                                 mpd[i].wildcard, mpd[i].header);
702         fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
703         for (i = 0; pd[i].header; i++)
704                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
705                                 pd[i].wildcard, pd[i].header);
706         fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
707         for (i = 0; pgd[i].header; i++)
708                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
709                                 pgd[i].wildcard, pgd[i].header);
710         return fwd;
711 }
712
713 void
714 get_path_layout(vector pathvec, int header)
715 {
716         vector gpvec = vector_convert(NULL, pathvec, struct path,
717                                       dm_path_to_gen);
718         _get_path_layout(gpvec,
719                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
720         vector_free(gpvec);
721 }
722
723 static void
724 reset_width(int *width, enum layout_reset reset, const char *header)
725 {
726         switch (reset) {
727         case LAYOUT_RESET_HEADER:
728                 *width = strlen(header);
729                 break;
730         case LAYOUT_RESET_ZERO:
731                 *width = 0;
732                 break;
733         default:
734                 /* don't reset */
735                 break;
736         }
737 }
738
739 void
740 _get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
741 {
742         int i, j;
743         char buff[MAX_FIELD_LEN];
744         const struct gen_path *gp;
745
746         for (j = 0; pd[j].header; j++) {
747
748                 reset_width(&pd[j].width, reset, pd[j].header);
749
750                 if (gpvec == NULL)
751                         continue;
752
753                 vector_foreach_slot (gpvec, gp, i) {
754                         gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
755                                          pd[j].wildcard);
756                         pd[j].width = MAX(pd[j].width, strlen(buff));
757                 }
758         }
759 }
760
761 static void
762 reset_multipath_layout (void)
763 {
764         int i;
765
766         for (i = 0; mpd[i].header; i++)
767                 mpd[i].width = 0;
768 }
769
770 void
771 get_multipath_layout (vector mpvec, int header) {
772         vector gmvec = vector_convert(NULL, mpvec, struct multipath,
773                                       dm_multipath_to_gen);
774         _get_multipath_layout(gmvec,
775                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
776         vector_free(gmvec);
777 }
778
779 void
780 _get_multipath_layout (const struct _vector *gmvec,
781                             enum layout_reset reset)
782 {
783         int i, j;
784         char buff[MAX_FIELD_LEN];
785         const struct gen_multipath * gm;
786
787         for (j = 0; mpd[j].header; j++) {
788
789                 reset_width(&mpd[j].width, reset, mpd[j].header);
790
791                 if (gmvec == NULL)
792                         continue;
793
794                 vector_foreach_slot (gmvec, gm, i) {
795                         gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
796                                          mpd[j].wildcard);
797                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
798                 }
799                 condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
800         }
801 }
802
803 static struct multipath_data *
804 mpd_lookup(char wildcard)
805 {
806         int i;
807
808         for (i = 0; mpd[i].header; i++)
809                 if (mpd[i].wildcard == wildcard)
810                         return &mpd[i];
811
812         return NULL;
813 }
814
815 int snprint_multipath_attr(const struct gen_multipath* gm,
816                            char *buf, int len, char wildcard)
817 {
818         const struct multipath *mpp = gen_multipath_to_dm(gm);
819         struct multipath_data *mpd = mpd_lookup(wildcard);
820
821         if (mpd == NULL)
822                 return 0;
823         return mpd->snprint(buf, len, mpp);
824 }
825
826 static struct path_data *
827 pd_lookup(char wildcard)
828 {
829         int i;
830
831         for (i = 0; pd[i].header; i++)
832                 if (pd[i].wildcard == wildcard)
833                         return &pd[i];
834
835         return NULL;
836 }
837
838 int snprint_path_attr(const struct gen_path* gp,
839                       char *buf, int len, char wildcard)
840 {
841         const struct path *pp = gen_path_to_dm(gp);
842         struct path_data *pd = pd_lookup(wildcard);
843
844         if (pd == NULL)
845                 return 0;
846         return pd->snprint(buf, len, pp);
847 }
848
849 static struct pathgroup_data *
850 pgd_lookup(char wildcard)
851 {
852         int i;
853
854         for (i = 0; pgd[i].header; i++)
855                 if (pgd[i].wildcard == wildcard)
856                         return &pgd[i];
857
858         return NULL;
859 }
860
861 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
862                            char *buf, int len, char wildcard)
863 {
864         const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
865         struct pathgroup_data *pdg = pgd_lookup(wildcard);
866
867         if (pdg == NULL)
868                 return 0;
869         return pdg->snprint(buf, len, pg);
870 }
871
872 int
873 snprint_multipath_header (char * line, int len, const char * format)
874 {
875         char * c = line;   /* line cursor */
876         char * s = line;   /* for padding */
877         const char * f = format; /* format string cursor */
878         int fwd;
879         struct multipath_data * data;
880
881         do {
882                 if (TAIL <= 0)
883                         break;
884
885                 if (*f != '%') {
886                         *c++ = *f;
887                         NOPAD;
888                         continue;
889                 }
890                 f++;
891
892                 if (!(data = mpd_lookup(*f)))
893                         continue; /* unknown wildcard */
894
895                 PRINT(c, TAIL, "%s", data->header);
896                 PAD(data->width);
897         } while (*f++);
898
899         __endline(line, len, c);
900         return (c - line);
901 }
902
903 int
904 _snprint_multipath (const struct gen_multipath * gmp,
905                     char * line, int len, const char * format, int pad)
906 {
907         char * c = line;   /* line cursor */
908         char * s = line;   /* for padding */
909         const char * f = format; /* format string cursor */
910         int fwd;
911         struct multipath_data * data;
912         char buff[MAX_FIELD_LEN] = {};
913
914         do {
915                 if (TAIL <= 0)
916                         break;
917
918                 if (*f != '%') {
919                         *c++ = *f;
920                         NOPAD;
921                         continue;
922                 }
923                 f++;
924
925                 if (!(data = mpd_lookup(*f)))
926                         continue;
927
928                 gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
929                 PRINT(c, TAIL, "%s", buff);
930                 if (pad)
931                         PAD(data->width);
932                 buff[0] = '\0';
933         } while (*f++);
934
935         __endline(line, len, c);
936         return (c - line);
937 }
938
939 int
940 snprint_path_header (char * line, int len, const char * format)
941 {
942         char * c = line;   /* line cursor */
943         char * s = line;   /* for padding */
944         const char * f = format; /* format string cursor */
945         int fwd;
946         struct path_data * data;
947
948         do {
949                 if (TAIL <= 0)
950                         break;
951
952                 if (*f != '%') {
953                         *c++ = *f;
954                         NOPAD;
955                         continue;
956                 }
957                 f++;
958
959                 if (!(data = pd_lookup(*f)))
960                         continue; /* unknown wildcard */
961
962                 PRINT(c, TAIL, "%s", data->header);
963                 PAD(data->width);
964         } while (*f++);
965
966         __endline(line, len, c);
967         return (c - line);
968 }
969
970 int
971 _snprint_path (const struct gen_path * gp, char * line, int len,
972                const char * format, int pad)
973 {
974         char * c = line;   /* line cursor */
975         char * s = line;   /* for padding */
976         const char * f = format; /* format string cursor */
977         int fwd;
978         struct path_data * data;
979         char buff[MAX_FIELD_LEN];
980
981         do {
982                 if (TAIL <= 0)
983                         break;
984
985                 if (*f != '%') {
986                         *c++ = *f;
987                         NOPAD;
988                         continue;
989                 }
990                 f++;
991
992                 if (!(data = pd_lookup(*f)))
993                         continue;
994
995                 gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
996                 PRINT(c, TAIL, "%s", buff);
997                 if (pad)
998                         PAD(data->width);
999         } while (*f++);
1000
1001         __endline(line, len, c);
1002         return (c - line);
1003 }
1004
1005 int
1006 _snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
1007                     char * format)
1008 {
1009         char * c = line;   /* line cursor */
1010         char * s = line;   /* for padding */
1011         char * f = format; /* format string cursor */
1012         int fwd;
1013         struct pathgroup_data * data;
1014         char buff[MAX_FIELD_LEN];
1015
1016         do {
1017                 if (TAIL <= 0)
1018                         break;
1019
1020                 if (*f != '%') {
1021                         *c++ = *f;
1022                         NOPAD;
1023                         continue;
1024                 }
1025                 f++;
1026
1027                 if (!(data = pgd_lookup(*f)))
1028                         continue;
1029
1030                 ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
1031                 PRINT(c, TAIL, "%s", buff);
1032                 PAD(data->width);
1033         } while (*f++);
1034
1035         __endline(line, len, c);
1036         return (c - line);
1037 }
1038 #define snprint_pathgroup(line, len, fmt, pgp) \
1039         _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
1040
1041 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1042 {
1043         int resize;
1044         char *buff = NULL;
1045         char *old = NULL;
1046         int len, maxlen = MAX_LINE_LEN * MAX_LINES;
1047
1048         buff = MALLOC(maxlen);
1049         do {
1050                 if (!buff) {
1051                         if (old)
1052                                 FREE(old);
1053                         condlog(0, "couldn't allocate memory for list: %s\n",
1054                                 strerror(errno));
1055                         return;
1056                 }
1057
1058                 len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
1059                 resize = (len == maxlen - 1);
1060
1061                 if (resize) {
1062                         maxlen *= 2;
1063                         old = buff;
1064                         buff = REALLOC(buff, maxlen);
1065                 }
1066         } while (resize);
1067         printf("%s", buff);
1068         FREE(buff);
1069 }
1070
1071 int
1072 snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
1073                         int verbosity)
1074 {
1075         int n;
1076         const struct multipath *mpp = gen_multipath_to_dm(gmp);
1077         bool need_action = (verbosity > 1 &&
1078                             mpp->action != ACT_NOTHING &&
1079                             mpp->action != ACT_UNDEF &&
1080                             mpp->action != ACT_IMPOSSIBLE);
1081         bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1082
1083         n = snprintf(style, len, "%s%s%s%s",
1084                      need_action ? "%A: " : "", "%n",
1085                      need_wwid ? " (%w)" : "", " %d %s");
1086         return MIN(n, len - 1);
1087 }
1088
1089 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1090                                 char *buff, int len, int verbosity)
1091 {
1092         int j, i, fwd = 0;
1093         const struct _vector *pgvec;
1094         const struct gen_pathgroup *gpg;
1095         char style[64];
1096         char * c = style;
1097         char fmt[64];
1098         char * f;
1099
1100         if (verbosity <= 0)
1101                 return fwd;
1102
1103         reset_multipath_layout();
1104
1105         if (verbosity == 1)
1106                 return _snprint_multipath(gmp, buff, len, "%n", 1);
1107
1108         if(isatty(1))
1109                 c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
1110
1111         c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
1112                              verbosity);
1113         if(isatty(1))
1114                 c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
1115
1116         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
1117         if (fwd >= len)
1118                 return len;
1119         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
1120                                   PRINT_MAP_PROPS, 1);
1121         if (fwd >= len)
1122                 return len;
1123
1124         pgvec = gmp->ops->get_pathgroups(gmp);
1125         if (pgvec == NULL)
1126                 return fwd;
1127
1128         vector_foreach_slot (pgvec, gpg, j) {
1129                 const struct _vector *pathvec;
1130                 struct gen_path *gp;
1131
1132                 f=fmt;
1133
1134                 if (j + 1 < VECTOR_SIZE(pgvec)) {
1135                         strcpy(f, "|-+- " PRINT_PG_INDENT);
1136                 } else
1137                         strcpy(f, "`-+- " PRINT_PG_INDENT);
1138                 fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
1139
1140                 if (fwd >= len) {
1141                         fwd = len;
1142                         break;
1143                 }
1144
1145                 pathvec = gpg->ops->get_paths(gpg);
1146                 if (pathvec == NULL)
1147                         continue;
1148
1149                 vector_foreach_slot (pathvec, gp, i) {
1150                         f=fmt;
1151                         if (*f != '|')
1152                                 *f=' ';
1153                         f++;
1154                         if (i + 1 < VECTOR_SIZE(pathvec))
1155                                 strcpy(f, " |- " PRINT_PATH_INDENT);
1156                         else
1157                                 strcpy(f, " `- " PRINT_PATH_INDENT);
1158                         fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
1159                         if (fwd >= len) {
1160                                 fwd = len;
1161                                 break;
1162                         }
1163                 }
1164                 gpg->ops->rel_paths(gpg, pathvec);
1165
1166                 if (fwd == len)
1167                         break;
1168         }
1169         gmp->ops->rel_pathgroups(gmp, pgvec);
1170         return fwd;
1171 }
1172
1173
1174 static int
1175 snprint_json (char * buff, int len, int indent, char *json_str)
1176 {
1177         int fwd = 0, i;
1178
1179         for (i = 0; i < indent; i++) {
1180                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1181                 if (fwd >= len)
1182                         return fwd;
1183         }
1184
1185         fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
1186         return fwd;
1187 }
1188
1189 static int
1190 snprint_json_header (char * buff, int len)
1191 {
1192         int fwd = 0;
1193
1194         fwd +=  snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
1195         if (fwd >= len)
1196                 return fwd;
1197
1198         fwd +=  snprintf(buff + fwd, len  - fwd, PRINT_JSON_START_VERSION,
1199                         PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1200         return fwd;
1201 }
1202
1203 static int
1204 snprint_json_elem_footer (char * buff, int len, int indent, int last)
1205 {
1206         int fwd = 0, i;
1207
1208         for (i = 0; i < indent; i++) {
1209                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1210                 if (fwd >= len)
1211                         return fwd;
1212         }
1213
1214         if (last == 1)
1215                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
1216         else
1217                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
1218         return fwd;
1219 }
1220
1221 static int
1222 snprint_multipath_fields_json (char * buff, int len,
1223                 const struct multipath * mpp, int last)
1224 {
1225         int i, j, fwd = 0;
1226         struct path *pp;
1227         struct pathgroup *pgp;
1228
1229         fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
1230         if (fwd >= len)
1231                 return fwd;
1232
1233         fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
1234         if (fwd >= len)
1235                 return fwd;
1236
1237         vector_foreach_slot (mpp->pg, pgp, i) {
1238
1239                 fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
1240                 if (fwd >= len)
1241                         return fwd;
1242
1243                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
1244                 if (fwd >= len)
1245                         return fwd;
1246
1247                 fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
1248                 if (fwd >= len)
1249                         return fwd;
1250
1251                 vector_foreach_slot (pgp->paths, pp, j) {
1252                         fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
1253                         if (fwd >= len)
1254                                 return fwd;
1255
1256                         fwd += snprint_json_elem_footer(buff + fwd,
1257                                         len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
1258                         if (fwd >= len)
1259                                 return fwd;
1260                 }
1261                 fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1262                 if (fwd >= len)
1263                         return fwd;
1264
1265                 fwd +=  snprint_json_elem_footer(buff + fwd,
1266                                 len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
1267                 if (fwd >= len)
1268                         return fwd;
1269         }
1270
1271         fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1272         if (fwd >= len)
1273                 return fwd;
1274
1275         fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
1276         return fwd;
1277 }
1278
1279 int
1280 snprint_multipath_map_json (char * buff, int len,
1281                 const struct multipath * mpp, int last){
1282         int fwd = 0;
1283
1284         fwd +=  snprint_json_header(buff, len);
1285         if (fwd >= len)
1286                 return len;
1287
1288         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
1289         if (fwd >= len)
1290                 return len;
1291
1292         fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
1293         if (fwd >= len)
1294                 return len;
1295
1296         fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n");
1297         if (fwd >= len)
1298                 return len;
1299
1300         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1301         if (fwd >= len)
1302                 return len;
1303         return fwd;
1304 }
1305
1306 int
1307 snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
1308 {
1309         int i, fwd = 0;
1310         struct multipath * mpp;
1311
1312         fwd +=  snprint_json_header(buff, len);
1313         if (fwd >= len)
1314                 return len;
1315
1316         fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);
1317         if (fwd >= len)
1318                 return len;
1319
1320         vector_foreach_slot(vecs->mpvec, mpp, i) {
1321                 fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
1322                                 mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
1323                 if (fwd >= len)
1324                         return len;
1325         }
1326
1327         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1328         if (fwd >= len)
1329                 return len;
1330
1331         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1332         if (fwd >= len)
1333                 return len;
1334         return fwd;
1335 }
1336
1337 static int
1338 snprint_hwentry (struct config *conf, char * buff, int len, const struct hwentry * hwe)
1339 {
1340         int i;
1341         int fwd = 0;
1342         struct keyword * kw;
1343         struct keyword * rootkw;
1344
1345         rootkw = find_keyword(conf->keywords, NULL, "devices");
1346
1347         if (!rootkw || !rootkw->sub)
1348                 return 0;
1349
1350         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1351
1352         if (!rootkw)
1353                 return 0;
1354
1355         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1356         if (fwd >= len)
1357                 return len;
1358         iterate_sub_keywords(rootkw, kw, i) {
1359                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1360                                 kw, hwe);
1361                 if (fwd >= len)
1362                         return len;
1363         }
1364         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1365         if (fwd >= len)
1366                 return len;
1367         return fwd;
1368 }
1369
1370 int snprint_hwtable(struct config *conf, char *buff, int len, vector hwtable)
1371 {
1372         int fwd = 0;
1373         int i;
1374         struct hwentry * hwe;
1375         struct keyword * rootkw;
1376
1377         rootkw = find_keyword(conf->keywords, NULL, "devices");
1378         if (!rootkw)
1379                 return 0;
1380
1381         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
1382         if (fwd >= len)
1383                 return len;
1384         vector_foreach_slot (hwtable, hwe, i) {
1385                 fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
1386                 if (fwd >= len)
1387                         return len;
1388         }
1389         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1390         if (fwd >= len)
1391                 return len;
1392         return fwd;
1393 }
1394
1395 static int
1396 snprint_mpentry (struct config *conf, char * buff, int len, const struct mpentry * mpe)
1397 {
1398         int i;
1399         int fwd = 0;
1400         struct keyword * kw;
1401         struct keyword * rootkw;
1402
1403         rootkw = find_keyword(conf->keywords, NULL, "multipath");
1404         if (!rootkw)
1405                 return 0;
1406
1407         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
1408         if (fwd >= len)
1409                 return len;
1410         iterate_sub_keywords(rootkw, kw, i) {
1411                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1412                                 kw, mpe);
1413                 if (fwd >= len)
1414                         return len;
1415         }
1416         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1417         if (fwd >= len)
1418                 return len;
1419         return fwd;
1420 }
1421
1422 int snprint_mptable(struct config *conf, char *buff, int len, vector mptable)
1423 {
1424         int fwd = 0;
1425         int i;
1426         struct mpentry * mpe;
1427         struct keyword * rootkw;
1428
1429         rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1430         if (!rootkw)
1431                 return 0;
1432
1433         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
1434         if (fwd >= len)
1435                 return len;
1436         vector_foreach_slot (mptable, mpe, i) {
1437                 fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe);
1438                 if (fwd >= len)
1439                         return len;
1440         }
1441         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1442         if (fwd >= len)
1443                 return len;
1444         return fwd;
1445 }
1446
1447 int snprint_overrides(struct config *conf, char * buff, int len,
1448                       const struct hwentry *overrides)
1449 {
1450         int fwd = 0;
1451         int i;
1452         struct keyword *rootkw;
1453         struct keyword *kw;
1454
1455         rootkw = find_keyword(conf->keywords, NULL, "overrides");
1456         if (!rootkw)
1457                 return 0;
1458
1459         fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
1460         if (fwd >= len)
1461                 return len;
1462         if (!overrides)
1463                 goto out;
1464         iterate_sub_keywords(rootkw, kw, i) {
1465                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1466                                        kw, NULL);
1467                 if (fwd >= len)
1468                         return len;
1469         }
1470 out:
1471         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1472         if (fwd >= len)
1473                 return len;
1474         return fwd;
1475 }
1476
1477 int snprint_defaults(struct config *conf, char *buff, int len)
1478 {
1479         int fwd = 0;
1480         int i;
1481         struct keyword *rootkw;
1482         struct keyword *kw;
1483
1484         rootkw = find_keyword(conf->keywords, NULL, "defaults");
1485         if (!rootkw)
1486                 return 0;
1487
1488         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
1489         if (fwd >= len)
1490                 return len;
1491
1492         iterate_sub_keywords(rootkw, kw, i) {
1493                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1494                                 kw, NULL);
1495                 if (fwd >= len)
1496                         return len;
1497         }
1498         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1499         if (fwd >= len)
1500                 return len;
1501         return fwd;
1502 }
1503
1504 static int
1505 snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
1506 {
1507         int threshold = MAX_LINE_LEN;
1508         struct blentry * ble;
1509         int pos;
1510         int i;
1511
1512         pos = *fwd;
1513         if (!VECTOR_SIZE(*vec)) {
1514                 if ((len - pos - threshold) <= 0)
1515                         return 0;
1516                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1517         } else vector_foreach_slot (*vec, ble, i) {
1518                 if ((len - pos - threshold) <= 0)
1519                         return 0;
1520                 if (ble->origin == ORIGIN_CONFIG)
1521                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1522                 else if (ble->origin == ORIGIN_DEFAULT)
1523                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1524                 pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
1525         }
1526
1527         *fwd = pos;
1528         return pos;
1529 }
1530
1531 static int
1532 snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
1533 {
1534         int threshold = MAX_LINE_LEN;
1535         struct blentry_device * bled;
1536         int pos;
1537         int i;
1538
1539         pos = *fwd;
1540         if (!VECTOR_SIZE(*vec)) {
1541                 if ((len - pos - threshold) <= 0)
1542                         return 0;
1543                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1544         } else vector_foreach_slot (*vec, bled, i) {
1545                 if ((len - pos - threshold) <= 0)
1546                         return 0;
1547                 if (bled->origin == ORIGIN_CONFIG)
1548                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1549                 else if (bled->origin == ORIGIN_DEFAULT)
1550                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1551                 pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
1552         }
1553
1554         *fwd = pos;
1555         return pos;
1556 }
1557
1558 int snprint_blacklist_report(struct config *conf, char *buff, int len)
1559 {
1560         int threshold = MAX_LINE_LEN;
1561         int fwd = 0;
1562
1563         if ((len - fwd - threshold) <= 0)
1564                 return len;
1565         fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
1566                                                "- blacklist:\n");
1567         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
1568                 return len;
1569
1570         if ((len - fwd - threshold) <= 0)
1571                 return len;
1572         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1573         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
1574                 return len;
1575
1576         if ((len - fwd - threshold) <= 0)
1577                 return len;
1578         fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
1579                                                "- blacklist:\n");
1580         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
1581                 return len;
1582
1583         if ((len - fwd - threshold) <= 0)
1584                 return len;
1585         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1586         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
1587                 return len;
1588
1589         if ((len - fwd - threshold) <= 0)
1590                 return len;
1591         fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
1592                                                "- blacklist:\n");
1593         if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
1594                 return len;
1595
1596         if ((len - fwd - threshold) <= 0)
1597                 return len;
1598         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1599         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
1600                 return len;
1601
1602         if ((len - fwd - threshold) <= 0)
1603                 return len;
1604         fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
1605                                                "- blacklist:\n");
1606         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
1607                 return len;
1608
1609         if ((len - fwd - threshold) <= 0)
1610                 return len;
1611         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1612         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
1613                 return len;
1614
1615         if (fwd > len)
1616                 return len;
1617         return fwd;
1618 }
1619
1620 int snprint_blacklist(struct config *conf, char *buff, int len)
1621 {
1622         int i;
1623         struct blentry * ble;
1624         struct blentry_device * bled;
1625         int fwd = 0;
1626         struct keyword *rootkw;
1627         struct keyword *kw;
1628
1629         rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1630         if (!rootkw)
1631                 return 0;
1632
1633         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
1634         if (fwd >= len)
1635                 return len;
1636
1637         vector_foreach_slot (conf->blist_devnode, ble, i) {
1638                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1639                 if (!kw)
1640                         return 0;
1641                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1642                                        kw, ble);
1643                 if (fwd >= len)
1644                         return len;
1645         }
1646         vector_foreach_slot (conf->blist_wwid, ble, i) {
1647                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1648                 if (!kw)
1649                         return 0;
1650                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1651                                        kw, ble);
1652                 if (fwd >= len)
1653                         return len;
1654         }
1655         vector_foreach_slot (conf->blist_property, ble, i) {
1656                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1657                 if (!kw)
1658                         return 0;
1659                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1660                                        kw, ble);
1661                 if (fwd >= len)
1662                         return len;
1663         }
1664         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1665         if (!rootkw)
1666                 return 0;
1667
1668         vector_foreach_slot (conf->blist_device, bled, i) {
1669                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1670                 if (fwd >= len)
1671                         return len;
1672                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1673                 if (!kw)
1674                         return 0;
1675                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1676                                        kw, bled);
1677                 if (fwd >= len)
1678                         return len;
1679                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1680                 if (!kw)
1681                         return 0;
1682                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1683                                        kw, bled);
1684                 if (fwd >= len)
1685                         return len;
1686                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1687                 if (fwd >= len)
1688                         return len;
1689         }
1690         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1691         if (fwd >= len)
1692                 return len;
1693         return fwd;
1694 }
1695
1696 int snprint_blacklist_except(struct config *conf, char *buff, int len)
1697 {
1698         int i;
1699         struct blentry * ele;
1700         struct blentry_device * eled;
1701         int fwd = 0;
1702         struct keyword *rootkw;
1703         struct keyword *kw;
1704
1705         rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1706         if (!rootkw)
1707                 return 0;
1708
1709         fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
1710         if (fwd >= len)
1711                 return len;
1712
1713         vector_foreach_slot (conf->elist_devnode, ele, i) {
1714                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1715                 if (!kw)
1716                         return 0;
1717                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1718                                        kw, ele);
1719                 if (fwd >= len)
1720                         return len;
1721         }
1722         vector_foreach_slot (conf->elist_wwid, ele, i) {
1723                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1724                 if (!kw)
1725                         return 0;
1726                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1727                                        kw, ele);
1728                 if (fwd >= len)
1729                         return len;
1730         }
1731         vector_foreach_slot (conf->elist_property, ele, i) {
1732                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1733                 if (!kw)
1734                         return 0;
1735                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1736                                        kw, ele);
1737                 if (fwd >= len)
1738                         return len;
1739         }
1740         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1741         if (!rootkw)
1742                 return 0;
1743
1744         vector_foreach_slot (conf->elist_device, eled, i) {
1745                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1746                 if (fwd >= len)
1747                         return len;
1748                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
1749                 if (!kw)
1750                         return 0;
1751                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1752                                        kw, eled);
1753                 if (fwd >= len)
1754                         return len;
1755                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1756                 if (!kw)
1757                         return 0;
1758                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1759                                        kw, eled);
1760                 if (fwd >= len)
1761                         return len;
1762                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1763                 if (fwd >= len)
1764                         return len;
1765         }
1766         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1767         if (fwd >= len)
1768                 return len;
1769         return fwd;
1770 }
1771
1772 int snprint_status(char *buff, int len, const struct vectors *vecs)
1773 {
1774         int fwd = 0;
1775         int i;
1776         unsigned int count[PATH_MAX_STATE] = {0};
1777         struct path * pp;
1778
1779         vector_foreach_slot (vecs->pathvec, pp, i) {
1780                 count[pp->state]++;
1781         }
1782         fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
1783         for (i=0; i<PATH_MAX_STATE; i++) {
1784                 if (!count[i])
1785                         continue;
1786                 fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
1787                                 checker_state_name(i), count[i]);
1788         }
1789
1790         int monitored_count = 0;
1791
1792         vector_foreach_slot(vecs->pathvec, pp, i)
1793                 if (pp->fd >= 0)
1794                         monitored_count++;
1795         fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
1796                         monitored_count, is_uevent_busy()? "True" : "False");
1797
1798         if (fwd >= len)
1799                 return len;
1800         return fwd;
1801 }
1802
1803 int snprint_devices(struct config *conf, char * buff, int len,
1804                     const struct vectors *vecs)
1805 {
1806         DIR *blkdir;
1807         struct dirent *blkdev;
1808         struct stat statbuf;
1809         char devpath[PATH_MAX];
1810         char *devptr;
1811         int threshold = MAX_LINE_LEN;
1812         int fwd = 0;
1813         int r;
1814
1815         struct path * pp;
1816
1817         if (!(blkdir = opendir("/sys/block")))
1818                 return 1;
1819
1820         if ((len - fwd - threshold) <= 0) {
1821                 closedir(blkdir);
1822                 return len;
1823         }
1824         fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
1825
1826         strcpy(devpath,"/sys/block/");
1827         while ((blkdev = readdir(blkdir)) != NULL) {
1828                 if ((strcmp(blkdev->d_name,".") == 0) ||
1829                     (strcmp(blkdev->d_name,"..") == 0))
1830                         continue;
1831
1832                 devptr = devpath + 11;
1833                 *devptr = '\0';
1834                 strncat(devptr, blkdev->d_name, PATH_MAX-12);
1835                 if (stat(devpath, &statbuf) < 0)
1836                         continue;
1837
1838                 if (S_ISDIR(statbuf.st_mode) == 0)
1839                         continue;
1840
1841                 if ((len - fwd - threshold)  <= 0) {
1842                         closedir(blkdir);
1843                         return len;
1844                 }
1845
1846                 fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
1847                 pp = find_path_by_dev(vecs->pathvec, devptr);
1848                 if (!pp) {
1849                         r = filter_devnode(conf->blist_devnode,
1850                                            conf->elist_devnode, devptr);
1851                         if (r > 0)
1852                                 fwd += snprintf(buff + fwd, len - fwd,
1853                                                 " devnode blacklisted, unmonitored");
1854                         else if (r <= 0)
1855                                 fwd += snprintf(buff + fwd, len - fwd,
1856                                                 " devnode whitelisted, unmonitored");
1857                 } else
1858                         fwd += snprintf(buff + fwd, len - fwd,
1859                                         " devnode whitelisted, monitored");
1860                 fwd += snprintf(buff + fwd, len - fwd, "\n");
1861         }
1862         closedir(blkdir);
1863
1864         if (fwd >= len)
1865                 return len;
1866         return fwd;
1867 }
1868
1869 /*
1870  * stdout printing helpers
1871  */
1872 void print_path(struct path *pp, char *style)
1873 {
1874         char line[MAX_LINE_LEN];
1875
1876         memset(&line[0], 0, MAX_LINE_LEN);
1877         snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
1878         printf("%s", line);
1879 }
1880
1881 void print_all_paths(vector pathvec, int banner)
1882 {
1883         print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
1884 }
1885
1886 void print_all_paths_custo(vector pathvec, int banner, char *fmt)
1887 {
1888         int i;
1889         struct path * pp;
1890         char line[MAX_LINE_LEN];
1891
1892         if (!VECTOR_SIZE(pathvec)) {
1893                 if (banner)
1894                         fprintf(stdout, "===== no paths =====\n");
1895                 return;
1896         }
1897
1898         if (banner)
1899                 fprintf(stdout, "===== paths list =====\n");
1900
1901         get_path_layout(pathvec, 1);
1902         snprint_path_header(line, MAX_LINE_LEN, fmt);
1903         fprintf(stdout, "%s", line);
1904
1905         vector_foreach_slot (pathvec, pp, i)
1906                 print_path(pp, fmt);
1907 }