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