Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / lvm2 / dist / lib / report / report.c
1 /*      $NetBSD: report.c,v 1.1.1.3 2009/12/02 00:26:46 haad Exp $      */
2
3 /*
4  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include "lib.h"
19 #include "metadata.h"
20 #include "report.h"
21 #include "toolcontext.h"
22 #include "lvm-string.h"
23 #include "display.h"
24 #include "activate.h"
25 #include "segtype.h"
26 #include "str_list.h"
27 #include "lvmcache.h"
28 #include <stddef.h>
29
30 struct lvm_report_object {
31         struct volume_group *vg;
32         struct logical_volume *lv;
33         struct physical_volume *pv;
34         struct lv_segment *seg;
35         struct pv_segment *pvseg;
36 };
37
38 /*
39  * For macro use
40  */
41 static union {
42         struct physical_volume _pv;
43         struct logical_volume _lv;
44         struct volume_group _vg;
45         struct lv_segment _seg;
46         struct pv_segment _pvseg;
47 } _dummy;
48
49 static char _alloc_policy_char(alloc_policy_t alloc)
50 {
51         switch (alloc) {
52         case ALLOC_CONTIGUOUS:
53                 return 'c';
54         case ALLOC_CLING:
55                 return 'l';
56         case ALLOC_NORMAL:
57                 return 'n';
58         case ALLOC_ANYWHERE:
59                 return 'a';
60         default:
61                 return 'i';
62         }
63 }
64
65 static const uint64_t _minusone = UINT64_C(-1);
66
67 /*
68  * Data-munging functions to prepare each data type for display and sorting
69  */
70 static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
71                         struct dm_report_field *field,
72                         const void *data, void *private __attribute((unused)))
73 {
74         return dm_report_field_string(rh, field, (const char **) data);
75 }
76
77 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
78                           struct dm_report_field *field,
79                           const void *data, void *private __attribute((unused)))
80 {
81         const char *name = dev_name(*(const struct device **) data);
82
83         return dm_report_field_string(rh, field, &name);
84 }
85
86 static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
87                           const void *data, int range_format)
88 {
89         const struct lv_segment *seg = (const struct lv_segment *) data;
90         unsigned int s;
91         const char *name = NULL;
92         uint32_t extent = 0;
93         char extent_str[32];
94
95         if (!dm_pool_begin_object(mem, 256)) {
96                 log_error("dm_pool_begin_object failed");
97                 return 0;
98         }
99
100         for (s = 0; s < seg->area_count; s++) {
101                 switch (seg_type(seg, s)) {
102                 case AREA_LV:
103                         name = seg_lv(seg, s)->name;
104                         extent = seg_le(seg, s);
105                         break;
106                 case AREA_PV:
107                         name = dev_name(seg_dev(seg, s));
108                         extent = seg_pe(seg, s);
109                         break;
110                 case AREA_UNASSIGNED:
111                         name = "unassigned";
112                         extent = 0;
113                 }
114
115                 if (!dm_pool_grow_object(mem, name, strlen(name))) {
116                         log_error("dm_pool_grow_object failed");
117                         return 0;
118                 }
119
120                 if (dm_snprintf(extent_str, sizeof(extent_str),
121                                 "%s%" PRIu32 "%s",
122                                 range_format ? ":" : "(", extent,
123                                 range_format ? "-"  : ")") < 0) {
124                         log_error("Extent number dm_snprintf failed");
125                         return 0;
126                 }
127                 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
128                         log_error("dm_pool_grow_object failed");
129                         return 0;
130                 }
131
132                 if (range_format) {
133                         if (dm_snprintf(extent_str, sizeof(extent_str),
134                                         "%" PRIu32, extent + seg->area_len - 1) < 0) {
135                                 log_error("Extent number dm_snprintf failed");
136                                 return 0;
137                         }
138                         if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
139                                 log_error("dm_pool_grow_object failed");
140                                 return 0;
141                         }
142                 }
143
144                 if ((s != seg->area_count - 1) &&
145                     !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
146                         log_error("dm_pool_grow_object failed");
147                         return 0;
148                 }
149         }
150
151         if (!dm_pool_grow_object(mem, "\0", 1)) {
152                 log_error("dm_pool_grow_object failed");
153                 return 0;
154         }
155
156         dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
157
158         return 1;
159 }
160
161 static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
162                          struct dm_report_field *field,
163                          const void *data, void *private __attribute((unused)))
164 {
165         return _format_pvsegs(mem, field, data, 0);
166 }
167
168 static int _peranges_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
169                           struct dm_report_field *field,
170                           const void *data, void *private __attribute((unused)))
171 {
172         return _format_pvsegs(mem, field, data, 1);
173 }
174
175 static int _tags_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
176                       struct dm_report_field *field,
177                       const void *data, void *private __attribute((unused)))
178 {
179         const struct dm_list *tags = (const struct dm_list *) data;
180         struct str_list *sl;
181
182         if (!dm_pool_begin_object(mem, 256)) {
183                 log_error("dm_pool_begin_object failed");
184                 return 0;
185         }
186
187         dm_list_iterate_items(sl, tags) {
188                 if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
189                     (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
190                         log_error("dm_pool_grow_object failed");
191                         return 0;
192                 }
193         }
194
195         if (!dm_pool_grow_object(mem, "\0", 1)) {
196                 log_error("dm_pool_grow_object failed");
197                 return 0;
198         }
199
200         dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
201
202         return 1;
203 }
204
205 static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
206                          struct dm_report_field *field,
207                          const void *data, void *private)
208 {
209         const struct logical_volume *lv = (const struct logical_volume *) data;
210         struct dm_list *modules;
211
212         if (!(modules = str_list_create(mem))) {
213                 log_error("modules str_list allocation failed");
214                 return 0;
215         }
216
217         if (!list_lv_modules(mem, lv, modules))
218                 return_0;
219
220         return _tags_disp(rh, mem, field, modules, private);
221 }
222
223 static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
224                        struct dm_report_field *field,
225                        const void *data, void *private)
226 {
227         const struct volume_group *vg = (const struct volume_group *) data;
228
229         if (!vg->fid) {
230                 dm_report_field_set_value(field, "", NULL);
231                 return 1;
232         }
233
234         return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
235 }
236
237 static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
238                        struct dm_report_field *field,
239                        const void *data, void *private)
240 {
241         const struct physical_volume *pv =
242             (const struct physical_volume *) data;
243
244         if (!pv->fmt) {
245                 dm_report_field_set_value(field, "", NULL);
246                 return 1;
247         }
248
249         return _string_disp(rh, mem, field, &pv->fmt->name, private);
250 }
251
252 static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
253                         struct dm_report_field *field,
254                         const void *data, void *private __attribute((unused)))
255 {
256         const struct logical_volume *lv = (const struct logical_volume *) data;
257         struct lvinfo info;
258
259         if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
260                 return dm_report_field_int(rh, field, &info.major);
261
262         return dm_report_field_uint64(rh, field, &_minusone);
263 }
264
265 static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
266                         struct dm_report_field *field,
267                         const void *data, void *private __attribute((unused)))
268 {
269         const struct logical_volume *lv = (const struct logical_volume *) data;
270         struct lvinfo info;
271
272         if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists)
273                 return dm_report_field_int(rh, field, &info.minor);
274
275         return dm_report_field_uint64(rh, field, &_minusone);
276 }
277
278 static int _lv_mimage_in_sync(const struct logical_volume *lv)
279 {
280         float percent;
281         percent_range_t percent_range;
282         struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv));
283
284         if (!(lv->status & MIRROR_IMAGE) || !mirror_seg)
285                 return_0;
286
287         if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent,
288                                &percent_range, NULL))
289                 return_0;
290
291         return (percent_range == PERCENT_100) ? 1 : 0;
292 }
293
294 static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
295                           struct dm_report_field *field,
296                           const void *data, void *private __attribute((unused)))
297 {
298         const struct logical_volume *lv = (const struct logical_volume *) data;
299         struct lvinfo info;
300         char *repstr;
301         float snap_percent;
302         percent_range_t percent_range;
303
304         if (!(repstr = dm_pool_zalloc(mem, 7))) {
305                 log_error("dm_pool_alloc failed");
306                 return 0;
307         }
308
309         /* Blank if this is a "free space" LV. */
310         if (!*lv->name)
311                 goto out;
312
313         if (lv->status & PVMOVE)
314                 repstr[0] = 'p';
315         else if (lv->status & CONVERTING)
316                 repstr[0] = 'c';
317         else if (lv->status & VIRTUAL)
318                 repstr[0] = 'v';
319         /* Origin takes precedence over Mirror */
320         else if (lv_is_origin(lv))
321                 repstr[0] = 'o';
322         else if (lv->status & MIRRORED) {
323                 if (lv->status & MIRROR_NOTSYNCED)
324                         repstr[0] = 'M';
325                 else
326                         repstr[0] = 'm';
327         }else if (lv->status & MIRROR_IMAGE)
328                 if (_lv_mimage_in_sync(lv))
329                         repstr[0] = 'i';
330                 else
331                         repstr[0] = 'I';
332         else if (lv->status & MIRROR_LOG)
333                 repstr[0] = 'l';
334         else if (lv_is_cow(lv))
335                 repstr[0] = 's';
336         else
337                 repstr[0] = '-';
338
339         if (lv->status & PVMOVE)
340                 repstr[1] = '-';
341         else if (lv->status & LVM_WRITE)
342                 repstr[1] = 'w';
343         else if (lv->status & LVM_READ)
344                 repstr[1] = 'r';
345         else
346                 repstr[1] = '-';
347
348         repstr[2] = _alloc_policy_char(lv->alloc);
349
350         if (lv->status & LOCKED)
351                 repstr[2] = toupper(repstr[2]);
352
353         if (lv->status & FIXED_MINOR)
354                 repstr[3] = 'm';        /* Fixed Minor */
355         else
356                 repstr[3] = '-';
357
358         if (lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists) {
359                 if (info.suspended)
360                         repstr[4] = 's';        /* Suspended */
361                 else if (info.live_table)
362                         repstr[4] = 'a';        /* Active */
363                 else if (info.inactive_table)
364                         repstr[4] = 'i';        /* Inactive with table */
365                 else
366                         repstr[4] = 'd';        /* Inactive without table */
367
368                 /* Snapshot dropped? */
369                 if (info.live_table && lv_is_cow(lv) &&
370                     (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
371                      percent_range == PERCENT_INVALID)) {
372                         repstr[0] = toupper(repstr[0]);
373                         if (info.suspended)
374                                 repstr[4] = 'S'; /* Susp Inv snapshot */
375                         else
376                                 repstr[4] = 'I'; /* Invalid snapshot */
377                 }
378
379                 if (info.open_count)
380                         repstr[5] = 'o';        /* Open */
381                 else
382                         repstr[5] = '-';
383         } else {
384                 repstr[4] = '-';
385                 repstr[5] = '-';
386         }
387
388 out:
389         dm_report_field_set_value(field, repstr, NULL);
390         return 1;
391 }
392
393 static int _pvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
394                           struct dm_report_field *field,
395                           const void *data, void *private __attribute((unused)))
396 {
397         const uint32_t status = *(const uint32_t *) data;
398         char *repstr;
399
400         if (!(repstr = dm_pool_zalloc(mem, 3))) {
401                 log_error("dm_pool_alloc failed");
402                 return 0;
403         }
404
405         if (status & ALLOCATABLE_PV)
406                 repstr[0] = 'a';
407         else
408                 repstr[0] = '-';
409
410         if (status & EXPORTED_VG)
411                 repstr[1] = 'x';
412         else
413                 repstr[1] = '-';
414
415         dm_report_field_set_value(field, repstr, NULL);
416         return 1;
417 }
418
419 static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
420                           struct dm_report_field *field,
421                           const void *data, void *private __attribute((unused)))
422 {
423         const struct volume_group *vg = (const struct volume_group *) data;
424         char *repstr;
425
426         if (!(repstr = dm_pool_zalloc(mem, 7))) {
427                 log_error("dm_pool_alloc failed");
428                 return 0;
429         }
430
431         if (vg->status & LVM_WRITE)
432                 repstr[0] = 'w';
433         else
434                 repstr[0] = 'r';
435
436         if (vg_is_resizeable(vg))
437                 repstr[1] = 'z';
438         else
439                 repstr[1] = '-';
440
441         if (vg_is_exported(vg))
442                 repstr[2] = 'x';
443         else
444                 repstr[2] = '-';
445
446         if (vg_missing_pv_count(vg))
447                 repstr[3] = 'p';
448         else
449                 repstr[3] = '-';
450
451         repstr[4] = _alloc_policy_char(vg->alloc);
452
453         if (vg_is_clustered(vg))
454                 repstr[5] = 'c';
455         else
456                 repstr[5] = '-';
457
458         dm_report_field_set_value(field, repstr, NULL);
459         return 1;
460 }
461
462 static int _segtype_disp(struct dm_report *rh __attribute((unused)),
463                          struct dm_pool *mem __attribute((unused)),
464                          struct dm_report_field *field,
465                          const void *data, void *private __attribute((unused)))
466 {
467         const struct lv_segment *seg = (const struct lv_segment *) data;
468
469         if (seg->area_count == 1) {
470                 dm_report_field_set_value(field, "linear", NULL);
471                 return 1;
472         }
473
474         dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL);
475         return 1;
476 }
477
478 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
479                        struct dm_report_field *field,
480                        const void *data, void *private __attribute((unused)))
481 {
482         const struct logical_volume *lv = (const struct logical_volume *) data;
483         struct lv_segment *seg;
484
485         dm_list_iterate_items(seg, &lv->segments) {
486                 if (!seg_is_mirrored(seg) || !seg->log_lv)
487                         continue;
488                 return dm_report_field_string(rh, field,
489                                               (const char **) &seg->log_lv->name);
490         }
491
492         dm_report_field_set_value(field, "", NULL);
493         return 1;
494 }
495
496 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
497                         struct dm_report_field *field,
498                         const void *data, void *private __attribute((unused)))
499 {
500         const struct logical_volume *lv = (const struct logical_volume *) data;
501         char *repstr, *lvname;
502         size_t len;
503
504         if (lv_is_visible(lv)) {
505                 repstr = lv->name;
506                 return dm_report_field_string(rh, field, (const char **) &repstr);
507         }
508
509         len = strlen(lv->name) + 3;
510         if (!(repstr = dm_pool_zalloc(mem, len))) {
511                 log_error("dm_pool_alloc failed");
512                 return 0;
513         }
514
515         if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
516                 log_error("lvname snprintf failed");
517                 return 0;
518         }
519
520         if (!(lvname = dm_pool_strdup(mem, lv->name))) {
521                 log_error("dm_pool_strdup failed");
522                 return 0;
523         }
524
525         dm_report_field_set_value(field, repstr, lvname);
526
527         return 1;
528 }
529
530 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
531                         struct dm_report_field *field,
532                         const void *data, void *private)
533 {
534         const struct logical_volume *lv = (const struct logical_volume *) data;
535
536         if (lv_is_cow(lv))
537                 return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
538
539         dm_report_field_set_value(field, "", NULL);
540         return 1;
541 }
542
543 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
544                         struct dm_report_field *field,
545                         const void *data, void *private __attribute((unused)))
546 {
547         const struct logical_volume *lv = (const struct logical_volume *) data;
548         const char *name;
549         struct lv_segment *seg;
550
551         dm_list_iterate_items(seg, &lv->segments) {
552                 if (!(seg->status & PVMOVE))
553                         continue;
554                 name = dev_name(seg_dev(seg, 0));
555                 return dm_report_field_string(rh, field, &name);
556         }
557
558         dm_report_field_set_value(field, "", NULL);
559         return 1;
560 }
561
562 static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
563                            struct dm_report_field *field,
564                            const void *data, void *private __attribute((unused)))
565 {
566         const struct logical_volume *lv = (const struct logical_volume *) data;
567         const char *name = NULL;
568         struct lv_segment *seg;
569
570         if (lv->status & CONVERTING) {
571                 if (lv->status & MIRRORED) {
572                         seg = first_seg(lv);
573
574                         /* Temporary mirror is always area_num == 0 */
575                         if (seg_type(seg, 0) == AREA_LV &&
576                             is_temporary_mirror_layer(seg_lv(seg, 0)))
577                                 name = seg_lv(seg, 0)->name;
578                 }
579         }
580
581         if (name)
582                 return dm_report_field_string(rh, field, &name);
583
584         dm_report_field_set_value(field, "", NULL);
585         return 1;
586 }
587
588 static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
589                         struct dm_report_field *field,
590                         const void *data, void *private)
591 {
592         const uint32_t size = *(const uint32_t *) data;
593         const char *disp, *repstr;
594         uint64_t *sortval;
595
596         if (!*(disp = display_size_units(private, (uint64_t) size)))
597                 return_0;
598
599         if (!(repstr = dm_pool_strdup(mem, disp))) {
600                 log_error("dm_pool_strdup failed");
601                 return 0;
602         }
603
604         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
605                 log_error("dm_pool_alloc failed");
606                 return 0;
607         }
608
609         *sortval = (const uint64_t) size;
610
611         dm_report_field_set_value(field, repstr, sortval);
612
613         return 1;
614 }
615
616 static int _size64_disp(struct dm_report *rh __attribute((unused)),
617                         struct dm_pool *mem,
618                         struct dm_report_field *field,
619                         const void *data, void *private)
620 {
621         const uint64_t size = *(const uint64_t *) data;
622         const char *disp, *repstr;
623         uint64_t *sortval;
624
625         if (!*(disp = display_size_units(private, size)))
626                 return_0;
627
628         if (!(repstr = dm_pool_strdup(mem, disp))) {
629                 log_error("dm_pool_strdup failed");
630                 return 0;
631         }
632
633         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
634                 log_error("dm_pool_alloc failed");
635                 return 0;
636         }
637
638         *sortval = size;
639         dm_report_field_set_value(field, repstr, sortval);
640
641         return 1;
642 }
643
644 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
645                              struct dm_report_field *field,
646                              const void *data, void *private __attribute((unused)))
647 {
648         const struct logical_volume *lv = (const struct logical_volume *) data;
649
650         if (lv->read_ahead == DM_READ_AHEAD_AUTO) {
651                 dm_report_field_set_value(field, "auto", &_minusone);
652                 return 1;
653         }
654
655         return _size32_disp(rh, mem, field, &lv->read_ahead, private);
656 }
657
658 static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
659                               struct dm_report_field *field,
660                               const void *data,
661                               void *private)
662 {
663         const struct logical_volume *lv = (const struct logical_volume *) data;
664         struct lvinfo info;
665
666         if (!lv_info(lv->vg->cmd, lv, &info, 0, 1) || !info.exists)
667                 return dm_report_field_uint64(rh, field, &_minusone);
668
669         return _size32_disp(rh, mem, field, &info.read_ahead, private);
670 }
671
672 static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
673                         struct dm_report_field *field,
674                         const void *data, void *private)
675 {
676         const struct volume_group *vg = (const struct volume_group *) data;
677         uint64_t size;
678
679         size = (uint64_t) vg_size(vg);
680
681         return _size64_disp(rh, mem, field, &size, private);
682 }
683
684 static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
685                           struct dm_report_field *field,
686                           const void *data, void *private)
687 {
688         const struct lv_segment *seg = (const struct lv_segment *) data;
689         uint64_t start;
690
691         start = (uint64_t) seg->le * seg->lv->vg->extent_size;
692
693         return _size64_disp(rh, mem, field, &start, private);
694 }
695
696 static int _segstartpe_disp(struct dm_report *rh,
697                             struct dm_pool *mem __attribute((unused)),
698                             struct dm_report_field *field,
699                             const void *data,
700                             void *private __attribute((unused)))
701 {
702         const struct lv_segment *seg = (const struct lv_segment *) data;
703
704         return dm_report_field_uint32(rh, field, &seg->le);
705 }
706
707 static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
708                          struct dm_report_field *field,
709                          const void *data, void *private)
710 {
711         const struct lv_segment *seg = (const struct lv_segment *) data;
712         uint64_t size;
713
714         size = (uint64_t) seg->len * seg->lv->vg->extent_size;
715
716         return _size64_disp(rh, mem, field, &size, private);
717 }
718
719 static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
720                            struct dm_report_field *field,
721                            const void *data, void *private)
722 {
723         const struct lv_segment *seg = (const struct lv_segment *) data;
724         uint64_t size;
725
726         if (lv_is_cow(seg->lv))
727                 size = (uint64_t) find_cow(seg->lv)->chunk_size;
728         else
729                 size = UINT64_C(0);
730
731         return _size64_disp(rh, mem, field, &size, private);
732 }
733
734 static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
735                             struct dm_report_field *field,
736                             const void *data, void *private)
737 {
738         const struct logical_volume *lv = (const struct logical_volume *) data;
739         uint64_t size;
740
741         if (lv_is_cow(lv))
742                 size = (uint64_t) find_cow(lv)->len * lv->vg->extent_size;
743         else if (lv_is_origin(lv))
744                 size = lv->size;
745         else
746                 size = UINT64_C(0);
747
748         return _size64_disp(rh, mem, field, &size, private);
749 }
750
751 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
752                         struct dm_report_field *field,
753                         const void *data, void *private)
754 {
755         const struct physical_volume *pv =
756             (const struct physical_volume *) data;
757         uint64_t used;
758
759         if (!pv->pe_count)
760                 used = 0LL;
761         else
762                 used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
763
764         return _size64_disp(rh, mem, field, &used, private);
765 }
766
767 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
768                         struct dm_report_field *field,
769                         const void *data, void *private)
770 {
771         const struct physical_volume *pv =
772             (const struct physical_volume *) data;
773         uint64_t freespace;
774
775         if (!pv->pe_count)
776                 freespace = pv->size;
777         else
778                 freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
779
780         return _size64_disp(rh, mem, field, &freespace, private);
781 }
782
783 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
784                         struct dm_report_field *field,
785                         const void *data, void *private)
786 {
787         const struct physical_volume *pv =
788             (const struct physical_volume *) data;
789         uint64_t size;
790
791         if (!pv->pe_count)
792                 size = pv->size;
793         else
794                 size = (uint64_t) pv->pe_count * pv->pe_size;
795
796         return _size64_disp(rh, mem, field, &size, private);
797 }
798
799 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
800                          struct dm_report_field *field,
801                          const void *data, void *private)
802 {
803         const struct device *dev = *(const struct device **) data;
804         uint64_t size;
805
806         if (!dev_get_size(dev, &size))
807                 size = 0;
808
809         return _size64_disp(rh, mem, field, &size, private);
810 }
811
812 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
813                         struct dm_report_field *field,
814                         const void *data, void *private)
815 {
816         const struct volume_group *vg = (const struct volume_group *) data;
817         uint64_t freespace;
818
819         freespace = (uint64_t) vg_free(vg);
820
821         return _size64_disp(rh, mem, field, &freespace, private);
822 }
823
824 static int _uuid_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
825                       struct dm_report_field *field,
826                       const void *data, void *private __attribute((unused)))
827 {
828         char *repstr = NULL;
829
830         if (!(repstr = dm_pool_alloc(mem, 40))) {
831                 log_error("dm_pool_alloc failed");
832                 return 0;
833         }
834
835         if (!id_write_format((const struct id *) data, repstr, 40))
836                 return_0;
837
838         dm_report_field_set_value(field, repstr, NULL);
839         return 1;
840 }
841
842 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
843                         struct dm_report_field *field,
844                         const void *data, void *private __attribute((unused)))
845 {
846         return dm_report_field_uint32(rh, field, data);
847 }
848
849 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
850                        struct dm_report_field *field,
851                        const void *data, void *private __attribute((unused)))
852 {
853         return dm_report_field_int32(rh, field, data);
854 }
855
856 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
857                         struct dm_report_field *field,
858                         const void *data, void *private)
859 {
860         uint32_t count;
861         const struct physical_volume *pv =
862             (const struct physical_volume *) data;
863
864         count = pv_mda_count(pv);
865
866         return _uint32_disp(rh, mem, field, &count, private);
867 }
868
869 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem,
870                         struct dm_report_field *field,
871                         const void *data, void *private)
872 {
873         const struct volume_group *vg = (const struct volume_group *) data;
874         uint32_t count;
875
876         count = vg_mda_count(vg);
877
878         return _uint32_disp(rh, mem, field, &count, private);
879 }
880
881 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
882                            struct dm_report_field *field,
883                            const void *data, void *private)
884 {
885         struct lvmcache_info *info;
886         uint64_t freespace = UINT64_MAX, mda_free;
887         const char *pvid = (const char *)(&((struct id *) data)->uuid);
888         struct metadata_area *mda;
889
890         if ((info = info_from_pvid(pvid, 0)))
891                 dm_list_iterate_items(mda, &info->mdas) {
892                         if (!mda->ops->mda_free_sectors)
893                                 continue;
894                         mda_free = mda->ops->mda_free_sectors(mda);
895                         if (mda_free < freespace)
896                                 freespace = mda_free;
897                 }
898
899         if (freespace == UINT64_MAX)
900                 freespace = UINT64_C(0);
901
902         return _size64_disp(rh, mem, field, &freespace, private);
903 }
904
905 static uint64_t _find_min_mda_size(struct dm_list *mdas)
906 {
907         uint64_t min_mda_size = UINT64_MAX, mda_size;
908         struct metadata_area *mda;
909
910         dm_list_iterate_items(mda, mdas) {
911                 if (!mda->ops->mda_total_sectors)
912                         continue;
913                 mda_size = mda->ops->mda_total_sectors(mda);
914                 if (mda_size < min_mda_size)
915                         min_mda_size = mda_size;
916         }
917
918         if (min_mda_size == UINT64_MAX)
919                 min_mda_size = UINT64_C(0);
920
921         return min_mda_size;
922 }
923
924 static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
925                            struct dm_report_field *field,
926                            const void *data, void *private)
927 {
928         struct lvmcache_info *info;
929         uint64_t min_mda_size = 0;
930         const char *pvid = (const char *)(&((struct id *) data)->uuid);
931
932         /* PVs could have 2 mdas of different sizes (rounding effect) */
933         if ((info = info_from_pvid(pvid, 0)))
934                 min_mda_size = _find_min_mda_size(&info->mdas);
935
936         return _size64_disp(rh, mem, field, &min_mda_size, private);
937 }
938
939 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
940                            struct dm_report_field *field,
941                            const void *data, void *private)
942 {
943         const struct volume_group *vg = (const struct volume_group *) data;
944         uint64_t min_mda_size;
945
946         min_mda_size = _find_min_mda_size(&vg->fid->metadata_areas);
947
948         return _size64_disp(rh, mem, field, &min_mda_size, private);
949 }
950
951 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
952                            struct dm_report_field *field,
953                            const void *data, void *private)
954 {
955         const struct volume_group *vg = (const struct volume_group *) data;
956         uint64_t freespace = UINT64_MAX, mda_free;
957         struct metadata_area *mda;
958
959         dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
960                 if (!mda->ops->mda_free_sectors)
961                         continue;
962                 mda_free = mda->ops->mda_free_sectors(mda);
963                 if (mda_free < freespace)
964                         freespace = mda_free;
965         }
966
967         if (freespace == UINT64_MAX)
968                 freespace = UINT64_C(0);
969
970         return _size64_disp(rh, mem, field, &freespace, private);
971 }
972
973 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem,
974                          struct dm_report_field *field,
975                          const void *data, void *private)
976 {
977         const struct volume_group *vg = (const struct volume_group *) data;
978         uint32_t count;
979
980         count = vg_visible_lvs(vg);
981
982         return _uint32_disp(rh, mem, field, &count, private);
983 }
984
985 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
986                             struct dm_report_field *field,
987                             const void *data, void *private)
988 {
989         const struct logical_volume *lv = (const struct logical_volume *) data;
990         uint32_t count;
991
992         count = dm_list_size(&lv->segments);
993
994         return _uint32_disp(rh, mem, field, &count, private);
995 }
996
997 static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem,
998                            struct dm_report_field *field,
999                            const void *data, void *private)
1000 {
1001         const struct volume_group *vg = (const struct volume_group *) data;
1002         uint32_t count;
1003
1004         count = snapshot_count(vg);
1005
1006         return _uint32_disp(rh, mem, field, &count, private);
1007 }
1008
1009 static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
1010                            struct dm_report_field *field,
1011                            const void *data, void *private __attribute((unused)))
1012 {
1013         const struct logical_volume *lv = (const struct logical_volume *) data;
1014         struct lvinfo info;
1015         float snap_percent;
1016         percent_range_t percent_range;
1017         uint64_t *sortval;
1018         char *repstr;
1019
1020         /* Suppress snapshot percentage if not using driver */
1021         if (!activation()) {
1022                 dm_report_field_set_value(field, "", NULL);
1023                 return 1;
1024         }
1025
1026         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1027                 log_error("dm_pool_alloc failed");
1028                 return 0;
1029         }
1030
1031         if (!lv_is_cow(lv) ||
1032             (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) {
1033                 *sortval = UINT64_C(0);
1034                 dm_report_field_set_value(field, "", sortval);
1035                 return 1;
1036         }
1037
1038         if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
1039                                  (percent_range == PERCENT_INVALID)) {
1040                 *sortval = UINT64_C(100);
1041                 dm_report_field_set_value(field, "100.00", sortval);
1042                 return 1;
1043         }
1044
1045         if (!(repstr = dm_pool_zalloc(mem, 8))) {
1046                 log_error("dm_pool_alloc failed");
1047                 return 0;
1048         }
1049
1050         if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
1051                 log_error("snapshot percentage too large");
1052                 return 0;
1053         }
1054
1055         *sortval = snap_percent * UINT64_C(1000);
1056         dm_report_field_set_value(field, repstr, sortval);
1057
1058         return 1;
1059 }
1060
1061 static int _copypercent_disp(struct dm_report *rh __attribute((unused)),
1062                              struct dm_pool *mem,
1063                              struct dm_report_field *field,
1064                              const void *data, void *private __attribute((unused)))
1065 {
1066         struct logical_volume *lv = (struct logical_volume *) data;
1067         float percent;
1068         percent_range_t percent_range;
1069         uint64_t *sortval;
1070         char *repstr;
1071
1072         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
1073                 log_error("dm_pool_alloc failed");
1074                 return 0;
1075         }
1076
1077         if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
1078             !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, &percent_range,
1079                                NULL) || (percent_range == PERCENT_INVALID)) {
1080                 *sortval = UINT64_C(0);
1081                 dm_report_field_set_value(field, "", sortval);
1082                 return 1;
1083         }
1084
1085         percent = copy_percent(lv, &percent_range);
1086
1087         if (!(repstr = dm_pool_zalloc(mem, 8))) {
1088                 log_error("dm_pool_alloc failed");
1089                 return 0;
1090         }
1091
1092         if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
1093                 log_error("copy percentage too large");
1094                 return 0;
1095         }
1096
1097         *sortval = percent * UINT64_C(1000);
1098         dm_report_field_set_value(field, repstr, sortval);
1099
1100         return 1;
1101 }
1102
1103 /* Report object types */
1104
1105 /* necessary for displaying something for PVs not belonging to VG */
1106 static struct format_instance _dummy_fid = {
1107         .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) },
1108 };
1109
1110 static struct volume_group _dummy_vg = {
1111         .fid = &_dummy_fid,
1112         .name = (char *) "",
1113         .system_id = (char *) "",
1114         .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
1115         .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
1116         .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) },
1117 };
1118
1119 static void *_obj_get_vg(void *obj)
1120 {
1121         struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
1122
1123         return vg ? vg : &_dummy_vg;
1124 }
1125
1126 static void *_obj_get_lv(void *obj)
1127 {
1128         return ((struct lvm_report_object *)obj)->lv;
1129 }
1130
1131 static void *_obj_get_pv(void *obj)
1132 {
1133         return ((struct lvm_report_object *)obj)->pv;
1134 }
1135
1136 static void *_obj_get_seg(void *obj)
1137 {
1138         return ((struct lvm_report_object *)obj)->seg;
1139 }
1140
1141 static void *_obj_get_pvseg(void *obj)
1142 {
1143         return ((struct lvm_report_object *)obj)->pvseg;
1144 }
1145
1146 static const struct dm_report_object_type _report_types[] = {
1147         { VGS, "Volume Group", "vg_", _obj_get_vg },
1148         { LVS, "Logical Volume", "lv_", _obj_get_lv },
1149         { PVS, "Physical Volume", "pv_", _obj_get_pv },
1150         { LABEL, "Physical Volume Label", "pv_", _obj_get_pv },
1151         { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
1152         { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
1153         { 0, "", "", NULL },
1154 };
1155
1156 /*
1157  * Import column definitions
1158  */
1159
1160 #define STR DM_REPORT_FIELD_TYPE_STRING
1161 #define NUM DM_REPORT_FIELD_TYPE_NUMBER
1162 #define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, offsetof(struct strct, field), width, id, head, &_ ## func ## _disp, desc},
1163
1164 static struct dm_report_field_type _fields[] = {
1165 #define lv      logical_volume
1166 #define pv      physical_volume
1167 #define vg      volume_group
1168 #define seg     lv_segment
1169 #define pvseg   pv_segment
1170 #include "columns.h"
1171 {0, 0, 0, 0, "", "", NULL, NULL},
1172 #undef lv
1173 #undef pv
1174 #undef vg
1175 #undef seg
1176 #undef pvseg
1177 };
1178
1179 #undef STR
1180 #undef NUM
1181 #undef FIELD
1182
1183 void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
1184                   report_type_t *report_type, const char *separator,
1185                   int aligned, int buffered, int headings, int field_prefixes,
1186                   int quoted, int columns_as_rows)
1187 {
1188         uint32_t report_flags = 0;
1189         void *rh;
1190
1191         if (aligned)
1192                 report_flags |= DM_REPORT_OUTPUT_ALIGNED;
1193
1194         if (buffered)
1195                 report_flags |= DM_REPORT_OUTPUT_BUFFERED;
1196
1197         if (headings)
1198                 report_flags |= DM_REPORT_OUTPUT_HEADINGS;
1199
1200         if (field_prefixes)
1201                 report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
1202
1203         if (!quoted)
1204                 report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
1205
1206         if (columns_as_rows)
1207                 report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
1208
1209         rh = dm_report_init(report_type, _report_types, _fields, format,
1210                             separator, report_flags, keys, cmd);
1211
1212         if (rh && field_prefixes)
1213                 dm_report_set_output_field_name_prefix(rh, "lvm2_");
1214
1215         return rh;
1216 }
1217
1218 /*
1219  * Create a row of data for an object
1220  */
1221 int report_object(void *handle, struct volume_group *vg,
1222                   struct logical_volume *lv, struct physical_volume *pv,
1223                   struct lv_segment *seg, struct pv_segment *pvseg)
1224 {
1225         struct lvm_report_object obj;
1226
1227         /* The two format fields might as well match. */
1228         if (!vg && pv)
1229                 _dummy_fid.fmt = pv->fmt;
1230
1231         obj.vg = vg;
1232         obj.lv = lv;
1233         obj.pv = pv;
1234         obj.seg = seg;
1235         obj.pvseg = pvseg;
1236
1237         return dm_report_object(handle, &obj);
1238 }