multipathd: fix reservation_key check
[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 static int
636 snprint_path_failures(char * buff, size_t len, const struct path * pp)
637 {
638         return snprint_int(buff, len, pp->failcount);
639 }
640
641 struct multipath_data mpd[] = {
642         {'n', "name",          0, snprint_name},
643         {'w', "uuid",          0, snprint_multipath_uuid},
644         {'d', "sysfs",         0, snprint_sysfs},
645         {'F', "failback",      0, snprint_failback},
646         {'Q', "queueing",      0, snprint_queueing},
647         {'N', "paths",         0, snprint_nb_paths},
648         {'r', "write_prot",    0, snprint_ro},
649         {'t', "dm-st",         0, snprint_dm_map_state},
650         {'S', "size",          0, snprint_multipath_size},
651         {'f', "features",      0, snprint_features},
652         {'x', "failures",      0, snprint_map_failures},
653         {'h', "hwhandler",     0, snprint_hwhandler},
654         {'A', "action",        0, snprint_action},
655         {'0', "path_faults",   0, snprint_path_faults},
656         {'1', "switch_grp",    0, snprint_switch_grp},
657         {'2', "map_loads",     0, snprint_map_loads},
658         {'3', "total_q_time",  0, snprint_total_q_time},
659         {'4', "q_timeouts",    0, snprint_q_timeouts},
660         {'s', "vend/prod/rev", 0, snprint_multipath_vpr},
661         {'v', "vend",          0, snprint_multipath_vend},
662         {'p', "prod",          0, snprint_multipath_prod},
663         {'e', "rev",           0, snprint_multipath_rev},
664         {'G', "foreign",       0, snprint_multipath_foreign},
665         {0, NULL, 0 , NULL}
666 };
667
668 struct path_data pd[] = {
669         {'w', "uuid",          0, snprint_path_uuid},
670         {'i', "hcil",          0, snprint_hcil},
671         {'d', "dev",           0, snprint_dev},
672         {'D', "dev_t",         0, snprint_dev_t},
673         {'t', "dm_st",         0, snprint_dm_path_state},
674         {'o', "dev_st",        0, snprint_offline},
675         {'T', "chk_st",        0, snprint_chk_state},
676         {'s', "vend/prod/rev", 0, snprint_vpr},
677         {'c', "checker",       0, snprint_path_checker},
678         {'C', "next_check",    0, snprint_next_check},
679         {'p', "pri",           0, snprint_pri},
680         {'S', "size",          0, snprint_path_size},
681         {'z', "serial",        0, snprint_path_serial},
682         {'m', "multipath",     0, snprint_path_mpp},
683         {'N', "host WWNN",     0, snprint_host_wwnn},
684         {'n', "target WWNN",   0, snprint_tgt_wwnn},
685         {'R', "host WWPN",     0, snprint_host_wwpn},
686         {'r', "target WWPN",   0, snprint_tgt_wwpn},
687         {'a', "host adapter",  0, snprint_host_adapter},
688         {'G', "foreign",       0, snprint_path_foreign},
689         {'0', "failures",      0, snprint_path_failures},
690         {0, NULL, 0 , NULL}
691 };
692
693 struct pathgroup_data pgd[] = {
694         {'s', "selector",      0, snprint_pg_selector},
695         {'p', "pri",           0, snprint_pg_pri},
696         {'t', "dm_st",         0, snprint_pg_state},
697         {0, NULL, 0 , NULL}
698 };
699
700 int
701 snprint_wildcards (char * buff, int len)
702 {
703         int i, fwd = 0;
704
705         fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
706         for (i = 0; mpd[i].header; i++)
707                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
708                                 mpd[i].wildcard, mpd[i].header);
709         fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
710         for (i = 0; pd[i].header; i++)
711                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
712                                 pd[i].wildcard, pd[i].header);
713         fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
714         for (i = 0; pgd[i].header; i++)
715                 fwd += snprintf(buff + fwd, len - fwd, "%%%c  %s\n",
716                                 pgd[i].wildcard, pgd[i].header);
717         return fwd;
718 }
719
720 void
721 get_path_layout(vector pathvec, int header)
722 {
723         vector gpvec = vector_convert(NULL, pathvec, struct path,
724                                       dm_path_to_gen);
725         _get_path_layout(gpvec,
726                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
727         vector_free(gpvec);
728 }
729
730 static void
731 reset_width(int *width, enum layout_reset reset, const char *header)
732 {
733         switch (reset) {
734         case LAYOUT_RESET_HEADER:
735                 *width = strlen(header);
736                 break;
737         case LAYOUT_RESET_ZERO:
738                 *width = 0;
739                 break;
740         default:
741                 /* don't reset */
742                 break;
743         }
744 }
745
746 void
747 _get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
748 {
749         int i, j;
750         char buff[MAX_FIELD_LEN];
751         const struct gen_path *gp;
752
753         for (j = 0; pd[j].header; j++) {
754
755                 reset_width(&pd[j].width, reset, pd[j].header);
756
757                 if (gpvec == NULL)
758                         continue;
759
760                 vector_foreach_slot (gpvec, gp, i) {
761                         gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
762                                          pd[j].wildcard);
763                         pd[j].width = MAX(pd[j].width, strlen(buff));
764                 }
765         }
766 }
767
768 static void
769 reset_multipath_layout (void)
770 {
771         int i;
772
773         for (i = 0; mpd[i].header; i++)
774                 mpd[i].width = 0;
775 }
776
777 void
778 get_multipath_layout (vector mpvec, int header) {
779         vector gmvec = vector_convert(NULL, mpvec, struct multipath,
780                                       dm_multipath_to_gen);
781         _get_multipath_layout(gmvec,
782                          header ? LAYOUT_RESET_HEADER : LAYOUT_RESET_ZERO);
783         vector_free(gmvec);
784 }
785
786 void
787 _get_multipath_layout (const struct _vector *gmvec,
788                             enum layout_reset reset)
789 {
790         int i, j;
791         char buff[MAX_FIELD_LEN];
792         const struct gen_multipath * gm;
793
794         for (j = 0; mpd[j].header; j++) {
795
796                 reset_width(&mpd[j].width, reset, mpd[j].header);
797
798                 if (gmvec == NULL)
799                         continue;
800
801                 vector_foreach_slot (gmvec, gm, i) {
802                         gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
803                                          mpd[j].wildcard);
804                         mpd[j].width = MAX(mpd[j].width, strlen(buff));
805                 }
806                 condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
807         }
808 }
809
810 static struct multipath_data *
811 mpd_lookup(char wildcard)
812 {
813         int i;
814
815         for (i = 0; mpd[i].header; i++)
816                 if (mpd[i].wildcard == wildcard)
817                         return &mpd[i];
818
819         return NULL;
820 }
821
822 int snprint_multipath_attr(const struct gen_multipath* gm,
823                            char *buf, int len, char wildcard)
824 {
825         const struct multipath *mpp = gen_multipath_to_dm(gm);
826         struct multipath_data *mpd = mpd_lookup(wildcard);
827
828         if (mpd == NULL)
829                 return 0;
830         return mpd->snprint(buf, len, mpp);
831 }
832
833 static struct path_data *
834 pd_lookup(char wildcard)
835 {
836         int i;
837
838         for (i = 0; pd[i].header; i++)
839                 if (pd[i].wildcard == wildcard)
840                         return &pd[i];
841
842         return NULL;
843 }
844
845 int snprint_path_attr(const struct gen_path* gp,
846                       char *buf, int len, char wildcard)
847 {
848         const struct path *pp = gen_path_to_dm(gp);
849         struct path_data *pd = pd_lookup(wildcard);
850
851         if (pd == NULL)
852                 return 0;
853         return pd->snprint(buf, len, pp);
854 }
855
856 static struct pathgroup_data *
857 pgd_lookup(char wildcard)
858 {
859         int i;
860
861         for (i = 0; pgd[i].header; i++)
862                 if (pgd[i].wildcard == wildcard)
863                         return &pgd[i];
864
865         return NULL;
866 }
867
868 int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
869                            char *buf, int len, char wildcard)
870 {
871         const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
872         struct pathgroup_data *pdg = pgd_lookup(wildcard);
873
874         if (pdg == NULL)
875                 return 0;
876         return pdg->snprint(buf, len, pg);
877 }
878
879 int
880 snprint_multipath_header (char * line, int len, const char * format)
881 {
882         char * c = line;   /* line cursor */
883         char * s = line;   /* for padding */
884         const char * f = format; /* format string cursor */
885         int fwd;
886         struct multipath_data * data;
887
888         do {
889                 if (TAIL <= 0)
890                         break;
891
892                 if (*f != '%') {
893                         *c++ = *f;
894                         NOPAD;
895                         continue;
896                 }
897                 f++;
898
899                 if (!(data = mpd_lookup(*f)))
900                         continue; /* unknown wildcard */
901
902                 PRINT(c, TAIL, "%s", data->header);
903                 PAD(data->width);
904         } while (*f++);
905
906         __endline(line, len, c);
907         return (c - line);
908 }
909
910 int
911 _snprint_multipath (const struct gen_multipath * gmp,
912                     char * line, int len, const char * format, int pad)
913 {
914         char * c = line;   /* line cursor */
915         char * s = line;   /* for padding */
916         const char * f = format; /* format string cursor */
917         int fwd;
918         struct multipath_data * data;
919         char buff[MAX_FIELD_LEN] = {};
920
921         do {
922                 if (TAIL <= 0)
923                         break;
924
925                 if (*f != '%') {
926                         *c++ = *f;
927                         NOPAD;
928                         continue;
929                 }
930                 f++;
931
932                 if (!(data = mpd_lookup(*f)))
933                         continue;
934
935                 gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
936                 PRINT(c, TAIL, "%s", buff);
937                 if (pad)
938                         PAD(data->width);
939                 buff[0] = '\0';
940         } while (*f++);
941
942         __endline(line, len, c);
943         return (c - line);
944 }
945
946 int
947 snprint_path_header (char * line, int len, const char * format)
948 {
949         char * c = line;   /* line cursor */
950         char * s = line;   /* for padding */
951         const char * f = format; /* format string cursor */
952         int fwd;
953         struct path_data * data;
954
955         do {
956                 if (TAIL <= 0)
957                         break;
958
959                 if (*f != '%') {
960                         *c++ = *f;
961                         NOPAD;
962                         continue;
963                 }
964                 f++;
965
966                 if (!(data = pd_lookup(*f)))
967                         continue; /* unknown wildcard */
968
969                 PRINT(c, TAIL, "%s", data->header);
970                 PAD(data->width);
971         } while (*f++);
972
973         __endline(line, len, c);
974         return (c - line);
975 }
976
977 int
978 _snprint_path (const struct gen_path * gp, char * line, int len,
979                const char * format, int pad)
980 {
981         char * c = line;   /* line cursor */
982         char * s = line;   /* for padding */
983         const char * f = format; /* format string cursor */
984         int fwd;
985         struct path_data * data;
986         char buff[MAX_FIELD_LEN];
987
988         do {
989                 if (TAIL <= 0)
990                         break;
991
992                 if (*f != '%') {
993                         *c++ = *f;
994                         NOPAD;
995                         continue;
996                 }
997                 f++;
998
999                 if (!(data = pd_lookup(*f)))
1000                         continue;
1001
1002                 gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
1003                 PRINT(c, TAIL, "%s", buff);
1004                 if (pad)
1005                         PAD(data->width);
1006         } while (*f++);
1007
1008         __endline(line, len, c);
1009         return (c - line);
1010 }
1011
1012 int
1013 _snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
1014                     char * format)
1015 {
1016         char * c = line;   /* line cursor */
1017         char * s = line;   /* for padding */
1018         char * f = format; /* format string cursor */
1019         int fwd;
1020         struct pathgroup_data * data;
1021         char buff[MAX_FIELD_LEN];
1022
1023         do {
1024                 if (TAIL <= 0)
1025                         break;
1026
1027                 if (*f != '%') {
1028                         *c++ = *f;
1029                         NOPAD;
1030                         continue;
1031                 }
1032                 f++;
1033
1034                 if (!(data = pgd_lookup(*f)))
1035                         continue;
1036
1037                 ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
1038                 PRINT(c, TAIL, "%s", buff);
1039                 PAD(data->width);
1040         } while (*f++);
1041
1042         __endline(line, len, c);
1043         return (c - line);
1044 }
1045 #define snprint_pathgroup(line, len, fmt, pgp) \
1046         _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
1047
1048 void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
1049 {
1050         int resize;
1051         char *buff = NULL;
1052         char *old = NULL;
1053         int len, maxlen = MAX_LINE_LEN * MAX_LINES;
1054
1055         buff = MALLOC(maxlen);
1056         do {
1057                 if (!buff) {
1058                         if (old)
1059                                 FREE(old);
1060                         condlog(0, "couldn't allocate memory for list: %s\n",
1061                                 strerror(errno));
1062                         return;
1063                 }
1064
1065                 len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
1066                 resize = (len == maxlen - 1);
1067
1068                 if (resize) {
1069                         maxlen *= 2;
1070                         old = buff;
1071                         buff = REALLOC(buff, maxlen);
1072                 }
1073         } while (resize);
1074         printf("%s", buff);
1075         FREE(buff);
1076 }
1077
1078 int
1079 snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
1080                         int verbosity)
1081 {
1082         int n;
1083         const struct multipath *mpp = gen_multipath_to_dm(gmp);
1084         bool need_action = (verbosity > 1 &&
1085                             mpp->action != ACT_NOTHING &&
1086                             mpp->action != ACT_UNDEF &&
1087                             mpp->action != ACT_IMPOSSIBLE);
1088         bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
1089
1090         n = snprintf(style, len, "%s%s%s%s",
1091                      need_action ? "%A: " : "", "%n",
1092                      need_wwid ? " (%w)" : "", " %d %s");
1093         return MIN(n, len - 1);
1094 }
1095
1096 int _snprint_multipath_topology(const struct gen_multipath *gmp,
1097                                 char *buff, int len, int verbosity)
1098 {
1099         int j, i, fwd = 0;
1100         const struct _vector *pgvec;
1101         const struct gen_pathgroup *gpg;
1102         char style[64];
1103         char * c = style;
1104         char fmt[64];
1105         char * f;
1106
1107         if (verbosity <= 0)
1108                 return fwd;
1109
1110         reset_multipath_layout();
1111
1112         if (verbosity == 1)
1113                 return _snprint_multipath(gmp, buff, len, "%n", 1);
1114
1115         if(isatty(1))
1116                 c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
1117
1118         c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
1119                              verbosity);
1120         if(isatty(1))
1121                 c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
1122
1123         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
1124         if (fwd >= len)
1125                 return len;
1126         fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
1127                                   PRINT_MAP_PROPS, 1);
1128         if (fwd >= len)
1129                 return len;
1130
1131         pgvec = gmp->ops->get_pathgroups(gmp);
1132         if (pgvec == NULL)
1133                 return fwd;
1134
1135         vector_foreach_slot (pgvec, gpg, j) {
1136                 const struct _vector *pathvec;
1137                 struct gen_path *gp;
1138
1139                 f=fmt;
1140
1141                 if (j + 1 < VECTOR_SIZE(pgvec)) {
1142                         strcpy(f, "|-+- " PRINT_PG_INDENT);
1143                 } else
1144                         strcpy(f, "`-+- " PRINT_PG_INDENT);
1145                 fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
1146
1147                 if (fwd >= len) {
1148                         fwd = len;
1149                         break;
1150                 }
1151
1152                 pathvec = gpg->ops->get_paths(gpg);
1153                 if (pathvec == NULL)
1154                         continue;
1155
1156                 vector_foreach_slot (pathvec, gp, i) {
1157                         f=fmt;
1158                         if (*f != '|')
1159                                 *f=' ';
1160                         f++;
1161                         if (i + 1 < VECTOR_SIZE(pathvec))
1162                                 strcpy(f, " |- " PRINT_PATH_INDENT);
1163                         else
1164                                 strcpy(f, " `- " PRINT_PATH_INDENT);
1165                         fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
1166                         if (fwd >= len) {
1167                                 fwd = len;
1168                                 break;
1169                         }
1170                 }
1171                 gpg->ops->rel_paths(gpg, pathvec);
1172
1173                 if (fwd == len)
1174                         break;
1175         }
1176         gmp->ops->rel_pathgroups(gmp, pgvec);
1177         return fwd;
1178 }
1179
1180
1181 static int
1182 snprint_json (char * buff, int len, int indent, char *json_str)
1183 {
1184         int fwd = 0, i;
1185
1186         for (i = 0; i < indent; i++) {
1187                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1188                 if (fwd >= len)
1189                         return fwd;
1190         }
1191
1192         fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
1193         return fwd;
1194 }
1195
1196 static int
1197 snprint_json_header (char * buff, int len)
1198 {
1199         int fwd = 0;
1200
1201         fwd +=  snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
1202         if (fwd >= len)
1203                 return fwd;
1204
1205         fwd +=  snprintf(buff + fwd, len  - fwd, PRINT_JSON_START_VERSION,
1206                         PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
1207         return fwd;
1208 }
1209
1210 static int
1211 snprint_json_elem_footer (char * buff, int len, int indent, int last)
1212 {
1213         int fwd = 0, i;
1214
1215         for (i = 0; i < indent; i++) {
1216                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
1217                 if (fwd >= len)
1218                         return fwd;
1219         }
1220
1221         if (last == 1)
1222                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
1223         else
1224                 fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
1225         return fwd;
1226 }
1227
1228 static int
1229 snprint_multipath_fields_json (char * buff, int len,
1230                 const struct multipath * mpp, int last)
1231 {
1232         int i, j, fwd = 0;
1233         struct path *pp;
1234         struct pathgroup *pgp;
1235
1236         fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
1237         if (fwd >= len)
1238                 return fwd;
1239
1240         fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
1241         if (fwd >= len)
1242                 return fwd;
1243
1244         vector_foreach_slot (mpp->pg, pgp, i) {
1245
1246                 fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
1247                 if (fwd >= len)
1248                         return fwd;
1249
1250                 fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
1251                 if (fwd >= len)
1252                         return fwd;
1253
1254                 fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
1255                 if (fwd >= len)
1256                         return fwd;
1257
1258                 vector_foreach_slot (pgp->paths, pp, j) {
1259                         fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
1260                         if (fwd >= len)
1261                                 return fwd;
1262
1263                         fwd += snprint_json_elem_footer(buff + fwd,
1264                                         len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
1265                         if (fwd >= len)
1266                                 return fwd;
1267                 }
1268                 fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1269                 if (fwd >= len)
1270                         return fwd;
1271
1272                 fwd +=  snprint_json_elem_footer(buff + fwd,
1273                                 len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
1274                 if (fwd >= len)
1275                         return fwd;
1276         }
1277
1278         fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1279         if (fwd >= len)
1280                 return fwd;
1281
1282         fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
1283         return fwd;
1284 }
1285
1286 int
1287 snprint_multipath_map_json (char * buff, int len,
1288                 const struct multipath * mpp, int last){
1289         int fwd = 0;
1290
1291         fwd +=  snprint_json_header(buff, len);
1292         if (fwd >= len)
1293                 return len;
1294
1295         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
1296         if (fwd >= len)
1297                 return len;
1298
1299         fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
1300         if (fwd >= len)
1301                 return len;
1302
1303         fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n");
1304         if (fwd >= len)
1305                 return len;
1306
1307         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1308         if (fwd >= len)
1309                 return len;
1310         return fwd;
1311 }
1312
1313 int
1314 snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
1315 {
1316         int i, fwd = 0;
1317         struct multipath * mpp;
1318
1319         fwd +=  snprint_json_header(buff, len);
1320         if (fwd >= len)
1321                 return len;
1322
1323         fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);
1324         if (fwd >= len)
1325                 return len;
1326
1327         vector_foreach_slot(vecs->mpvec, mpp, i) {
1328                 fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
1329                                 mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
1330                 if (fwd >= len)
1331                         return len;
1332         }
1333
1334         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
1335         if (fwd >= len)
1336                 return len;
1337
1338         fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
1339         if (fwd >= len)
1340                 return len;
1341         return fwd;
1342 }
1343
1344 static int
1345 snprint_hwentry (struct config *conf, char * buff, int len, const struct hwentry * hwe)
1346 {
1347         int i;
1348         int fwd = 0;
1349         struct keyword * kw;
1350         struct keyword * rootkw;
1351
1352         rootkw = find_keyword(conf->keywords, NULL, "devices");
1353
1354         if (!rootkw || !rootkw->sub)
1355                 return 0;
1356
1357         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1358
1359         if (!rootkw)
1360                 return 0;
1361
1362         fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1363         if (fwd >= len)
1364                 return len;
1365         iterate_sub_keywords(rootkw, kw, i) {
1366                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1367                                 kw, hwe);
1368                 if (fwd >= len)
1369                         return len;
1370         }
1371         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1372         if (fwd >= len)
1373                 return len;
1374         return fwd;
1375 }
1376
1377 int snprint_hwtable(struct config *conf, char *buff, int len, vector hwtable)
1378 {
1379         int fwd = 0;
1380         int i;
1381         struct hwentry * hwe;
1382         struct keyword * rootkw;
1383
1384         rootkw = find_keyword(conf->keywords, NULL, "devices");
1385         if (!rootkw)
1386                 return 0;
1387
1388         fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
1389         if (fwd >= len)
1390                 return len;
1391         vector_foreach_slot (hwtable, hwe, i) {
1392                 fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
1393                 if (fwd >= len)
1394                         return len;
1395         }
1396         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1397         if (fwd >= len)
1398                 return len;
1399         return fwd;
1400 }
1401
1402 static int
1403 snprint_mpentry (struct config *conf, char * buff, int len, const struct mpentry * mpe)
1404 {
1405         int i;
1406         int fwd = 0;
1407         struct keyword * kw;
1408         struct keyword * rootkw;
1409
1410         rootkw = find_keyword(conf->keywords, NULL, "multipath");
1411         if (!rootkw)
1412                 return 0;
1413
1414         fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
1415         if (fwd >= len)
1416                 return len;
1417         iterate_sub_keywords(rootkw, kw, i) {
1418                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1419                                 kw, mpe);
1420                 if (fwd >= len)
1421                         return len;
1422         }
1423         fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1424         if (fwd >= len)
1425                 return len;
1426         return fwd;
1427 }
1428
1429 int snprint_mptable(struct config *conf, char *buff, int len, vector mptable)
1430 {
1431         int fwd = 0;
1432         int i;
1433         struct mpentry * mpe;
1434         struct keyword * rootkw;
1435
1436         rootkw = find_keyword(conf->keywords, NULL, "multipaths");
1437         if (!rootkw)
1438                 return 0;
1439
1440         fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
1441         if (fwd >= len)
1442                 return len;
1443         vector_foreach_slot (mptable, mpe, i) {
1444                 fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe);
1445                 if (fwd >= len)
1446                         return len;
1447         }
1448         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1449         if (fwd >= len)
1450                 return len;
1451         return fwd;
1452 }
1453
1454 int snprint_overrides(struct config *conf, char * buff, int len,
1455                       const struct hwentry *overrides)
1456 {
1457         int fwd = 0;
1458         int i;
1459         struct keyword *rootkw;
1460         struct keyword *kw;
1461
1462         rootkw = find_keyword(conf->keywords, NULL, "overrides");
1463         if (!rootkw)
1464                 return 0;
1465
1466         fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
1467         if (fwd >= len)
1468                 return len;
1469         if (!overrides)
1470                 goto out;
1471         iterate_sub_keywords(rootkw, kw, i) {
1472                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1473                                        kw, NULL);
1474                 if (fwd >= len)
1475                         return len;
1476         }
1477 out:
1478         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1479         if (fwd >= len)
1480                 return len;
1481         return fwd;
1482 }
1483
1484 int snprint_defaults(struct config *conf, char *buff, int len)
1485 {
1486         int fwd = 0;
1487         int i;
1488         struct keyword *rootkw;
1489         struct keyword *kw;
1490
1491         rootkw = find_keyword(conf->keywords, NULL, "defaults");
1492         if (!rootkw)
1493                 return 0;
1494
1495         fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
1496         if (fwd >= len)
1497                 return len;
1498
1499         iterate_sub_keywords(rootkw, kw, i) {
1500                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1501                                 kw, NULL);
1502                 if (fwd >= len)
1503                         return len;
1504         }
1505         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1506         if (fwd >= len)
1507                 return len;
1508         return fwd;
1509 }
1510
1511 static int
1512 snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
1513 {
1514         int threshold = MAX_LINE_LEN;
1515         struct blentry * ble;
1516         int pos;
1517         int i;
1518
1519         pos = *fwd;
1520         if (!VECTOR_SIZE(*vec)) {
1521                 if ((len - pos - threshold) <= 0)
1522                         return 0;
1523                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1524         } else vector_foreach_slot (*vec, ble, i) {
1525                 if ((len - pos - threshold) <= 0)
1526                         return 0;
1527                 if (ble->origin == ORIGIN_CONFIG)
1528                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1529                 else if (ble->origin == ORIGIN_DEFAULT)
1530                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1531                 pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
1532         }
1533
1534         *fwd = pos;
1535         return pos;
1536 }
1537
1538 static int
1539 snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
1540 {
1541         int threshold = MAX_LINE_LEN;
1542         struct blentry_device * bled;
1543         int pos;
1544         int i;
1545
1546         pos = *fwd;
1547         if (!VECTOR_SIZE(*vec)) {
1548                 if ((len - pos - threshold) <= 0)
1549                         return 0;
1550                 pos += snprintf(buff + pos, len - pos, "        <empty>\n");
1551         } else vector_foreach_slot (*vec, bled, i) {
1552                 if ((len - pos - threshold) <= 0)
1553                         return 0;
1554                 if (bled->origin == ORIGIN_CONFIG)
1555                         pos += snprintf(buff + pos, len - pos, "        (config file rule) ");
1556                 else if (bled->origin == ORIGIN_DEFAULT)
1557                         pos += snprintf(buff + pos, len - pos, "        (default rule)     ");
1558                 pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
1559         }
1560
1561         *fwd = pos;
1562         return pos;
1563 }
1564
1565 int snprint_blacklist_report(struct config *conf, char *buff, int len)
1566 {
1567         int threshold = MAX_LINE_LEN;
1568         int fwd = 0;
1569
1570         if ((len - fwd - threshold) <= 0)
1571                 return len;
1572         fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
1573                                                "- blacklist:\n");
1574         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
1575                 return len;
1576
1577         if ((len - fwd - threshold) <= 0)
1578                 return len;
1579         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1580         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
1581                 return len;
1582
1583         if ((len - fwd - threshold) <= 0)
1584                 return len;
1585         fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
1586                                                "- blacklist:\n");
1587         if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
1588                 return len;
1589
1590         if ((len - fwd - threshold) <= 0)
1591                 return len;
1592         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1593         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
1594                 return len;
1595
1596         if ((len - fwd - threshold) <= 0)
1597                 return len;
1598         fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
1599                                                "- blacklist:\n");
1600         if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
1601                 return len;
1602
1603         if ((len - fwd - threshold) <= 0)
1604                 return len;
1605         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1606         if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
1607                 return len;
1608
1609         if ((len - fwd - threshold) <= 0)
1610                 return len;
1611         fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
1612                                                "- blacklist:\n");
1613         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
1614                 return len;
1615
1616         if ((len - fwd - threshold) <= 0)
1617                 return len;
1618         fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
1619         if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
1620                 return len;
1621
1622         if (fwd > len)
1623                 return len;
1624         return fwd;
1625 }
1626
1627 int snprint_blacklist(struct config *conf, char *buff, int len)
1628 {
1629         int i;
1630         struct blentry * ble;
1631         struct blentry_device * bled;
1632         int fwd = 0;
1633         struct keyword *rootkw;
1634         struct keyword *kw;
1635
1636         rootkw = find_keyword(conf->keywords, NULL, "blacklist");
1637         if (!rootkw)
1638                 return 0;
1639
1640         fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
1641         if (fwd >= len)
1642                 return len;
1643
1644         vector_foreach_slot (conf->blist_devnode, ble, i) {
1645                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1646                 if (!kw)
1647                         return 0;
1648                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1649                                        kw, ble);
1650                 if (fwd >= len)
1651                         return len;
1652         }
1653         vector_foreach_slot (conf->blist_wwid, ble, i) {
1654                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1655                 if (!kw)
1656                         return 0;
1657                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1658                                        kw, ble);
1659                 if (fwd >= len)
1660                         return len;
1661         }
1662         vector_foreach_slot (conf->blist_property, ble, i) {
1663                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1664                 if (!kw)
1665                         return 0;
1666                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1667                                        kw, ble);
1668                 if (fwd >= len)
1669                         return len;
1670         }
1671         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1672         if (!rootkw)
1673                 return 0;
1674
1675         vector_foreach_slot (conf->blist_device, bled, i) {
1676                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1677                 if (fwd >= len)
1678                         return len;
1679                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
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                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1687                 if (!kw)
1688                         return 0;
1689                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1690                                        kw, bled);
1691                 if (fwd >= len)
1692                         return len;
1693                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1694                 if (fwd >= len)
1695                         return len;
1696         }
1697         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1698         if (fwd >= len)
1699                 return len;
1700         return fwd;
1701 }
1702
1703 int snprint_blacklist_except(struct config *conf, char *buff, int len)
1704 {
1705         int i;
1706         struct blentry * ele;
1707         struct blentry_device * eled;
1708         int fwd = 0;
1709         struct keyword *rootkw;
1710         struct keyword *kw;
1711
1712         rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
1713         if (!rootkw)
1714                 return 0;
1715
1716         fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
1717         if (fwd >= len)
1718                 return len;
1719
1720         vector_foreach_slot (conf->elist_devnode, ele, i) {
1721                 kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
1722                 if (!kw)
1723                         return 0;
1724                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1725                                        kw, ele);
1726                 if (fwd >= len)
1727                         return len;
1728         }
1729         vector_foreach_slot (conf->elist_wwid, ele, i) {
1730                 kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
1731                 if (!kw)
1732                         return 0;
1733                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1734                                        kw, ele);
1735                 if (fwd >= len)
1736                         return len;
1737         }
1738         vector_foreach_slot (conf->elist_property, ele, i) {
1739                 kw = find_keyword(conf->keywords, rootkw->sub, "property");
1740                 if (!kw)
1741                         return 0;
1742                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
1743                                        kw, ele);
1744                 if (fwd >= len)
1745                         return len;
1746         }
1747         rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
1748         if (!rootkw)
1749                 return 0;
1750
1751         vector_foreach_slot (conf->elist_device, eled, i) {
1752                 fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
1753                 if (fwd >= len)
1754                         return len;
1755                 kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
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                 kw = find_keyword(conf->keywords, rootkw->sub, "product");
1763                 if (!kw)
1764                         return 0;
1765                 fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
1766                                        kw, eled);
1767                 if (fwd >= len)
1768                         return len;
1769                 fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
1770                 if (fwd >= len)
1771                         return len;
1772         }
1773         fwd += snprintf(buff + fwd, len - fwd, "}\n");
1774         if (fwd >= len)
1775                 return len;
1776         return fwd;
1777 }
1778
1779 int snprint_status(char *buff, int len, const struct vectors *vecs)
1780 {
1781         int fwd = 0;
1782         int i;
1783         unsigned int count[PATH_MAX_STATE] = {0};
1784         struct path * pp;
1785
1786         vector_foreach_slot (vecs->pathvec, pp, i) {
1787                 count[pp->state]++;
1788         }
1789         fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
1790         for (i=0; i<PATH_MAX_STATE; i++) {
1791                 if (!count[i])
1792                         continue;
1793                 fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
1794                                 checker_state_name(i), count[i]);
1795         }
1796
1797         int monitored_count = 0;
1798
1799         vector_foreach_slot(vecs->pathvec, pp, i)
1800                 if (pp->fd >= 0)
1801                         monitored_count++;
1802         fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
1803                         monitored_count, is_uevent_busy()? "True" : "False");
1804
1805         if (fwd >= len)
1806                 return len;
1807         return fwd;
1808 }
1809
1810 int snprint_devices(struct config *conf, char * buff, int len,
1811                     const struct vectors *vecs)
1812 {
1813         DIR *blkdir;
1814         struct dirent *blkdev;
1815         struct stat statbuf;
1816         char devpath[PATH_MAX];
1817         char *devptr;
1818         int threshold = MAX_LINE_LEN;
1819         int fwd = 0;
1820         int r;
1821
1822         struct path * pp;
1823
1824         if (!(blkdir = opendir("/sys/block")))
1825                 return 1;
1826
1827         if ((len - fwd - threshold) <= 0) {
1828                 closedir(blkdir);
1829                 return len;
1830         }
1831         fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
1832
1833         strcpy(devpath,"/sys/block/");
1834         while ((blkdev = readdir(blkdir)) != NULL) {
1835                 if ((strcmp(blkdev->d_name,".") == 0) ||
1836                     (strcmp(blkdev->d_name,"..") == 0))
1837                         continue;
1838
1839                 devptr = devpath + 11;
1840                 *devptr = '\0';
1841                 strncat(devptr, blkdev->d_name, PATH_MAX-12);
1842                 if (stat(devpath, &statbuf) < 0)
1843                         continue;
1844
1845                 if (S_ISDIR(statbuf.st_mode) == 0)
1846                         continue;
1847
1848                 if ((len - fwd - threshold)  <= 0) {
1849                         closedir(blkdir);
1850                         return len;
1851                 }
1852
1853                 fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
1854                 pp = find_path_by_dev(vecs->pathvec, devptr);
1855                 if (!pp) {
1856                         r = filter_devnode(conf->blist_devnode,
1857                                            conf->elist_devnode, devptr);
1858                         if (r > 0)
1859                                 fwd += snprintf(buff + fwd, len - fwd,
1860                                                 " devnode blacklisted, unmonitored");
1861                         else if (r <= 0)
1862                                 fwd += snprintf(buff + fwd, len - fwd,
1863                                                 " devnode whitelisted, unmonitored");
1864                 } else
1865                         fwd += snprintf(buff + fwd, len - fwd,
1866                                         " devnode whitelisted, monitored");
1867                 fwd += snprintf(buff + fwd, len - fwd, "\n");
1868         }
1869         closedir(blkdir);
1870
1871         if (fwd >= len)
1872                 return len;
1873         return fwd;
1874 }
1875
1876 /*
1877  * stdout printing helpers
1878  */
1879 void print_path(struct path *pp, char *style)
1880 {
1881         char line[MAX_LINE_LEN];
1882
1883         memset(&line[0], 0, MAX_LINE_LEN);
1884         snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
1885         printf("%s", line);
1886 }
1887
1888 void print_all_paths(vector pathvec, int banner)
1889 {
1890         print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
1891 }
1892
1893 void print_all_paths_custo(vector pathvec, int banner, char *fmt)
1894 {
1895         int i;
1896         struct path * pp;
1897         char line[MAX_LINE_LEN];
1898
1899         if (!VECTOR_SIZE(pathvec)) {
1900                 if (banner)
1901                         fprintf(stdout, "===== no paths =====\n");
1902                 return;
1903         }
1904
1905         if (banner)
1906                 fprintf(stdout, "===== paths list =====\n");
1907
1908         get_path_layout(pathvec, 1);
1909         snprint_path_header(line, MAX_LINE_LEN, fmt);
1910         fprintf(stdout, "%s", line);
1911
1912         vector_foreach_slot (pathvec, pp, i)
1913                 print_path(pp, fmt);
1914 }