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