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