Tizen 2.1 base
[external/device-mapper.git] / lib / report / report.c
1 /*
2  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
7  * This copyrighted material is made available to anyone wishing to use,
8  * modify, copy, or redistribute it subject to the terms and conditions
9  * of the GNU Lesser General Public License v.2.1.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include "lib.h"
17 #include "metadata.h"
18 #include "report.h"
19 #include "toolcontext.h"
20 #include "lvm-string.h"
21 #include "display.h"
22 #include "activate.h"
23 #include "segtype.h"
24 #include "str_list.h"
25 #include "lvmcache.h"
26
27 #include <stddef.h> /* offsetof() */
28
29 struct lvm_report_object {
30         struct volume_group *vg;
31         struct logical_volume *lv;
32         struct physical_volume *pv;
33         struct lv_segment *seg;
34         struct pv_segment *pvseg;
35 };
36
37 static const uint64_t _minusone64 = UINT64_C(-1);
38 static const int32_t _minusone32 = INT32_C(-1);
39
40 /*
41  * Data-munging functions to prepare each data type for display and sorting
42  */
43 static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
44                         struct dm_report_field *field,
45                         const void *data, void *private __attribute__((unused)))
46 {
47         return dm_report_field_string(rh, field, (const char **) data);
48 }
49
50 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
51                           struct dm_report_field *field,
52                           const void *data, void *private __attribute__((unused)))
53 {
54         const char *name = dev_name(*(const struct device * const *) data);
55
56         return dm_report_field_string(rh, field, &name);
57 }
58
59 static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
60                           const void *data, int range_format)
61 {
62         const struct lv_segment *seg = (const struct lv_segment *) data;
63         unsigned int s;
64         const char *name = NULL;
65         uint32_t extent = 0;
66         char extent_str[32];
67
68         if (!dm_pool_begin_object(mem, 256)) {
69                 log_error("dm_pool_begin_object failed");
70                 return 0;
71         }
72
73         for (s = 0; s < seg->area_count; s++) {
74                 switch (seg_type(seg, s)) {
75                 case AREA_LV:
76                         name = seg_lv(seg, s)->name;
77                         extent = seg_le(seg, s);
78                         break;
79                 case AREA_PV:
80                         name = dev_name(seg_dev(seg, s));
81                         extent = seg_pe(seg, s);
82                         break;
83                 case AREA_UNASSIGNED:
84                         name = "unassigned";
85                         extent = 0;
86                 }
87
88                 if (!dm_pool_grow_object(mem, name, strlen(name))) {
89                         log_error("dm_pool_grow_object failed");
90                         return 0;
91                 }
92
93                 if (dm_snprintf(extent_str, sizeof(extent_str),
94                                 "%s%" PRIu32 "%s",
95                                 range_format ? ":" : "(", extent,
96                                 range_format ? "-"  : ")") < 0) {
97                         log_error("Extent number dm_snprintf failed");
98                         return 0;
99                 }
100                 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
101                         log_error("dm_pool_grow_object failed");
102                         return 0;
103                 }
104
105                 if (range_format) {
106                         if (dm_snprintf(extent_str, sizeof(extent_str),
107                                         "%" PRIu32, extent + seg->area_len - 1) < 0) {
108                                 log_error("Extent number dm_snprintf failed");
109                                 return 0;
110                         }
111                         if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
112                                 log_error("dm_pool_grow_object failed");
113                                 return 0;
114                         }
115                 }
116
117                 if ((s != seg->area_count - 1) &&
118                     !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
119                         log_error("dm_pool_grow_object failed");
120                         return 0;
121                 }
122         }
123
124         if (!dm_pool_grow_object(mem, "\0", 1)) {
125                 log_error("dm_pool_grow_object failed");
126                 return 0;
127         }
128
129         dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
130
131         return 1;
132 }
133
134 static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
135                          struct dm_report_field *field,
136                          const void *data, void *private __attribute__((unused)))
137 {
138         return _format_pvsegs(mem, field, data, 0);
139 }
140
141 static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
142                           struct dm_report_field *field,
143                           const void *data, void *private __attribute__((unused)))
144 {
145         return _format_pvsegs(mem, field, data, 1);
146 }
147
148 static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
149                       struct dm_report_field *field,
150                       const void *data, void *private __attribute__((unused)))
151 {
152         const struct dm_list *tags = (const struct dm_list *) data;
153         char *tags_str;
154
155         if (!(tags_str = tags_format_and_copy(mem, tags)))
156                 return 0;
157
158         dm_report_field_set_value(field, tags_str, NULL);
159
160         return 1;
161 }
162
163 static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
164                          struct dm_report_field *field,
165                          const void *data, void *private)
166 {
167         const struct logical_volume *lv = (const struct logical_volume *) data;
168         char *modules_str;
169
170         if (!(modules_str = lv_modules_dup(mem, lv)))
171                 return 0;
172
173         dm_report_field_set_value(field, modules_str, NULL);
174         return 1;
175 }
176
177 static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
178                        struct dm_report_field *field,
179                        const void *data, void *private)
180 {
181         const struct volume_group *vg = (const struct volume_group *) data;
182
183         if (!vg->fid) {
184                 dm_report_field_set_value(field, "", NULL);
185                 return 1;
186         }
187
188         return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
189 }
190
191 static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
192                        struct dm_report_field *field,
193                        const void *data, void *private)
194 {
195         const struct physical_volume *pv =
196             (const struct physical_volume *) data;
197
198         if (!pv->fmt) {
199                 dm_report_field_set_value(field, "", NULL);
200                 return 1;
201         }
202
203         return _string_disp(rh, mem, field, &pv->fmt->name, private);
204 }
205
206 static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
207                         struct dm_report_field *field,
208                         const void *data, void *private __attribute__((unused)))
209 {
210         const struct logical_volume *lv = (const struct logical_volume *) data;
211         int major;
212
213         if ((major = lv_kernel_major(lv)) >= 0)
214                 return dm_report_field_int(rh, field, &major);
215
216         return dm_report_field_int32(rh, field, &_minusone32);
217 }
218
219 static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
220                         struct dm_report_field *field,
221                         const void *data, void *private __attribute__((unused)))
222 {
223         const struct logical_volume *lv = (const struct logical_volume *) data;
224         int minor;
225
226         if ((minor = lv_kernel_minor(lv)) >= 0)
227                 return dm_report_field_int(rh, field, &minor);
228
229         return dm_report_field_int32(rh, field, &_minusone32);
230 }
231
232 static int _lvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
233                           struct dm_report_field *field,
234                           const void *data, void *private __attribute__((unused)))
235 {
236         const struct logical_volume *lv = (const struct logical_volume *) data;
237         char *repstr;
238
239         if (!(repstr = lv_attr_dup(mem, lv)))
240                 return 0;
241
242         dm_report_field_set_value(field, repstr, NULL);
243         return 1;
244 }
245
246 static int _pvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
247                           struct dm_report_field *field,
248                           const void *data, void *private __attribute__((unused)))
249 {
250         const struct physical_volume *pv =
251             (const struct physical_volume *) data;
252         char *repstr;
253
254         if (!(repstr = pv_attr_dup(mem, pv)))
255                 return 0;
256
257         dm_report_field_set_value(field, repstr, NULL);
258         return 1;
259 }
260
261 static int _vgstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
262                           struct dm_report_field *field,
263                           const void *data, void *private __attribute__((unused)))
264 {
265         const struct volume_group *vg = (const struct volume_group *) data;
266         char *repstr;
267
268         if (!(repstr = vg_attr_dup(mem, vg)))
269                 return 0;
270
271         dm_report_field_set_value(field, repstr, NULL);
272         return 1;
273 }
274
275 static int _segtype_disp(struct dm_report *rh __attribute__((unused)),
276                          struct dm_pool *mem __attribute__((unused)),
277                          struct dm_report_field *field,
278                          const void *data, void *private __attribute__((unused)))
279 {
280         const struct lv_segment *seg = (const struct lv_segment *) data;
281
282         char *name;
283         name = lvseg_segtype_dup(seg);
284         dm_report_field_set_value(field, name, NULL);
285         return 1;
286 }
287
288 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
289                        struct dm_report_field *field,
290                        const void *data, void *private __attribute__((unused)))
291 {
292         const struct logical_volume *lv = (const struct logical_volume *) data;
293         const char *name;
294
295         if ((name = lv_mirror_log_dup(mem, lv)))
296                 return dm_report_field_string(rh, field, &name);
297
298         dm_report_field_set_value(field, "", NULL);
299         return 1;
300 }
301
302 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
303                         struct dm_report_field *field,
304                         const void *data, void *private __attribute__((unused)))
305 {
306         const struct logical_volume *lv = (const struct logical_volume *) data;
307         char *repstr, *lvname;
308         size_t len;
309
310         if (lv_is_visible(lv)) {
311                 repstr = lv->name;
312                 return dm_report_field_string(rh, field, (const char **) &repstr);
313         }
314
315         len = strlen(lv->name) + 3;
316         if (!(repstr = dm_pool_zalloc(mem, len))) {
317                 log_error("dm_pool_alloc failed");
318                 return 0;
319         }
320
321         if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
322                 log_error("lvname snprintf failed");
323                 return 0;
324         }
325
326         if (!(lvname = dm_pool_strdup(mem, lv->name))) {
327                 log_error("dm_pool_strdup failed");
328                 return 0;
329         }
330
331         dm_report_field_set_value(field, repstr, lvname);
332
333         return 1;
334 }
335
336 static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem,
337                         struct dm_report_field *field,
338                         const void *data, void *private __attribute__((unused)))
339 {
340         const struct logical_volume *lv = (const struct logical_volume *) data;
341         char *repstr;
342
343         if (!(repstr = lv_path_dup(mem, lv)))
344                 return 0;
345
346         dm_report_field_set_value(field, repstr, NULL);
347
348         return 1;
349 }
350
351 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
352                         struct dm_report_field *field,
353                         const void *data, void *private)
354 {
355         const struct logical_volume *lv = (const struct logical_volume *) data;
356
357         if (lv_is_cow(lv))
358                 return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
359
360         dm_report_field_set_value(field, "", NULL);
361         return 1;
362 }
363
364 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
365                         struct dm_report_field *field,
366                         const void *data, void *private __attribute__((unused)))
367 {
368         const struct logical_volume *lv = (const struct logical_volume *) data;
369         const char *name;
370
371         if (!(name = lv_move_pv_dup(mem, lv)))
372                 dm_report_field_set_value(field, "", NULL);
373         else
374                 return dm_report_field_string(rh, field, &name);
375         return 1;
376 }
377
378 static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
379                            struct dm_report_field *field,
380                            const void *data, void *private __attribute__((unused)))
381 {
382         const struct logical_volume *lv = (const struct logical_volume *) data;
383         const char *name = NULL;
384
385         name = lv_convert_lv_dup(mem, lv);
386         if (name)
387                 return dm_report_field_string(rh, field, &name);
388
389         dm_report_field_set_value(field, "", NULL);
390         return 1;
391 }
392
393 static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
394                         struct dm_report_field *field,
395                         const void *data, void *private)
396 {
397         const uint32_t size = *(const uint32_t *) data;
398         const char *disp, *repstr;
399         uint64_t *sortval;
400
401         if (!*(disp = display_size_units(private, (uint64_t) size)))
402                 return_0;
403
404         if (!(repstr = dm_pool_strdup(mem, disp))) {
405                 log_error("dm_pool_strdup failed");
406                 return 0;
407         }
408
409         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
410                 log_error("dm_pool_alloc failed");
411                 return 0;
412         }
413
414         *sortval = (const uint64_t) size;
415
416         dm_report_field_set_value(field, repstr, sortval);
417
418         return 1;
419 }
420
421 static int _size64_disp(struct dm_report *rh __attribute__((unused)),
422                         struct dm_pool *mem,
423                         struct dm_report_field *field,
424                         const void *data, void *private)
425 {
426         const uint64_t size = *(const uint64_t *) data;
427         const char *disp, *repstr;
428         uint64_t *sortval;
429
430         if (!*(disp = display_size_units(private, size)))
431                 return_0;
432
433         if (!(repstr = dm_pool_strdup(mem, disp))) {
434                 log_error("dm_pool_strdup failed");
435                 return 0;
436         }
437
438         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
439                 log_error("dm_pool_alloc failed");
440                 return 0;
441         }
442
443         *sortval = size;
444         dm_report_field_set_value(field, repstr, sortval);
445
446         return 1;
447 }
448
449 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
450                              struct dm_report_field *field,
451                              const void *data, void *private __attribute__((unused)))
452 {
453         const struct logical_volume *lv = (const struct logical_volume *) data;
454
455         if (lv->read_ahead == DM_READ_AHEAD_AUTO) {
456                 dm_report_field_set_value(field, "auto", &_minusone64);
457                 return 1;
458         }
459
460         return _size32_disp(rh, mem, field, &lv->read_ahead, private);
461 }
462
463 static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
464                               struct dm_report_field *field,
465                               const void *data,
466                               void *private)
467 {
468         const struct logical_volume *lv = (const struct logical_volume *) data;
469         uint32_t read_ahead;
470
471         if ((read_ahead = lv_kernel_read_ahead(lv)) == UINT32_MAX)
472                 return dm_report_field_int32(rh, field, &_minusone32);
473
474         return _size32_disp(rh, mem, field, &read_ahead, private);
475 }
476
477 static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
478                         struct dm_report_field *field,
479                         const void *data, void *private)
480 {
481         const struct volume_group *vg = (const struct volume_group *) data;
482         uint64_t size;
483
484         size = (uint64_t) vg_size(vg);
485
486         return _size64_disp(rh, mem, field, &size, private);
487 }
488
489 static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
490                           struct dm_report_field *field,
491                           const void *data, void *private)
492 {
493         const struct lv_segment *seg = (const struct lv_segment *) data;
494         uint64_t start;
495
496         start = lvseg_start(seg);
497
498         return _size64_disp(rh, mem, field, &start, private);
499 }
500
501 static int _segstartpe_disp(struct dm_report *rh,
502                             struct dm_pool *mem __attribute__((unused)),
503                             struct dm_report_field *field,
504                             const void *data,
505                             void *private __attribute__((unused)))
506 {
507         const struct lv_segment *seg = (const struct lv_segment *) data;
508
509         return dm_report_field_uint32(rh, field, &seg->le);
510 }
511
512 static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
513                          struct dm_report_field *field,
514                          const void *data, void *private)
515 {
516         const struct lv_segment *seg = (const struct lv_segment *) data;
517         uint64_t size;
518
519         size = lvseg_size(seg);
520
521         return _size64_disp(rh, mem, field, &size, private);
522 }
523
524 static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
525                            struct dm_report_field *field,
526                            const void *data, void *private)
527 {
528         const struct lv_segment *seg = (const struct lv_segment *) data;
529         uint64_t size;
530
531         size = lvseg_chunksize(seg);
532
533         return _size64_disp(rh, mem, field, &size, private);
534 }
535
536 static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
537                             struct dm_report_field *field,
538                             const void *data, void *private)
539 {
540         const struct logical_volume *lv = (const struct logical_volume *) data;
541         uint64_t size;
542
543         size = lv_origin_size(lv);
544
545         return _size64_disp(rh, mem, field, &size, private);
546 }
547
548 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
549                         struct dm_report_field *field,
550                         const void *data, void *private)
551 {
552         const struct physical_volume *pv =
553             (const struct physical_volume *) data;
554         uint64_t used;
555
556         used = pv_used(pv);
557
558         return _size64_disp(rh, mem, field, &used, private);
559 }
560
561 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
562                         struct dm_report_field *field,
563                         const void *data, void *private)
564 {
565         const struct physical_volume *pv =
566             (const struct physical_volume *) data;
567         uint64_t freespace;
568
569         freespace = pv_free(pv);
570
571         return _size64_disp(rh, mem, field, &freespace, private);
572 }
573
574 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
575                         struct dm_report_field *field,
576                         const void *data, void *private)
577 {
578         const struct physical_volume *pv =
579             (const struct physical_volume *) data;
580         uint64_t size;
581
582         size = pv_size_field(pv);
583
584         return _size64_disp(rh, mem, field, &size, private);
585 }
586
587 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
588                          struct dm_report_field *field,
589                          const void *data, void *private)
590 {
591         const struct physical_volume *pv =
592             (const struct physical_volume *) data;
593         uint64_t size;
594
595         size = pv_dev_size(pv);
596
597         return _size64_disp(rh, mem, field, &size, private);
598 }
599
600 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
601                         struct dm_report_field *field,
602                         const void *data, void *private)
603 {
604         const struct volume_group *vg = (const struct volume_group *) data;
605         uint64_t freespace;
606
607         freespace = (uint64_t) vg_free(vg);
608
609         return _size64_disp(rh, mem, field, &freespace, private);
610 }
611
612 static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
613                       struct dm_report_field *field,
614                       const void *data, void *private __attribute__((unused)))
615 {
616         char *repstr = NULL;
617
618         if (!(repstr = id_format_and_copy(mem, (struct id *)data)))
619                 return_0;
620
621         dm_report_field_set_value(field, repstr, NULL);
622         return 1;
623 }
624
625 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
626                         struct dm_report_field *field,
627                         const void *data, void *private __attribute__((unused)))
628 {
629         return dm_report_field_uint32(rh, field, data);
630 }
631
632 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
633                        struct dm_report_field *field,
634                        const void *data, void *private __attribute__((unused)))
635 {
636         return dm_report_field_int32(rh, field, data);
637 }
638
639 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
640                         struct dm_report_field *field,
641                         const void *data, void *private)
642 {
643         uint32_t count;
644         const struct physical_volume *pv =
645             (const struct physical_volume *) data;
646
647         count = pv_mda_count(pv);
648
649         return _uint32_disp(rh, mem, field, &count, private);
650 }
651
652 static int _pvmdasused_disp(struct dm_report *rh, struct dm_pool *mem,
653                              struct dm_report_field *field,
654                              const void *data, void *private)
655 {
656         uint32_t count;
657         const struct physical_volume *pv =
658             (const struct physical_volume *) data;
659
660         count = pv_mda_used_count(pv);
661
662         return _uint32_disp(rh, mem, field, &count, private);
663 }
664
665 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem,
666                         struct dm_report_field *field,
667                         const void *data, void *private)
668 {
669         const struct volume_group *vg = (const struct volume_group *) data;
670         uint32_t count;
671
672         count = vg_mda_count(vg);
673
674         return _uint32_disp(rh, mem, field, &count, private);
675 }
676
677 static int _vgmdasused_disp(struct dm_report *rh, struct dm_pool *mem,
678                              struct dm_report_field *field,
679                              const void *data, void *private)
680 {
681         const struct volume_group *vg = (const struct volume_group *) data;
682         uint32_t count;
683
684         count = vg_mda_used_count(vg);
685
686         return _uint32_disp(rh, mem, field, &count, private);
687 }
688
689 static int _vgmdacopies_disp(struct dm_report *rh, struct dm_pool *mem,
690                                    struct dm_report_field *field,
691                                    const void *data, void *private)
692 {
693         const struct volume_group *vg = (const struct volume_group *) data;
694         uint32_t count;
695
696         count = vg_mda_copies(vg);
697
698         if (count == VGMETADATACOPIES_UNMANAGED) {
699                 dm_report_field_set_value(field, "unmanaged", &_minusone64);
700                 return 1;
701         }
702
703         return _uint32_disp(rh, mem, field, &count, private);
704 }
705
706 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
707                            struct dm_report_field *field,
708                            const void *data, void *private)
709 {
710         const struct physical_volume *pv =
711             (const struct physical_volume *) data;
712         uint64_t freespace;
713
714         freespace = pv_mda_free(pv);
715
716         return _size64_disp(rh, mem, field, &freespace, private);
717 }
718
719 static int _pvmdasize_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 physical_volume *pv =
724             (const struct physical_volume *) data;
725         uint64_t min_mda_size;
726
727         min_mda_size = pv_mda_size(pv);
728
729         return _size64_disp(rh, mem, field, &min_mda_size, private);
730 }
731
732 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
733                            struct dm_report_field *field,
734                            const void *data, void *private)
735 {
736         const struct volume_group *vg = (const struct volume_group *) data;
737         uint64_t min_mda_size;
738
739         min_mda_size = vg_mda_size(vg);
740
741         return _size64_disp(rh, mem, field, &min_mda_size, private);
742 }
743
744 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
745                            struct dm_report_field *field,
746                            const void *data, void *private)
747 {
748         const struct volume_group *vg = (const struct volume_group *) data;
749         uint64_t freespace;
750
751         freespace = vg_mda_free(vg);
752
753         return _size64_disp(rh, mem, field, &freespace, private);
754 }
755
756 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem,
757                          struct dm_report_field *field,
758                          const void *data, void *private)
759 {
760         const struct volume_group *vg = (const struct volume_group *) data;
761         uint32_t count;
762
763         count = vg_visible_lvs(vg);
764
765         return _uint32_disp(rh, mem, field, &count, private);
766 }
767
768 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
769                             struct dm_report_field *field,
770                             const void *data, void *private)
771 {
772         const struct logical_volume *lv = (const struct logical_volume *) data;
773         uint32_t count;
774
775         count = dm_list_size(&lv->segments);
776
777         return _uint32_disp(rh, mem, field, &count, private);
778 }
779
780 static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem,
781                            struct dm_report_field *field,
782                            const void *data, void *private)
783 {
784         const struct volume_group *vg = (const struct volume_group *) data;
785         uint32_t count;
786
787         count = snapshot_count(vg);
788
789         return _uint32_disp(rh, mem, field, &count, private);
790 }
791
792 static int _snpercent_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
793                            struct dm_report_field *field,
794                            const void *data, void *private __attribute__((unused)))
795 {
796         const struct logical_volume *lv = (const struct logical_volume *) data;
797         struct lvinfo info;
798         percent_t snap_percent;
799         uint64_t *sortval;
800         char *repstr;
801
802         /* Suppress snapshot percentage if not using driver */
803         if (!activation()) {
804                 dm_report_field_set_value(field, "", NULL);
805                 return 1;
806         }
807
808         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
809                 log_error("dm_pool_alloc failed");
810                 return 0;
811         }
812
813         if ((!lv_is_cow(lv) && !lv_is_merging_origin(lv)) ||
814             !lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) || !info.exists) {
815                 *sortval = UINT64_C(0);
816                 dm_report_field_set_value(field, "", sortval);
817                 return 1;
818         }
819
820         if (!lv_snapshot_percent(lv, &snap_percent) ||
821                                  (snap_percent == PERCENT_INVALID)) {
822                 if (!lv_is_merging_origin(lv)) {
823                         *sortval = UINT64_C(100);
824                         dm_report_field_set_value(field, "100.00", sortval);
825                 } else {
826                         /* onactivate merge that hasn't started yet would
827                          * otherwise display incorrect snap% in origin
828                          */
829                         *sortval = UINT64_C(0);
830                         dm_report_field_set_value(field, "", sortval);
831                 }
832                 return 1;
833         }
834
835         if (!(repstr = dm_pool_zalloc(mem, 8))) {
836                 log_error("dm_pool_alloc failed");
837                 return 0;
838         }
839
840         if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(snap_percent)) < 0) {
841                 log_error("snapshot percentage too large");
842                 return 0;
843         }
844
845         *sortval = (uint64_t)(snap_percent * 1000.f);
846         dm_report_field_set_value(field, repstr, sortval);
847
848         return 1;
849 }
850
851 static int _copypercent_disp(struct dm_report *rh __attribute__((unused)),
852                              struct dm_pool *mem,
853                              struct dm_report_field *field,
854                              const void *data, void *private __attribute__((unused)))
855 {
856         struct logical_volume *lv = (struct logical_volume *) data;
857         percent_t percent;
858         uint64_t *sortval;
859         char *repstr;
860
861         if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
862                 log_error("dm_pool_alloc failed");
863                 return 0;
864         }
865
866         if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
867             !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent,
868                                NULL) || (percent == PERCENT_INVALID)) {
869                 *sortval = UINT64_C(0);
870                 dm_report_field_set_value(field, "", sortval);
871                 return 1;
872         }
873
874         percent = copy_percent(lv);
875
876         if (!(repstr = dm_pool_zalloc(mem, 8))) {
877                 log_error("dm_pool_alloc failed");
878                 return 0;
879         }
880
881         if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(percent)) < 0) {
882                 log_error("copy percentage too large");
883                 return 0;
884         }
885
886         *sortval = (uint64_t)(percent * 1000.f);
887         dm_report_field_set_value(field, repstr, sortval);
888
889         return 1;
890 }
891
892 /* Report object types */
893
894 /* necessary for displaying something for PVs not belonging to VG */
895 static struct format_instance _dummy_fid = {
896         .metadata_areas_in_use = { &(_dummy_fid.metadata_areas_in_use), &(_dummy_fid.metadata_areas_in_use) },
897         .metadata_areas_ignored = { &(_dummy_fid.metadata_areas_ignored), &(_dummy_fid.metadata_areas_ignored) },
898 };
899
900 static struct volume_group _dummy_vg = {
901         .fid = &_dummy_fid,
902         .name = (char *) "",
903         .system_id = (char *) "",
904         .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
905         .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
906         .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) },
907 };
908
909 static void *_obj_get_vg(void *obj)
910 {
911         struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
912
913         return vg ? vg : &_dummy_vg;
914 }
915
916 static void *_obj_get_lv(void *obj)
917 {
918         return ((struct lvm_report_object *)obj)->lv;
919 }
920
921 static void *_obj_get_pv(void *obj)
922 {
923         return ((struct lvm_report_object *)obj)->pv;
924 }
925
926 static void *_obj_get_seg(void *obj)
927 {
928         return ((struct lvm_report_object *)obj)->seg;
929 }
930
931 static void *_obj_get_pvseg(void *obj)
932 {
933         return ((struct lvm_report_object *)obj)->pvseg;
934 }
935
936 static const struct dm_report_object_type _report_types[] = {
937         { VGS, "Volume Group", "vg_", _obj_get_vg },
938         { LVS, "Logical Volume", "lv_", _obj_get_lv },
939         { PVS, "Physical Volume", "pv_", _obj_get_pv },
940         { LABEL, "Physical Volume Label", "pv_", _obj_get_pv },
941         { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
942         { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
943         { 0, "", "", NULL },
944 };
945
946 /*
947  * Import column definitions
948  */
949
950 #define STR DM_REPORT_FIELD_TYPE_STRING
951 #define NUM DM_REPORT_FIELD_TYPE_NUMBER
952 #define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \
953         {type, sorttype, offsetof(type_ ## strct, field), width, \
954          #id, head, &_ ## func ## _disp, desc},
955
956 typedef struct physical_volume type_pv;
957 typedef struct logical_volume type_lv;
958 typedef struct volume_group type_vg;
959 typedef struct lv_segment type_seg;
960 typedef struct pv_segment type_pvseg;
961
962 static const struct dm_report_field_type _fields[] = {
963 #include "columns.h"
964 {0, 0, 0, 0, "", "", NULL, NULL},
965 };
966
967 #undef STR
968 #undef NUM
969 #undef FIELD
970
971 void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
972                   report_type_t *report_type, const char *separator,
973                   int aligned, int buffered, int headings, int field_prefixes,
974                   int quoted, int columns_as_rows)
975 {
976         uint32_t report_flags = 0;
977         void *rh;
978
979         if (aligned)
980                 report_flags |= DM_REPORT_OUTPUT_ALIGNED;
981
982         if (buffered)
983                 report_flags |= DM_REPORT_OUTPUT_BUFFERED;
984
985         if (headings)
986                 report_flags |= DM_REPORT_OUTPUT_HEADINGS;
987
988         if (field_prefixes)
989                 report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
990
991         if (!quoted)
992                 report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
993
994         if (columns_as_rows)
995                 report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
996
997         rh = dm_report_init(report_type, _report_types, _fields, format,
998                             separator, report_flags, keys, cmd);
999
1000         if (rh && field_prefixes)
1001                 dm_report_set_output_field_name_prefix(rh, "lvm2_");
1002
1003         return rh;
1004 }
1005
1006 /*
1007  * Create a row of data for an object
1008  */
1009 int report_object(void *handle, struct volume_group *vg,
1010                   struct logical_volume *lv, struct physical_volume *pv,
1011                   struct lv_segment *seg, struct pv_segment *pvseg)
1012 {
1013         struct lvm_report_object obj;
1014
1015         /* The two format fields might as well match. */
1016         if (!vg && pv)
1017                 _dummy_fid.fmt = pv->fmt;
1018
1019         obj.vg = vg;
1020         obj.lv = lv;
1021         obj.pv = pv;
1022         obj.seg = seg;
1023         obj.pvseg = pvseg;
1024
1025         return dm_report_object(handle, &obj);
1026 }