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