Home | History | Annotate | Line # | Download | only in report
      1 /*	$NetBSD: report.c,v 1.2 2011/05/30 16:03:02 joerg 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 
     31 struct 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 
     39 static 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 
     55 static const uint64_t _minusone = UINT64_C(-1);
     56 
     57 /*
     58  * Data-munging functions to prepare each data type for display and sorting
     59  */
     60 static 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 
     67 static 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 
     76 static 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 
    151 static 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 
    158 static 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 
    165 static 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 
    195 static 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 
    213 static 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 
    227 static 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 
    242 static 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 
    255 static 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 
    268 static 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 
    284 static 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 
    378 out:
    379 	dm_report_field_set_value(field, repstr, NULL);
    380 	return 1;
    381 }
    382 
    383 static 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 
    409 static 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 
    452 static 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 
    468 static 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 
    486 static 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 
    520 static 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 
    533 static 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 
    552 static 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 
    578 static 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 
    606 static 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 
    634 static 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 
    648 static 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 
    662 static 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 
    674 static 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 
    686 static 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 
    697 static 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 
    709 static 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 
    724 static 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 
    741 static 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 
    757 static 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 
    773 static 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 
    789 static 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 
    802 static 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 
    814 static 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 
    832 static 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 
    839 static 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 
    846 static 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 
    859 static 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 
    871 static 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 
    895 static 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 
    914 static 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 
    929 static 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 
    941 static 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 
    963 static 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 
    975 static 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 
    987 static 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 
    999 static 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 
   1051 static 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 */
   1096 static struct format_instance _dummy_fid = {
   1097 	.metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) },
   1098 };
   1099 
   1100 static 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 
   1109 static 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 
   1116 static void *_obj_get_lv(void *obj)
   1117 {
   1118 	return ((struct lvm_report_object *)obj)->lv;
   1119 }
   1120 
   1121 static void *_obj_get_pv(void *obj)
   1122 {
   1123 	return ((struct lvm_report_object *)obj)->pv;
   1124 }
   1125 
   1126 static void *_obj_get_seg(void *obj)
   1127 {
   1128 	return ((struct lvm_report_object *)obj)->seg;
   1129 }
   1130 
   1131 static void *_obj_get_pvseg(void *obj)
   1132 {
   1133 	return ((struct lvm_report_object *)obj)->pvseg;
   1134 }
   1135 
   1136 static 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 
   1156 typedef struct physical_volume type_pv;
   1157 typedef struct logical_volume type_lv;
   1158 typedef struct volume_group type_vg;
   1159 typedef struct lv_segment type_seg;
   1160 typedef struct pv_segment type_pvseg;
   1161 
   1162 static 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 
   1171 void *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  */
   1209 int 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