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