[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH] (4/4) LVM2 to use dm_report



Hi,

This patch makes LVM2 to use dm_report in libdevmapper
instead of its lib/report functions.

Tested following commands where LVs of linear, striped, mirrored
and snapshot exist and confirmed the output is same with the
original LVM2 2.02.17.

  lvs
  pvs
  vgs
  lvs -a
  pvs -a
  lvs -a -o +devices
  lvs -o name,name,lv_name,vg_name
  lvs -a -o name,name,lv_name,vg_name
  lvs -a -o name,lv_name,vg_name -O name
  lvs -a -o name,lv_name,vg_name -O -name
  lvs -a -o name,lv_name,vg_name -O size
  lvs -a -o name,lv_name,vg_name -O lv_size
  lvs -a -o name,lv_name,vg_name -O -size
  pvs -o +pe_alloc_count,used,dev_size
  pvs -a -o +pe_alloc_count,used,dev_size

Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
Replaces lib/report by dm_report API in libdevmapper.


Index: LVM2.02.17/lib/Makefile.in
===================================================================
--- LVM2.02.17.orig/lib/Makefile.in	2007-01-11 11:27:16.000000000 -0500
+++ LVM2.02.17/lib/Makefile.in	2007-01-12 03:46:15.000000000 -0500
@@ -84,7 +84,6 @@ SOURCES =\
 	regex/matcher.c \
 	regex/parse_rx.c \
 	regex/ttree.c \
-	report/report.c \
 	striped/striped.c \
 	uuid/uuid.c \
 	zero/zero.c
