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