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