Index: LVM2.02.17/lib/report/columns.h
===================================================================
--- LVM2.02.17.orig/lib/report/columns.h	2006-10-07 06:42:27.000000000 -0400
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/* Report type, Containing struct, Field type, Report heading,
- * Data field with struct to pass to display function, Minimum display width,
- * Display Fn, Unique format identifier */
-
-/* *INDENT-OFF* */
-FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
-FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
-FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
-FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
-FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
-FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
-FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
-FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
-FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
-FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
-FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
-FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
-FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
-FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
-FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
-FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
-
-FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
-FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
-FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
-FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
-FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
-FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
-FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
-FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
-FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
-FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
-FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
-FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
-
-FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
-FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
-FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
-FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
-FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
-FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
-FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
-FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
-FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
-FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
-FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
-FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
-FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
-FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
-FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
-FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
-FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
-
-FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
-FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
-FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
-FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
-FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
-FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
-
-FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
-FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
-/* *INDENT-ON* */
Index: LVM2.02.17/lib/report/report.c
===================================================================
--- LVM2.02.17.orig/lib/report/report.c	2007-01-11 11:27:16.000000000 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,1572 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include "lib.h"
-#include "metadata.h"
-#include "report.h"
-#include "toolcontext.h"
-#include "lvm-string.h"
-#include "display.h"
-#include "activate.h"
-#include "segtype.h"
-#include "str_list.h"
-
-/* 
- * For macro use
- */
-static union {
-	struct physical_volume _pv;
-	struct logical_volume _lv;
-	struct volume_group _vg;
-	struct lv_segment _seg;
-	struct pv_segment _pvseg;
-} _dummy;
-
-/*
- * Report handle flags
- */
-#define RH_SORT_REQUIRED	0x00000001
-#define RH_HEADINGS_PRINTED	0x00000002
-#define RH_BUFFERED		0x00000004
-#define RH_ALIGNED		0x00000008
-#define RH_HEADINGS		0x00000010
-
-struct report_handle {
-	struct cmd_context *cmd;
-	struct dm_pool *mem;
-
-	report_type_t type;
-	const char *field_prefix;
-	uint32_t flags;
-	const char *separator;
-
-	uint32_t keys_count;
-
-	/* Ordered list of fields needed for this report */
-	struct list field_props;
-
-	/* Rows of report data */
-	struct list rows;
-};
-
-/* 
- * Per-field flags
- */
-#define FLD_ALIGN_LEFT	0x00000001
-#define FLD_ALIGN_RIGHT	0x00000002
-#define FLD_STRING	0x00000004
-#define FLD_NUMBER	0x00000008
-#define FLD_HIDDEN	0x00000010
-#define FLD_SORT_KEY	0x00000020
-#define FLD_ASCENDING	0x00000040
-#define FLD_DESCENDING	0x00000080
-
-struct field_properties {
-	struct list list;
-	uint32_t field_num;
-	uint32_t sort_posn;
-	int width;
-	uint32_t flags;
-};
-
-/* 
- * Report data
- */
-struct field {
-	struct list list;
-	struct field_properties *props;
-
-	const char *report_string;	/* Formatted ready for display */
-	const void *sort_value;	/* Raw value for sorting */
-};
-
-struct row {
-	struct list list;
-	struct report_handle *rh;
-	struct list fields;	/* Fields in display order */
-	struct field *(*sort_fields)[];	/* Fields in sort order */
-};
-
-static char _alloc_policy_char(alloc_policy_t alloc)
-{
-	switch (alloc) {
-	case ALLOC_CONTIGUOUS:
-		return 'c';
-	case ALLOC_CLING:
-		return 'C';
-	case ALLOC_NORMAL:
-		return 'n';
-	case ALLOC_ANYWHERE:
-		return 'a';
-	default:
-		return 'i';
-	}
-}
-
-/*
- * Data-munging functions to prepare each data type for display and sorting
- */
-static int _string_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	if (!
-	    (field->report_string =
-	     dm_pool_strdup(rh->mem, *(const char **) data))) {
-		log_error("dm_pool_strdup failed");
-		return 0;
-	}
-
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _dev_name_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
-{
-	const char *name = dev_name(*(const struct device **) data);
-
-	return _string_disp(rh, field, &name);
-}
-
-static int _devices_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
-{
-	const struct lv_segment *seg = (const struct lv_segment *) data;
-	unsigned int s;
-	const char *name = NULL;
-	uint32_t extent = 0;
-	char extent_str[32];
-
-	if (!dm_pool_begin_object(rh->mem, 256)) {
-		log_error("dm_pool_begin_object failed");
-		return 0;
-	}
-
-	for (s = 0; s < seg->area_count; s++) {
-		switch (seg_type(seg, s)) {
-		case AREA_LV:
-			name = seg_lv(seg, s)->name;
-			extent = seg_le(seg, s);
-			break;
-		case AREA_PV:
-			name = dev_name(seg_dev(seg, s));
-			extent = seg_pe(seg, s);
-			break;
-		case AREA_UNASSIGNED:
-			name = "unassigned";
-			extent = 0;
-		}
-
-		if (!dm_pool_grow_object(rh->mem, name, strlen(name))) {
-			log_error("dm_pool_grow_object failed");
-			return 0;
-		}
-
-		if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
-				 ")", extent) < 0) {
-			log_error("Extent number dm_snprintf failed");
-			return 0;
-		}
-
-		if (!dm_pool_grow_object(rh->mem, extent_str, strlen(extent_str))) {
-			log_error("dm_pool_grow_object failed");
-			return 0;
-		}
-
-		if ((s != seg->area_count - 1) &&
-		    !dm_pool_grow_object(rh->mem, ",", 1)) {
-			log_error("dm_pool_grow_object failed");
-			return 0;
-		}
-	}
-
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-		log_error("dm_pool_grow_object failed");
-		return 0;
-	}
-
-	field->report_string = dm_pool_end_object(rh->mem);
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _tags_disp(struct report_handle *rh, struct field *field,
-		      const void *data)
-{
-	const struct list *tags = (const struct list *) data;
-	struct str_list *sl;
-
-	if (!dm_pool_begin_object(rh->mem, 256)) {
-		log_error("dm_pool_begin_object failed");
-		return 0;
-	}
-
-	list_iterate_items(sl, tags) {
-		if (!dm_pool_grow_object(rh->mem, sl->str, strlen(sl->str)) ||
-		    (sl->list.n != tags && !dm_pool_grow_object(rh->mem, ",", 1))) {
-			log_error("dm_pool_grow_object failed");
-			return 0;
-		}
-	}
-
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-		log_error("dm_pool_grow_object failed");
-		return 0;
-	}
-
-	field->report_string = dm_pool_end_object(rh->mem);
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _modules_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct list *modules;
-
-	if (!(modules = str_list_create(rh->mem))) {
-		log_error("modules str_list allocation failed");
-		return 0;
-	}
-
-	if (!list_lv_modules(rh->mem, lv, modules))
-		return_0;
-
-	return _tags_disp(rh, field, modules);
-}
-
-static int _vgfmt_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
-{
-	const struct volume_group *vg = (const struct volume_group *) data;
-
-	if (!vg->fid) {
-		field->report_string = "";
-		field->sort_value = (const void *) field->report_string;
-		return 1;
-	}
-
-	return _string_disp(rh, field, &vg->fid->fmt->name);
-}
-
-static int _pvfmt_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
-{
-	const struct physical_volume *pv =
-	    (const struct physical_volume *) data;
-
-	if (!pv->fmt) {
-		field->report_string = "";
-		field->sort_value = (const void *) field->report_string;
-		return 1;
-	}
-
-	return _string_disp(rh, field, &pv->fmt->name);
-}
-
-static int _int_disp(struct report_handle *rh, struct field *field,
-		     const void *data)
-{
-	const int value = *(const int *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
-		log_error("int too big: %d", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lvinfo info;
-	uint64_t minusone = UINT64_C(-1);
-
-	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
-		return _int_disp(rh, field, &info.major);
-	else
-		return _int_disp(rh, field, &minusone);
-
-	return 1;
-}
-
-static int _lvkmin_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lvinfo info;
-	uint64_t minusone = UINT64_C(-1);
-
-	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
-		return _int_disp(rh, field, &info.minor);
-	else
-		return _int_disp(rh, field, &minusone);
-
-	return 1;
-}
-
-static int _lvstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lvinfo info;
-	char *repstr;
-	float snap_percent;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (lv->status & PVMOVE)
-		repstr[0] = 'p';
-	else if (lv->status & MIRRORED) {
-		if (lv->status & MIRROR_NOTSYNCED)
-			repstr[0] = 'M';
-		else
-			repstr[0] = 'm';
-	}else if (lv->status & MIRROR_IMAGE)
-		repstr[0] = 'i';
-	else if (lv->status & MIRROR_LOG)
-		repstr[0] = 'l';
-	else if (lv->status & VIRTUAL)
-		repstr[0] = 'v';
-	else if (lv_is_origin(lv))
-		repstr[0] = 'o';
-	else if (lv_is_cow(lv))
-		repstr[0] = 's';
-	else
-		repstr[0] = '-';
-
-	if (lv->status & PVMOVE)
-		repstr[1] = '-';
-	else if (lv->status & LVM_WRITE)
-		repstr[1] = 'w';
-	else
-		repstr[1] = 'r';
-
-	repstr[2] = _alloc_policy_char(lv->alloc);
-
-	if (lv->status & LOCKED)
-		repstr[2] = toupper(repstr[2]);
-
-	if (lv->status & FIXED_MINOR)
-		repstr[3] = 'm';	/* Fixed Minor */
-	else
-		repstr[3] = '-';
-
-	if (lv_info(lv->vg->cmd, lv, &info, 1) && info.exists) {
-		if (info.suspended)
-			repstr[4] = 's';	/* Suspended */
-		else if (info.live_table)
-			repstr[4] = 'a';	/* Active */
-		else if (info.inactive_table)
-			repstr[4] = 'i';	/* Inactive with table */
-		else
-			repstr[4] = 'd';	/* Inactive without table */
-
-		/* Snapshot dropped? */
-		if (info.live_table && lv_is_cow(lv) &&
-		    (!lv_snapshot_percent(lv, &snap_percent) ||
-		     snap_percent < 0 || snap_percent >= 100)) {
-			repstr[0] = toupper(repstr[0]);
-			if (info.suspended)
-				repstr[4] = 'S'; /* Susp Inv snapshot */
-			else
-				repstr[4] = 'I'; /* Invalid snapshot */
-		}
-
-		if (info.open_count)
-			repstr[5] = 'o';	/* Open */
-		else
-			repstr[5] = '-';
-	} else {
-		repstr[4] = '-';
-		repstr[5] = '-';
-	}
-
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _pvstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
-{
-	const uint32_t status = *(const uint32_t *) data;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 4))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (status & ALLOCATABLE_PV)
-		repstr[0] = 'a';
-	else
-		repstr[0] = '-';
-
-	if (status & EXPORTED_VG)
-		repstr[1] = 'x';
-	else
-		repstr[1] = '-';
-
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _vgstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
-{
-	const struct volume_group *vg = (const struct volume_group *) data;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (vg->status & LVM_WRITE)
-		repstr[0] = 'w';
-	else
-		repstr[0] = 'r';
-
-	if (vg->status & RESIZEABLE_VG)
-		repstr[1] = 'z';
-	else
-		repstr[1] = '-';
-
-	if (vg->status & EXPORTED_VG)
-		repstr[2] = 'x';
-	else
-		repstr[2] = '-';
-
-	if (vg->status & PARTIAL_VG)
-		repstr[3] = 'p';
-	else
-		repstr[3] = '-';
-
-	repstr[4] = _alloc_policy_char(vg->alloc);
-
-	if (vg->status & CLUSTERED)
-		repstr[5] = 'c';
-	else
-		repstr[5] = '-';
-
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _segtype_disp(struct report_handle *rh __attribute((unused)),
-			 struct field *field,
-			 const void *data)
-{
-	const struct lv_segment *seg = (const struct lv_segment *) data;
-
-	if (seg->area_count == 1)
-		field->report_string = "linear";
-	else
-		field->report_string = seg->segtype->ops->name(seg);
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _origin_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-
-	if (lv_is_cow(lv))
-		return _string_disp(rh, field, &origin_from_cow(lv)->name);
-
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _loglv_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lv_segment *seg;
-
-	list_iterate_items(seg, &lv->segments) {
-		if (!seg_is_mirrored(seg) || !seg->log_lv)
-			continue;
-		return _string_disp(rh, field, &seg->log_lv->name);
-	}
-
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _lvname_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	char *repstr;
-	size_t len;
-
-	if (lv_is_visible(lv)) {
-		repstr = lv->name;
-		return _string_disp(rh, field, &repstr);
-	}
-
-	len = strlen(lv->name) + 3;
-	if (!(repstr = dm_pool_zalloc(rh->mem, len))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
-		log_error("lvname snprintf failed");
-		return 0;
-	}
-
-	field->report_string = repstr;
-
-	if (!(field->sort_value = dm_pool_strdup(rh->mem, lv->name))) {
-		log_error("dm_pool_strdup failed");
-		return 0;
-	}
-
-	return 1;
-}
-
-static int _movepv_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	const char *name;
-	struct lv_segment *seg;
-
-	list_iterate_items(seg, &lv->segments) {
-		if (!(seg->status & PVMOVE))
-			continue;
-		name = dev_name(seg_dev(seg, 0));
-		return _string_disp(rh, field, &name);
-	}
-
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _size32_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const uint32_t size = *(const uint32_t *) data;
-	const char *disp;
-	uint64_t *sortval;
-
-	if (!*(disp = display_size_units(rh->cmd, (uint64_t) size))) {
-		stack;
-		return 0;
-	}
-
-	if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
-		log_error("dm_pool_strdup failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	*sortval = (const uint64_t) size;
-	field->sort_value = (const void *) sortval;
-
-	return 1;
-}
-
-static int _size64_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const uint64_t size = *(const uint64_t *) data;
-	const char *disp;
-	uint64_t *sortval;
-
-	if (!*(disp = display_size_units(rh->cmd, size))) {
-		stack;
-		return 0;
-	}
-
-	if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
-		log_error("dm_pool_strdup failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	*sortval = size;
-	field->sort_value = sortval;
-
-	return 1;
-}
-
-static int _vgsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct volume_group *vg = (const struct volume_group *) data;
-	uint64_t size;
-
-	size = (uint64_t) vg->extent_count * vg->extent_size;
-
-	return _size64_disp(rh, field, &size);
-}
-
-static int _segstart_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
-{
-	const struct lv_segment *seg = (const struct lv_segment *) data;
-	uint64_t start;
-
-	start = (uint64_t) seg->le * seg->lv->vg->extent_size;
-
-	return _size64_disp(rh, field, &start);
-}
-
-static int _segsize_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
-{
-	const struct lv_segment *seg = (const struct lv_segment *) data;
-	uint64_t size;
-
-	size = (uint64_t) seg->len * seg->lv->vg->extent_size;
-
-	return _size64_disp(rh, field, &size);
-}
-
-static int _chunksize_disp(struct report_handle *rh, struct field *field,
-			   const void *data)
-{
-	const struct lv_segment *seg = (const struct lv_segment *) data;
-	uint64_t size;
-
-	if (lv_is_cow(seg->lv))
-		size = (uint64_t) find_cow(seg->lv)->chunk_size;
-	else
-		size = 0;
-
-	return _size64_disp(rh, field, &size);
-}
-
-static int _pvused_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct physical_volume *pv =
-	    (const struct physical_volume *) data;
-	uint64_t used;
-
-	if (!pv->pe_count)
-		used = 0LL;
-	else
-		used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
-
-	return _size64_disp(rh, field, &used);
-}
-
-static int _pvfree_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct physical_volume *pv =
-	    (const struct physical_volume *) data;
-	uint64_t freespace;
-
-	if (!pv->pe_count)
-		freespace = pv->size;
-	else
-		freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
-
-	return _size64_disp(rh, field, &freespace);
-}
-
-static int _pvsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct physical_volume *pv =
-	    (const struct physical_volume *) data;
-	uint64_t size;
-
-	if (!pv->pe_count)
-		size = pv->size;
-	else
-		size = (uint64_t) pv->pe_count * pv->pe_size;
-
-	return _size64_disp(rh, field, &size);
-}
-
-static int _devsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct device *dev = *(const struct device **) data;
-	uint64_t size;
-
-	if (!dev_get_size(dev, &size))
-		size = 0;
-
-	return _size64_disp(rh, field, &size);
-}
-
-static int _vgfree_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const struct volume_group *vg = (const struct volume_group *) data;
-	uint64_t freespace;
-
-	freespace = (uint64_t) vg->free_count * vg->extent_size;
-
-	return _size64_disp(rh, field, &freespace);
-}
-
-static int _uuid_disp(struct report_handle *rh, struct field *field,
-		      const void *data)
-{
-	char *repstr = NULL;
-
-	if (!(repstr = dm_pool_alloc(rh->mem, 40))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!id_write_format((const struct id *) data, repstr, 40)) {
-		stack;
-		return 0;
-	}
-
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
-}
-
-static int _uint32_disp(struct report_handle *rh, struct field *field,
-			const void *data)
-{
-	const uint32_t value = *(const uint32_t *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 11, "%u", value) < 0) {
-		log_error("uint32 too big: %u", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-static int _int32_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
-{
-	const int32_t value = *(const int32_t *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
-		log_error("int32 too big: %d", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-static int _lvsegcount_disp(struct report_handle *rh, struct field *field,
-			    const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	uint32_t count;
-
-	count = list_size(&lv->segments);
-
-	return _uint32_disp(rh, field, &count);
-}
-
-static int _snpercent_disp(struct report_handle *rh, struct field *field,
-			   const void *data)
-{
-	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lvinfo info;
-	float snap_percent;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!lv_is_cow(lv) ||
-	    (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
-		field->report_string = "";
-		*sortval = UINT64_C(0);
-		field->sort_value = sortval;
-		return 1;
-	}
-
-	if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
-		field->report_string = "100.00";
-		*sortval = UINT64_C(100);
-		field->sort_value = sortval;
-		return 1;
-	}
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
-		log_error("snapshot percentage too large");
-		return 0;
-	}
-
-	*sortval = snap_percent * UINT64_C(1000);
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-static int _copypercent_disp(struct report_handle *rh, struct field *field,
-			     const void *data)
-{
-	struct logical_volume *lv = (struct logical_volume *) data;
-	float percent;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
-	    !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) {
-		field->report_string = "";
-		*sortval = UINT64_C(0);
-		field->sort_value = sortval;
-		return 1;
-	}
-
-	percent = copy_percent(lv);
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
-		log_error("copy percentage too large");
-		return 0;
-	}
-
-	*sortval = percent * UINT64_C(1000);
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-/*
- * Import column definitions
- */
-
-#define STR (FLD_STRING | FLD_ALIGN_LEFT)
-#define NUM (FLD_NUMBER | FLD_ALIGN_RIGHT)
-#define FIELD(type, strct, sorttype, head, field, width, func, id) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp},
-
-static struct {
-	report_type_t type;
-	const char id[32];
-	off_t offset;
-	const char heading[32];
-	int width;
-	uint32_t flags;
-	field_report_fn report_fn;
-} _fields[] = {
-#include "columns.h"
-};
-
-#undef STR
-#undef NUM
-#undef FIELD
-
-const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
-
-static void _display_fields(void)
-{
-	uint32_t f;
-	const char *type, *last_type = "";
-
-	for (f = 0; f < _num_fields; f++) {
-		switch (_fields[f].type) {
-		case PVS:
-			type = "Physical Volume";
-			break;
-		case LVS:
-			type = "Logical Volume";
-			break;
-		case VGS:
-			type = "Volume Group";
-			break;
-		case SEGS:
-			type = "Logical Volume Segment";
-			break;
-		case PVSEGS:
-			type = "Physical Volume Segment";
-			break;
-		default:
-			type = " ";
-		}
-
-		if (type != last_type) {
-			if (*last_type)
-				log_print(" ");
-			log_print("%s Fields", type);
-		}
-
-		log_print("- %s", _fields[f].id);
-
-		last_type = type;
-	}
-}
-
-/*
- * Initialise report handle
- */
-static int _field_match(struct report_handle *rh, const char *field, size_t len)
-{
-	uint32_t f, l;
-	struct field_properties *fp;
-
-	if (!len)
-		return 0;
-
-	for (f = 0; f < _num_fields; f++) {
-		if ((!strncasecmp(_fields[f].id, field, len) &&
-		     strlen(_fields[f].id) == len) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
-		     !strncasecmp(_fields[f].id + l, field, len) &&
-		     strlen(_fields[f].id) == l + len)) {
-			rh->type |= _fields[f].type;
-			if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
-				log_error("struct field_properties allocation "
-					  "failed");
-				return 0;
-			}
-			fp->field_num = f;
-			fp->width = _fields[f].width;
-			fp->flags = _fields[f].flags;
-
-			/* Suppress snapshot percentage if not using driver */
-			if (!activation()
-			    && !strncmp(field, "snap_percent", len))
-				fp->flags |= FLD_HIDDEN;
-
-			list_add(&rh->field_props, &fp->list);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
-			 uint32_t flags)
-{
-	struct field_properties *fp, *found = NULL;
-
-	list_iterate_items(fp, &rh->field_props) {
-		if (fp->field_num == field_num) {
-			found = fp;
-			break;
-		}
-	}
-
-	if (!found) {
-		/* Add as a non-display field */
-		if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
-			log_error("struct field_properties allocation failed");
-			return 0;
-		}
-
-		rh->type |= _fields[field_num].type;
-		found->field_num = field_num;
-		found->width = _fields[field_num].width;
-		found->flags = _fields[field_num].flags | FLD_HIDDEN;
-
-		list_add(&rh->field_props, &found->list);
-	}
-
-	if (found->flags & FLD_SORT_KEY) {
-		log_error("Ignoring duplicate sort field: %s",
-			  _fields[field_num].id);
-		return 1;
-	}
-
-	found->flags |= FLD_SORT_KEY;
-	found->sort_posn = rh->keys_count++;
-	found->flags |= flags;
-
-	return 1;
-}
-
-static int _key_match(struct report_handle *rh, const char *key, size_t len)
-{
-	uint32_t f, l;
-	uint32_t flags = 0;
-
-	if (!len)
-		return 0;
-
-	if (*key == '+') {
-		key++;
-		len--;
-		flags = FLD_ASCENDING;
-	} else if (*key == '-') {
-		key++;
-		len--;
-		flags = FLD_DESCENDING;
-	} else
-		flags = FLD_ASCENDING;
-
-	if (!len) {
-		log_error("Missing sort field name");
-		return 0;
-	}
-
-	for (f = 0; f < _num_fields; f++) {
-		if ((!strncasecmp(_fields[f].id, key, len) &&
-		     strlen(_fields[f].id) == len) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
-		     !strncasecmp(_fields[f].id + l, key, len) &&
-		     strlen(_fields[f].id) == l + len)) {
-			return _add_sort_key(rh, f, flags);
-		}
-	}
-
-	return 0;
-}
-
-static int _parse_options(struct report_handle *rh, const char *format)
-{
-	const char *ws;		/* Word start */
-	const char *we = format;	/* Word end */
-
-	while (*we) {
-		/* Allow consecutive commas */
-		while (*we && *we == ',')
-			we++;
-		ws = we;
-		while (*we && *we != ',')
-			we++;
-		if (!_field_match(rh, ws, (size_t) (we - ws))) {
-			_display_fields();
-			log_print(" ");
-			log_error("Unrecognised field: %.*s", (int) (we - ws),
-				  ws);
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-static int _parse_keys(struct report_handle *rh, const char *keys)
-{
-	const char *ws;		/* Word start */
-	const char *we = keys;	/* Word end */
-
-	while (*we) {
-		/* Allow consecutive commas */
-		while (*we && *we == ',')
-			we++;
-		ws = we;
-		while (*we && *we != ',')
-			we++;
-		if (!_key_match(rh, ws, (size_t) (we - ws))) {
-			log_error("Unrecognised field: %.*s", (int) (we - ws),
-				  ws);
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
-		  report_type_t *report_type, const char *separator,
-		  int aligned, int buffered, int headings)
-{
-	struct report_handle *rh;
-
-	if (!(rh = dm_pool_zalloc(cmd->mem, sizeof(*rh)))) {
-		log_error("report_handle dm_pool_zalloc failed");
-		return 0;
-	}
-
-	rh->cmd = cmd;
-	rh->type = *report_type;
-	rh->separator = separator;
-
-	if (aligned)
-		rh->flags |= RH_ALIGNED;
-
-	if (buffered)
-		rh->flags |= RH_BUFFERED | RH_SORT_REQUIRED;
-
-	if (headings)
-		rh->flags |= RH_HEADINGS;
-
-	list_init(&rh->field_props);
-	list_init(&rh->rows);
-
-	switch (rh->type) {
-	case PVS:
-		rh->field_prefix = "pv_";
-		break;
-	case LVS:
-		rh->field_prefix = "lv_";
-		break;
-	case VGS:
-		rh->field_prefix = "vg_";
-		break;
-	case SEGS:
-		rh->field_prefix = "seg_";
-		break;
-	case PVSEGS:
-		rh->field_prefix = "pvseg_";
-		break;
-	default:
-		rh->field_prefix = "";
-	}
-
-	if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
-		log_error("Allocation of memory pool for report failed");
-		return NULL;
-	}
-
-	/* Generate list of fields for output based on format string & flags */
-	if (!_parse_options(rh, format))
-		return NULL;
-
-	if (!_parse_keys(rh, keys))
-		return NULL;
-
-	/* Ensure options selected are compatible */
-	if (rh->type & SEGS)
-		rh->type |= LVS;
-	if (rh->type & PVSEGS)
-		rh->type |= PVS;
-	if ((rh->type & LVS) && (rh->type & PVS)) {
-		log_error("Can't report LV and PV fields at the same time");
-		return NULL;
-	}
-
-	/* Change report type if fields specified makes this necessary */
-	if (rh->type & SEGS)
-		*report_type = SEGS;
-	else if (rh->type & LVS)
-		*report_type = LVS;
-	else if (rh->type & PVSEGS)
-		*report_type = PVSEGS;
-	else if (rh->type & PVS)
-		*report_type = PVS;
-
-	return rh;
-}
-
-void report_free(void *handle)
-{
-	struct report_handle *rh = handle;
-
-	dm_pool_destroy(rh->mem);
-
-	return;
-}
-
-/*
- * Create a row of data for an object
- */
-int report_object(void *handle, struct volume_group *vg,
-		  struct logical_volume *lv, struct physical_volume *pv,
-		  struct lv_segment *seg, struct pv_segment *pvseg)
-{
-	struct report_handle *rh = handle;
-	struct field_properties *fp;
-	struct row *row;
-	struct field *field;
-	void *data = NULL;
-	int skip;
-
-	if (lv && pv) {
-		log_error("report_object: One of *lv and *pv must be NULL!");
-		return 0;
-	}
-
-	if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
-		log_error("struct row allocation failed");
-		return 0;
-	}
-
-	row->rh = rh;
-
-	if ((rh->flags & RH_SORT_REQUIRED) &&
-	    !(row->sort_fields = dm_pool_zalloc(rh->mem, sizeof(struct field *) *
-					     rh->keys_count))) {
-		log_error("row sort value structure allocation failed");
-		return 0;
-	}
-
-	list_init(&row->fields);
-	list_add(&rh->rows, &row->list);
-
-	/* For each field to be displayed, call its report_fn */
-	list_iterate_items(fp, &rh->field_props) {
-		skip = 0;
-
-		if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
-			log_error("struct field allocation failed");
-			return 0;
-		}
-		field->props = fp;
-
-		switch (_fields[fp->field_num].type) {
-		case LVS:
-			data = (void *) lv + _fields[fp->field_num].offset;
-			break;
-		case VGS:
-			if (!vg) {
-				skip = 1;
-				break;
-			}
-			data = (void *) vg + _fields[fp->field_num].offset;
-			break;
-		case PVS:
-			data = (void *) pv + _fields[fp->field_num].offset;
-			break;
-		case SEGS:
-			data = (void *) seg + _fields[fp->field_num].offset;
-			break;
-		case PVSEGS:
-			data = (void *) pvseg + _fields[fp->field_num].offset;
-		}
-
-		if (skip) {
-			field->report_string = "";
-			field->sort_value = (const void *) field->report_string;
-		} else if (!_fields[fp->field_num].report_fn(rh, field, data)) {
-			log_error("report function failed for field %s",
-				  _fields[fp->field_num].id);
-			return 0;
-		}
-
-		if ((strlen(field->report_string) > field->props->width))
-			field->props->width = strlen(field->report_string);
-
-		if ((rh->flags & RH_SORT_REQUIRED) &&
-		    (field->props->flags & FLD_SORT_KEY)) {
-			(*row->sort_fields)[field->props->sort_posn] = field;
-		}
-		list_add(&row->fields, &field->list);
-	}
-
-	if (!(rh->flags & RH_BUFFERED))
-		report_output(handle);
-
-	return 1;
-}
-
-/* 
- * Print row of headings 
- */
-static int _report_headings(void *handle)
-{
-	struct report_handle *rh = handle;
-	struct field_properties *fp;
-	const char *heading;
-	char buf[1024];
-
-	if (rh->flags & RH_HEADINGS_PRINTED)
-		return 1;
-
-	rh->flags |= RH_HEADINGS_PRINTED;
-
-	if (!(rh->flags & RH_HEADINGS))
-		return 1;
-
-	if (!dm_pool_begin_object(rh->mem, 128)) {
-		log_error("dm_pool_begin_object failed for headings");
-		return 0;
-	}
-
-	/* First heading line */
-	list_iterate_items(fp, &rh->field_props) {
-		if (fp->flags & FLD_HIDDEN)
-			continue;
-
-		heading = _fields[fp->field_num].heading;
-		if (rh->flags & RH_ALIGNED) {
-			if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
-					 fp->width, fp->width, heading) < 0) {
-				log_error("snprintf heading failed");
-				dm_pool_end_object(rh->mem);
-				return 0;
-			}
-			if (!dm_pool_grow_object(rh->mem, buf, fp->width))
-				goto bad;
-		} else if (!dm_pool_grow_object(rh->mem, heading, strlen(heading)))
-			goto bad;
-
-		if (!list_end(&rh->field_props, &fp->list))
-			if (!dm_pool_grow_object(rh->mem, rh->separator,
-					      strlen(rh->separator)))
-				goto bad;
-	}
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-		log_error("dm_pool_grow_object failed");
-		goto bad;
-	}
-	log_print("%s", (char *) dm_pool_end_object(rh->mem));
-
-	return 1;
-
-      bad:
-	log_error("Failed to generate report headings for printing");
-
-	return 0;
-}
-
-/*
- * Sort rows of data
- */
-static int _row_compare(const void *a, const void *b)
-{
-	const struct row *rowa = *(const struct row **) a;
-	const struct row *rowb = *(const struct row **) b;
-	const struct field *sfa, *sfb;
-	int32_t cnt = -1;
-
-	for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
-		sfa = (*rowa->sort_fields)[cnt];
-		sfb = (*rowb->sort_fields)[cnt];
-		if (sfa->props->flags & FLD_NUMBER) {
-			const uint64_t numa =
-			    *(const uint64_t *) sfa->sort_value;
-			const uint64_t numb =
-			    *(const uint64_t *) sfb->sort_value;
-
-			if (numa == numb)
-				continue;
-
-			if (sfa->props->flags & FLD_ASCENDING) {
-				return (numa > numb) ? 1 : -1;
-			} else {	/* FLD_DESCENDING */
-				return (numa < numb) ? 1 : -1;
-			}
-		} else {	/* FLD_STRING */
-			const char *stra = (const char *) sfa->sort_value;
-			const char *strb = (const char *) sfb->sort_value;
-			int cmp = strcmp(stra, strb);
-
-			if (!cmp)
-				continue;
-
-			if (sfa->props->flags & FLD_ASCENDING) {
-				return (cmp > 0) ? 1 : -1;
-			} else {	/* FLD_DESCENDING */
-				return (cmp < 0) ? 1 : -1;
-			}
-		}
-	}
-
-	return 0;		/* Identical */
-}
-
-static int _sort_rows(struct report_handle *rh)
-{
-	struct row *(*rows)[];
-	uint32_t count = 0;
-	struct row *row;
-
-	if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
-				list_size(&rh->rows)))) {
-		log_error("sort array allocation failed");
-		return 0;
-	}
-
-	list_iterate_items(row, &rh->rows)
-		(*rows)[count++] = row;
-
-	qsort(rows, count, sizeof(**rows), _row_compare);
-
-	list_init(&rh->rows);
-	while (count--)
-		list_add_h(&rh->rows, &(*rows)[count]->list);
-
-	return 1;
-}
-
-/*
- * Produce report output
- */
-int report_output(void *handle)
-{
-	struct report_handle *rh = handle;
-	struct list *fh, *rowh, *ftmp, *rtmp;
-	struct row *row = NULL;
-	struct field *field;
-	const char *repstr;
-	char buf[4096];
-	int width;
-
-	if (list_empty(&rh->rows))
-		return 1;
-
-	/* Sort rows */
-	if ((rh->flags & RH_SORT_REQUIRED))
-		_sort_rows(rh);
-
-	/* If headings not printed yet, calculate field widths and print them */
-	if (!(rh->flags & RH_HEADINGS_PRINTED))
-		_report_headings(rh);
-
-	/* Print and clear buffer */
-	list_iterate_safe(rowh, rtmp, &rh->rows) {
-		if (!dm_pool_begin_object(rh->mem, 512)) {
-			log_error("dm_pool_begin_object failed for row");
-			return 0;
-		}
-		row = list_item(rowh, struct row);
-		list_iterate_safe(fh, ftmp, &row->fields) {
-			field = list_item(fh, struct field);
-			if (field->props->flags & FLD_HIDDEN)
-				continue;
-
-			repstr = field->report_string;
-			width = field->props->width;
-			if (!(rh->flags & RH_ALIGNED)) {
-				if (!dm_pool_grow_object(rh->mem, repstr,
-						      strlen(repstr)))
-					goto bad;
-			} else if (field->props->flags & FLD_ALIGN_LEFT) {
-				if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
-						 width, width, repstr) < 0) {
-					log_error("snprintf repstr failed");
-					dm_pool_end_object(rh->mem);
-					return 0;
-				}
-				if (!dm_pool_grow_object(rh->mem, buf, width))
-					goto bad;
-			} else if (field->props->flags & FLD_ALIGN_RIGHT) {
-				if (dm_snprintf(buf, sizeof(buf), "%*.*s",
-						 width, width, repstr) < 0) {
-					log_error("snprintf repstr failed");
-					dm_pool_end_object(rh->mem);
-					return 0;
-				}
-				if (!dm_pool_grow_object(rh->mem, buf, width))
-					goto bad;
-			}
-
-			if (!list_end(&row->fields, fh))
-				if (!dm_pool_grow_object(rh->mem, rh->separator,
-						      strlen(rh->separator)))
-					goto bad;
-			list_del(&field->list);
-		}
-		if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-			log_error("dm_pool_grow_object failed for row");
-			return 0;
-		}
-		log_print("%s", (char *) dm_pool_end_object(rh->mem));
-		list_del(&row->list);
-	}
-
-	if (row)
-		dm_pool_free(rh->mem, row);
-
-	return 1;
-
-      bad:
-	log_error("Failed to generate row for printing");
-	return 0;
-}
Index: LVM2.02.17/lib/report/report.h
===================================================================
--- LVM2.02.17.orig/lib/report/report.h	2007-01-11 11:27:16.000000000 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _LVM_REPORT_H
-#define _LVM_REPORT_H
-
-#include "metadata.h"
-
-typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
-
-struct field;
-struct report_handle;
-
-typedef int (*field_report_fn) (struct report_handle * dh, struct field * field,
-				const void *data);
-
-void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
-		  report_type_t *report_type, const char *separator,
-		  int aligned, int buffered, int headings);
-void report_free(void *handle);
-int report_object(void *handle, struct volume_group *vg,
-		  struct logical_volume *lv, struct physical_volume *pv,
-		  struct lv_segment *seg, struct pv_segment *pvseg);
-int report_output(void *handle);
-
-#endif
Index: LVM2.02.17/tools/columns.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ LVM2.02.17/tools/columns.h	2007-01-12 14:50:18.000000000 -0500
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.  
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Report type, Containing struct, Field type, Report heading,
+ * Data field with struct to pass to display function, Minimum display width,
+ * Display Fn, Unique format identifier */
+
+/* *INDENT-OFF* */
+FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
+FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
+FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
+FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
+FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
+FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
+FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
+FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
+FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
+FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
+FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
+FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
+FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
+FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
+FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
+FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
+
+FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
+FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
+FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
+FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
+FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
+FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
+FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
+FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
+FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
+FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
+FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
+FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
+
+FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
+FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
+FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
+FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
+FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
+FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
+FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
+FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
+FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
+FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
+FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
+FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
+FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
+FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
+FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
+FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
+FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
+
+FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
+FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
+FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
+FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
+FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
+FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
+
+FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
+FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
+
+/* *INDENT-ON* */
Index: LVM2.02.17/tools/reporter.c
===================================================================
--- LVM2.02.17.orig/tools/reporter.c	2006-09-01 21:18:17.000000000 -0400
+++ LVM2.02.17/tools/reporter.c	2007-01-12 17:31:55.000000000 -0500
@@ -13,19 +13,882 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "libdevmapper.h"
 #include "tools.h"
