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