-#include "report.h"
+
+#include "lib.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "lvm-string.h"
+#include "display.h"
+#include "activate.h"
+#include "segtype.h"
+#include "str_list.h"
+
+typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
+
+struct lvm_report_object {
+	struct volume_group *pv;
+	struct logical_volume *lv;
+	struct physical_volume *vg;
+	struct lv_segment *seg;
+	struct pv_segment *pvseg;
+};
+
+/*
+ * For macro use
+ */
+static union {
+	struct physical_volume _pv;
+	struct logical_volume _lv;
+	struct volume_group _vg;
+	struct lv_segment _seg;
+	struct pv_segment _pvseg;
+} _dummy;
+
+static char _alloc_policy_char(alloc_policy_t alloc)
+{
+	switch (alloc) {
+	case ALLOC_CONTIGUOUS:
+		return 'c';
+	case ALLOC_CLING:
+		return 'C';
+	case ALLOC_NORMAL:
+		return 'n';
+	case ALLOC_ANYWHERE:
+		return 'a';
+	default:
+		return 'i';
+	}
+}
+
+/*
+ * Data-munging functions to prepare each data type for display and sorting
+ */
+static int _string_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	return dm_report_field_string(rh, mem, field, data);
+}
+
+static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data)
+{
+	const char *name = dev_name(*(const struct device **) data);
+
+	return dm_report_field_string(rh, mem, field, &name);
+}
+
+static int _devices_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data)
+{
+	const struct lv_segment *seg = (const struct lv_segment *) data;
+	unsigned int s;
+	const char *name = NULL;
+	uint32_t extent = 0;
+	char extent_str[32];
+
+	if (!dm_pool_begin_object(mem, 256)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	for (s = 0; s < seg->area_count; s++) {
+		switch (seg_type(seg, s)) {
+		case AREA_LV:
+			name = seg_lv(seg, s)->name;
+			extent = seg_le(seg, s);
+			break;
+		case AREA_PV:
+			name = dev_name(seg_dev(seg, s));
+			extent = seg_pe(seg, s);
+			break;
+		case AREA_UNASSIGNED:
+			name = "unassigned";
+			extent = 0;
+		}
+
+		if (!dm_pool_grow_object(mem, name, strlen(name))) {
+			log_error("dm_pool_grow_object failed");
+			return 0;
+		}
+
+		if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
+				 ")", extent) < 0) {
+			log_error("Extent number dm_snprintf failed");
+			return 0;
+		}
+
+		if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
+			log_error("dm_pool_grow_object failed");
+			return 0;
+		}
+
+		if ((s != seg->area_count - 1) &&
+		    !dm_pool_grow_object(mem, ",", 1)) {
+			log_error("dm_pool_grow_object failed");
+			return 0;
+		}
+	}
+
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed");
+		return 0;
+	}
+
+	return dm_report_field_raw(rh, mem, field, dm_pool_end_object(mem));
+}
+
+static int _tags_disp(struct dm_report *rh, struct dm_pool *mem,
+		      struct dm_report_field *field,
+		      const void *data)
+{
+	const struct list *tags = (const struct list *) data;
+	struct str_list *sl;
+
+	if (!dm_pool_begin_object(mem, 256)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	list_iterate_items(sl, tags) {
+		if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
+		    (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
+			log_error("dm_pool_grow_object failed");
+			return 0;
+		}
+	}
+
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed");
+		return 0;
+	}
+
+	return dm_report_field_raw(rh, mem, field, dm_pool_end_object(mem));
+}
+
+static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct list *modules;
+
+	if (!(modules = str_list_create(mem))) {
+		log_error("modules str_list allocation failed");
+		return 0;
+	}
+
+	if (!list_lv_modules(mem, lv, modules))
+		return_0;
+
+	return _tags_disp(rh, mem, field, modules);
+}
+
+static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data)
+{
+	const struct volume_group *vg = (const struct volume_group *) data;
+
+	if (!vg->fid)
+		return dm_report_field_raw(rh, mem, field, "");
+
+	return _string_disp(rh, mem, field, &vg->fid->fmt->name);
+}
+
+static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data)
+{
+	const struct physical_volume *pv =
+	    (const struct physical_volume *) data;
+
+	if (!pv->fmt)
+		return dm_report_field_raw(rh, mem, field, "");
+
+	return _string_disp(rh, mem, field, &pv->fmt->name);
+}
+
+static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lvinfo info;
+	uint64_t minusone = UINT64_C(-1);
+
+	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
+		return dm_report_field_int(rh, mem, field, &info.major);
+
+	return dm_report_field_int(rh, mem, field, &minusone);
+}
+
+static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lvinfo info;
+	uint64_t minusone = UINT64_C(-1);
+
+	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
+		return dm_report_field_int(rh, mem, field, &info.minor);
+
+	return dm_report_field_int(rh, mem, field, &minusone);
+}
+
+static int _lvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lvinfo info;
+	char *repstr;
+	float snap_percent;
+
+	if (!(repstr = dm_pool_zalloc(mem, 7))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (lv->status & PVMOVE)
+		repstr[0] = 'p';
+	else if (lv->status & MIRRORED) {
+		if (lv->status & MIRROR_NOTSYNCED)
+			repstr[0] = 'M';
+		else
+			repstr[0] = 'm';
+	}else if (lv->status & MIRROR_IMAGE)
+		repstr[0] = 'i';
+	else if (lv->status & MIRROR_LOG)
+		repstr[0] = 'l';
+	else if (lv->status & VIRTUAL)
+		repstr[0] = 'v';
+	else if (lv_is_origin(lv))
+		repstr[0] = 'o';
+	else if (lv_is_cow(lv))
+		repstr[0] = 's';
+	else
+		repstr[0] = '-';
+
+	if (lv->status & PVMOVE)
+		repstr[1] = '-';
+	else if (lv->status & LVM_WRITE)
+		repstr[1] = 'w';
+	else
+		repstr[1] = 'r';
+
+	repstr[2] = _alloc_policy_char(lv->alloc);
+
+	if (lv->status & LOCKED)
+		repstr[2] = toupper(repstr[2]);
+
+	if (lv->status & FIXED_MINOR)
+		repstr[3] = 'm';	/* Fixed Minor */
+	else
+		repstr[3] = '-';
+
+	if (lv_info(lv->vg->cmd, lv, &info, 1) && info.exists) {
+		if (info.suspended)
+			repstr[4] = 's';	/* Suspended */
+		else if (info.live_table)
+			repstr[4] = 'a';	/* Active */
+		else if (info.inactive_table)
+			repstr[4] = 'i';	/* Inactive with table */
+		else
+			repstr[4] = 'd';	/* Inactive without table */
+
+		/* Snapshot dropped? */
+		if (info.live_table && lv_is_cow(lv) &&
+		    (!lv_snapshot_percent(lv, &snap_percent) ||
+		     snap_percent < 0 || snap_percent >= 100)) {
+			repstr[0] = toupper(repstr[0]);
+			if (info.suspended)
+				repstr[4] = 'S'; /* Susp Inv snapshot */
+			else
+				repstr[4] = 'I'; /* Invalid snapshot */
+		}
+
+		if (info.open_count)
+			repstr[5] = 'o';	/* Open */
+		else
+			repstr[5] = '-';
+	} else {
+		repstr[4] = '-';
+		repstr[5] = '-';
+	}
+
+	return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _pvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data)
+{
+	const uint32_t status = *(const uint32_t *) data;
+	char *repstr;
+
+	if (!(repstr = dm_pool_zalloc(mem, 4))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (status & ALLOCATABLE_PV)
+		repstr[0] = 'a';
+	else
+		repstr[0] = '-';
+
+	if (status & EXPORTED_VG)
+		repstr[1] = 'x';
+	else
+		repstr[1] = '-';
+
+	return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _vgstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data)
+{
+	const struct volume_group *vg = (const struct volume_group *) data;
+	char *repstr;
+
+	if (!(repstr = dm_pool_zalloc(mem, 7))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (vg->status & LVM_WRITE)
+		repstr[0] = 'w';
+	else
+		repstr[0] = 'r';
+
+	if (vg->status & RESIZEABLE_VG)
+		repstr[1] = 'z';
+	else
+		repstr[1] = '-';
+
+	if (vg->status & EXPORTED_VG)
+		repstr[2] = 'x';
+	else
+		repstr[2] = '-';
+
+	if (vg->status & PARTIAL_VG)
+		repstr[3] = 'p';
+	else
+		repstr[3] = '-';
+
+	repstr[4] = _alloc_policy_char(vg->alloc);
+
+	if (vg->status & CLUSTERED)
+		repstr[5] = 'c';
+	else
+		repstr[5] = '-';
+
+	return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _segtype_disp(struct dm_report *rh __attribute((unused)),
+			 struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data)
+{
+	const struct lv_segment *seg = (const struct lv_segment *) data;
+
+	if (seg->area_count == 1)
+		return dm_report_field_raw(rh, mem, field, "linear");
+
+	return dm_report_field_raw(rh, mem, field,
+				   seg->segtype->ops->name(seg));
+}
+
+static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+
+	if (lv_is_cow(lv))
+		return dm_report_field_string(rh, mem, field,
+					      &origin_from_cow(lv)->name);
+
+	return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lv_segment *seg;
+
+	list_iterate_items(seg, &lv->segments) {
+		if (!seg_is_mirrored(seg) || !seg->log_lv)
+			continue;
+		return dm_report_field_string(rh, mem, field,
+					      &seg->log_lv->name);
+	}
+
+	return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	char *repstr, *lvname;
+	size_t len;
+
+	if (lv_is_visible(lv)) {
+		repstr = lv->name;
+		return dm_report_field_string(rh, mem, field, &repstr);
+	}
+
+	len = strlen(lv->name) + 3;
+	if (!(repstr = dm_pool_zalloc(mem, len))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
+		log_error("lvname snprintf failed");
+		return 0;
+	}
+
+	dm_report_field_set_string(field, repstr);
+
+	if (!(lvname = dm_pool_strdup(mem, lv->name))) {
+		log_error("dm_pool_strdup failed");
+		return 0;
+	}
+	dm_report_field_set_sort_value(field, lvname);
+
+	return 1;
+}
+
+static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	const char *name;
+	struct lv_segment *seg;
+
+	list_iterate_items(seg, &lv->segments) {
+		if (!(seg->status & PVMOVE))
+			continue;
+		name = dev_name(seg_dev(seg, 0));
+		return dm_report_field_string(rh, mem, field, &name);
+	}
+
+	return dm_report_field_raw(rh, mem, field, "");
+}
+
+static int _size32_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const uint32_t size = *(const uint32_t *) data;
+	const char *disp, *repstr;
+	uint64_t *sortval;
+
+	if (!*(disp = display_size_units(dm_report_get_private(rh),
+					 (uint64_t) size))) {
+		stack;
+		return 0;
+	}
+
+	if (!(repstr = dm_pool_strdup(mem, disp))) {
+		log_error("dm_pool_strdup failed");
+		return 0;
+	}
+
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	*sortval = (const uint64_t) size;
+
+	dm_report_field_set_string(field, repstr);
+	dm_report_field_set_sort_value(field, sortval);
+
+	return 1;
+}
+
+static int _size64_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const uint64_t size = *(const uint64_t *) data;
+	const char *disp, *repstr;
+	uint64_t *sortval;
+
+	if (!*(disp = display_size_units(dm_report_get_private(rh), size))) {
+		stack;
+		return 0;
+	}
+
+	if (!(repstr = dm_pool_strdup(mem, disp))) {
+		log_error("dm_pool_strdup failed");
+		return 0;
+	}
+
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	*sortval = size;
+	dm_report_field_set_string(field, repstr);
+	dm_report_field_set_sort_value(field, sortval);
+
+	return 1;
+}
+
+static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct volume_group *vg = (const struct volume_group *) data;
+	uint64_t size;
+
+	size = (uint64_t) vg->extent_count * vg->extent_size;
+
+	return _size64_disp(rh, mem, field, &size);
+}
+
+static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data)
+{
+	const struct lv_segment *seg = (const struct lv_segment *) data;
+	uint64_t start;
+
+	start = (uint64_t) seg->le * seg->lv->vg->extent_size;
+
+	return _size64_disp(rh, mem, field, &start);
+}
+
+static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data)
+{
+	const struct lv_segment *seg = (const struct lv_segment *) data;
+	uint64_t size;
+
+	size = (uint64_t) seg->len * seg->lv->vg->extent_size;
+
+	return _size64_disp(rh, mem, field, &size);
+}
+
+static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field,
+			   const void *data)
+{
+	const struct lv_segment *seg = (const struct lv_segment *) data;
+	uint64_t size;
+
+	if (lv_is_cow(seg->lv))
+		size = (uint64_t) find_cow(seg->lv)->chunk_size;
+	else
+		size = 0;
+
+	return _size64_disp(rh, mem, field, &size);
+}
+
+static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct physical_volume *pv =
+	    (const struct physical_volume *) data;
+	uint64_t used;
+
+	if (!pv->pe_count)
+		used = 0LL;
+	else
+		used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
+
+	return _size64_disp(rh, mem, field, &used);
+}
+
+static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct physical_volume *pv =
+	    (const struct physical_volume *) data;
+	uint64_t freespace;
+
+	if (!pv->pe_count)
+		freespace = pv->size;
+	else
+		freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
+
+	return _size64_disp(rh, mem, field, &freespace);
+}
+
+static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct physical_volume *pv =
+	    (const struct physical_volume *) data;
+	uint64_t size;
+
+	if (!pv->pe_count)
+		size = pv->size;
+	else
+		size = (uint64_t) pv->pe_count * pv->pe_size;
+
+	return _size64_disp(rh, mem, field, &size);
+}
+
+static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data)
+{
+	const struct device *dev = *(const struct device **) data;
+	uint64_t size;
+
+	if (!dev_get_size(dev, &size))
+		size = 0;
+
+	return _size64_disp(rh, mem, field, &size);
+}
+
+static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	const struct volume_group *vg = (const struct volume_group *) data;
+	uint64_t freespace;
+
+	freespace = (uint64_t) vg->free_count * vg->extent_size;
+
+	return _size64_disp(rh, mem, field, &freespace);
+}
+
+static int _uuid_disp(struct dm_report *rh, struct dm_pool *mem,
+		      struct dm_report_field *field,
+		      const void *data)
+{
+	char *repstr = NULL;
+
+	if (!(repstr = dm_pool_alloc(mem, 40))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (!id_write_format((const struct id *) data, repstr, 40)) {
+		stack;
+		return 0;
+	}
+
+	return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data)
+{
+	return dm_report_field_uint32(rh, mem, field, data);
+}
+
+static int _int32_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data)
+{
+	return dm_report_field_int32(rh, mem, field, data);
+}
+
+static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
+			    struct dm_report_field *field,
+			    const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	uint32_t count;
+
+	count = list_size(&lv->segments);
+
+	return _uint32_disp(rh, mem, field, &count);
+}
+
+static int _snpercent_disp(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field,
+			   const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lvinfo info;
+	float snap_percent;
+	uint64_t *sortval;
+	char *repstr;
+
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (!lv_is_cow(lv) ||
+	    (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
+		dm_report_field_set_string(field, "");
+		*sortval = UINT64_C(0);
+		dm_report_field_set_sort_value(field, sortval);
+		return 1;
+	}
+
+	if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
+		dm_report_field_set_string(field, "100.00");
+		*sortval = UINT64_C(100);
+		dm_report_field_set_sort_value(field, sortval);
+		return 1;
+	}
+
+	if (!(repstr = dm_pool_zalloc(mem, 8))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
+		log_error("snapshot percentage too large");
+		return 0;
+	}
+
+	*sortval = snap_percent * UINT64_C(1000);
+	dm_report_field_set_sort_value(field, sortval);
+	dm_report_field_set_string(field, repstr);
+
+	return 1;
+}
+
+static int _copypercent_disp(struct dm_report *rh, struct dm_pool *mem,
+			     struct dm_report_field *field,
+			     const void *data)
+{
+	struct logical_volume *lv = (struct logical_volume *) data;
+	float percent;
+	uint64_t *sortval;
+	char *repstr;
+
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
+	    !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) {
+		dm_report_field_set_string(field, "");
+		*sortval = UINT64_C(0);
+		dm_report_field_set_sort_value(field, sortval);
+		return 1;
+	}
+
+	percent = copy_percent(lv);
+
+	if (!(repstr = dm_pool_zalloc(mem, 8))) {
+		log_error("dm_pool_alloc failed");
+		return 0;
+	}
+
+	if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
+		log_error("copy percentage too large");
+		return 0;
+	}
+
+	*sortval = percent * UINT64_C(1000);
+	dm_report_field_set_sort_value(field, sortval);
+	dm_report_field_set_string(field, repstr);
+
+	return 1;
+}
+
+/* Report object types */
+
+/* necessary for displaying something for PVs not belonging to VG */
+static struct volume_group _dummy_vg = {
+	.name = "",
+};
+
+static void *_obj_get_vg(void *obj)
+{
+	struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
+
+	return vg ? vg : &_dummy_vg;
+}
+
+static void *_obj_get_lv(void *obj)
+{
+	return ((struct lvm_report_object *)obj)->lv;
+}
+
+static void *_obj_get_pv(void *obj)
+{
+	return ((struct lvm_report_object *)obj)->pv;
+}
+
+static void *_obj_get_seg(void *obj)
+{
+	return ((struct lvm_report_object *)obj)->seg;
+}
+
+static void *_obj_get_pvseg(void *obj)
+{
+	return ((struct lvm_report_object *)obj)->pvseg;
+}
+
+static const struct dm_report_object_type _report_types[] = {
+        { VGS, "Volume Group", "vg_", _obj_get_vg },
+        { LVS, "Logical Volume", "lv_", _obj_get_lv },
+        { PVS, "Physical Volume", "pv_", _obj_get_pv },
+        { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
+        { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
+};
+const unsigned int _num_report_types = sizeof(_report_types) / sizeof(_report_types[0]);
+
+/*
+ * Import column definitions
+ */
+
+#define STR (DM_REPORT_FIELD_STRING | DM_REPORT_FIELD_ALIGN_LEFT)
+#define NUM (DM_REPORT_FIELD_NUMBER | DM_REPORT_FIELD_ALIGN_RIGHT)
+#define FIELD(type, strct, sorttype, head, field, width, func, id) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp},
+
+static struct dm_report_field_type _fields[] = {
+#include "columns.h"
+};
+
+#undef STR
+#undef NUM
+#undef FIELD
+
+const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
+
+#define PACKOBJ(o, v, l, p, s, ps) \
+	o.vg = v; \
+	o.lv = l; \
+	o.pv = p; \
+	o.seg = s; \
+	o.pvseg = ps;
 
 static int _vgs_single(struct cmd_context *cmd __attribute((unused)),
 		       const char *vg_name, struct volume_group *vg,
 		       int consistent __attribute((unused)), void *handle)
 {
+	struct lvm_report_object obj;
+
 	if (!vg) {
 		log_error("Volume group %s not found", vg_name);
 		return ECMD_FAILED;
 	}
 
-	if (!report_object(handle, vg, NULL, NULL, NULL, NULL))
+	PACKOBJ(obj, vg, NULL, NULL, NULL, NULL);
+	if (!dm_report_object(handle, &obj))
 		return ECMD_FAILED;
 
 	check_current_backup(vg);
@@ -36,10 +899,13 @@ static int _vgs_single(struct cmd_contex
 static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
 		       void *handle)
 {
+	struct lvm_report_object obj;
+
 	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
 		return ECMD_PROCESSED;
 
-	if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
+	PACKOBJ(obj, lv->vg, lv, NULL, NULL, NULL);
+	if (!dm_report_object(handle, &obj))
 		return ECMD_FAILED;
 
 	return ECMD_PROCESSED;
@@ -48,7 +914,10 @@ static int _lvs_single(struct cmd_contex
 static int _segs_single(struct cmd_context *cmd __attribute((unused)),
 			struct lv_segment *seg, void *handle)
 {
-	if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL))
+	struct lvm_report_object obj;
+
+	PACKOBJ(obj, seg->lv->vg, seg->lv, NULL, seg, NULL);
+	if (!dm_report_object(handle, &obj))
 		return ECMD_FAILED;
 
 	return ECMD_PROCESSED;
@@ -60,6 +929,7 @@ static int _pvsegs_sub_single(struct cmd
 	int consistent = 0;
 	struct physical_volume *pv = pvseg->pv;
 	int ret = ECMD_PROCESSED;
+	struct lvm_report_object obj;
 
 	if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
 		log_error("Can't lock %s: skipping", pv->vg_name);
@@ -78,7 +948,8 @@ static int _pvsegs_sub_single(struct cmd
 		goto out;
 	}
 
-	if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
+	PACKOBJ(obj, vg, NULL, pv, NULL, pvseg);
+	if (!dm_report_object(handle, &obj))
 		ret = ECMD_FAILED;
 
 out:
@@ -107,6 +978,7 @@ static int _pvs_single(struct cmd_contex
 {
 	int consistent = 0;
 	int ret = ECMD_PROCESSED;
+	struct lvm_report_object obj;
 
 	if (pv->vg_name) {
 		if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
@@ -128,7 +1000,8 @@ static int _pvs_single(struct cmd_contex
 		}
 	}
 
-	if (!report_object(handle, vg, NULL, pv, NULL, NULL))
+	PACKOBJ(obj, vg, NULL, pv, NULL, NULL);
+	if (!dm_report_object(handle, &obj))
 		ret = ECMD_FAILED;
 
 out:
@@ -257,10 +1130,32 @@ static int _report(struct cmd_context *c
 	if (arg_count(cmd, noheadings_ARG))
 		headings = 0;
 
-	if (!(report_handle = report_init(cmd, options, keys, &report_type,
+	if (!(report_handle = dm_report_init(options, keys, &report_type,
 					  separator, aligned, buffered,
-					  headings)))
+					  headings, _fields, _num_fields,
+					  _report_types, _num_report_types,
+					  cmd)))
+		return 0;
+
+	/* Ensure options selected are compatible */
+	if (report_type & SEGS)
+		report_type |= LVS;
+	if (report_type & PVSEGS)
+		report_type |= PVS;
+	if ((report_type & LVS) && (report_type & PVS)) {
+		log_error("Can't report LV and PV fields at the same time");
 		return 0;
+	}
+
+	/* Change report type if fields specified makes this necessary */
+	if (report_type & SEGS)
+		report_type = SEGS;
+	else if (report_type & LVS)
+		report_type = LVS;
+	else if (report_type & PVSEGS)
+		report_type = PVSEGS;
+	else if (report_type & PVS)
+		report_type = PVS;
 
 	switch (report_type) {
 	case LVS:
@@ -285,9 +1180,9 @@ static int _report(struct cmd_context *c
 		break;
 	}
 
-	report_output(report_handle);
+	dm_report_output(report_handle);
 
-	report_free(report_handle);
+	dm_report_free(report_handle);
 	return r;
 }
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]