* [PATCH] (2/4) dmsetup info to use dm_report
2007-01-12 23:13 ` Jun'ichi Nomura
@ 2007-01-12 23:31 ` Jun'ichi Nomura
-1 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:31 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 1504 bytes --]
Hi,
This patch makes "dmsetup info -c" to use dm_report
in libdevmapper.
For example, to see what maps are overlaying on each map,
# dmsetup info -c -o name,parents_count,parent_maps -O name
Name Parents Parent Maps
B8-root 0
B9-root 0
d1 2 testvg-m1_mimage_0,testvg-lvol2
d2 2 testvg-m1_mimage_1,testvg-lvol2
d3 1 testvg-lvol0-real
d4 2 testvg-lvol2,testvg-lvol0-real
d5 1 testvg-lvol1-cow
d6 1 testvg-lvol2
d7 1 testvg-m1_mlog
testvg-lvol0 0
testvg-lvol0-real 2 testvg-lvol1,testvg-lvol0
testvg-lvol1 0
testvg-lvol1-cow 1 testvg-lvol1
testvg-lvol2 0
testvg-m1 0
testvg-m1_mimage_0 1 testvg-m1
testvg-m1_mimage_1 1 testvg-m1
testvg-m1_mlog 1 testvg-m1
Then, to see the top level map names,
# dmsetup info -c -o name,-parents_count=0 --noheadings
B9-root
testvg-m1
testvg-lvol2
testvg-lvol1
testvg-lvol0
B8-root
Output of "dmsetup info -c" is basically same as the former version
except for a few spacing difference, which should be harmless.
- Field width is correctly aligned (e.g. in case of long map name)
- Trailing space is added to fill the width
(same behaviour as LVM2 lvs/pvs/vgs)
Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
[-- Attachment #2: 02-dmsetup-report.patch --]
[-- Type: text/x-patch, Size: 17162 bytes --]
Extend "dmsetup info -c -o" using dm_report API.
New options "-O" and "--seprator" are also added.
Usage:
dmsetup info -c -o <field1>[,<field2>...] \
[-O <field>[,<field>...]
[--separator <string>]
Combination of the following field name is allowed:
name
device
major
minor
uuid
status
open_count
target_count
event_nr
deps
deps_count
parents
parents_count
parent_maps
Examples:
If you have the following dm tree:
# dmsetup ls --tree -o inverted
(7:0)
|-d4 (254:6)
| |-testvg-lvol2 (254:17)
| `-testvg-lvol0-real (254:15)
| |-testvg-lvol1 (254:14)
| `-testvg-lvol0 (254:13)
|-d1 (254:3)
| |-testvg-m1_mimage_0 (254:10)
| | `-testvg-m1 (254:12)
| `-testvg-lvol2 (254:17)
|-d3 (254:5)
| `-testvg-lvol0-real (254:15)
| |-testvg-lvol1 (254:14)
| `-testvg-lvol0 (254:13)
|-d2 (254:4)
| |-testvg-m1_mimage_1 (254:11)
| | `-testvg-m1 (254:12)
| `-testvg-lvol2 (254:17)
|-d7 (254:9)
| `-testvg-m1_mlog (254:0)
| `-testvg-m1 (254:12)
|-d6 (254:8)
| `-testvg-lvol2 (254:17)
`-d5 (254:7)
`-testvg-lvol1-cow (254:16)
`-testvg-lvol1 (254:14)
(8:48)
`-asr_HOSTRAID1 (254:18)
|-asr_HOSTRAID15 (254:22)
|-asr_HOSTRAID13 (254:21)
|-asr_HOSTRAID12 (254:20)
`-asr_HOSTRAID11 (254:19)
(8:32)
`-asr_HOSTRAID1 (254:18)
|-asr_HOSTRAID15 (254:22)
|-asr_HOSTRAID13 (254:21)
|-asr_HOSTRAID12 (254:20)
`-asr_HOSTRAID11 (254:19)
To obtain the sorted list of the maps which have no parent maps:
# dmsetup info -c -o 'name,-parents_count=0' --noheadings -O name
asr_HOSTRAID11
asr_HOSTRAID12
asr_HOSTRAID13
asr_HOSTRAID15
testvg-lvol0
testvg-lvol1
testvg-lvol2
testvg-m1
Output of "dmsetup info -c" is basically same as the former version
except for a few spacing difference, which should be harmless.
- Field width is correctly aligned (e.g. in case of long map name)
- Trailing space is added to fill the width
(same behaviour as LVM2 lvs/pvs/vgs)
Index: device-mapper/dmsetup/dmsetup.c
===================================================================
--- device-mapper.orig/dmsetup/dmsetup.c 2007-01-12 16:50:37.000000000 -0500
+++ device-mapper/dmsetup/dmsetup.c 2007-01-12 17:03:45.000000000 -0500
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2005 NEC Corperation
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2007 NEC Corperation
*
* This file is part of the device-mapper userspace tools.
*
@@ -114,7 +114,9 @@ enum {
NOOPENCOUNT_ARG,
NOTABLE_ARG,
OPTIONS_ARG,
+ SEPARATOR_ARG,
SHOWKEYS_ARG,
+ SORTKEYS_ARG,
TABLE_ARG,
TARGET_ARG,
TREE_ARG,
@@ -129,11 +131,12 @@ static int _switches[NUM_SWITCHES];
static int _values[NUM_SWITCHES];
static int _num_devices;
static char *_uuid;
-static char *_fields;
+static char *_fields[NUM_SWITCHES];
static char *_table;
static char *_target;
static char *_command;
static struct dm_tree *_dtree;
+static struct dm_report *_rhandle;
/*
* Commands
@@ -322,6 +325,8 @@ static void _display_info_long(struct dm
printf("\n");
}
+static int _report(int argc, char **argv, void *data);
+
static int _display_info(struct dm_task *dmt)
{
struct dm_info info;
@@ -1056,6 +1061,12 @@ static int _info(int argc, char **argv,
struct dm_names *names = (struct dm_names *) data;
char *name = NULL;
+ /*
+ * Using reporter function
+ */
+ if (_switches[COLS_ARG])
+ return _report(argc, argv, data);
+
if (data)
name = names->name;
else {
@@ -1506,6 +1517,414 @@ static int _ls(int argc, char **argv, vo
return _process_all(argc, argv, 0, _display_name);
}
+
+/*
+ * Report device information
+ */
+
+/* dm specific display functions */
+
+static int _dm_name_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ const char *name = dm_task_get_name((struct dm_task *) data);
+
+ return dm_report_field_string(rh, mem, field, &name);
+}
+
+static int _dm_uuid_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ const char *uuid = dm_task_get_uuid((struct dm_task *) data);
+
+ if (!uuid || !*uuid)
+ uuid = "";
+
+ return dm_report_field_string(rh, mem, field, &uuid);
+}
+
+static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ char buf[5], *s = buf;
+ struct dm_info *info = (struct dm_info *) data;
+
+ buf[0] = info->live_table ? 'L' : '-';
+ buf[1] = info->inactive_table ? 'I' : '-';
+ buf[2] = info->suspended ? 's' : '-';
+ buf[3] = info->read_only ? 'r' : 'w';
+ buf[4] = 0;
+
+ return dm_report_field_string(rh, mem, field, &s);
+}
+
+#define MAJ_MIN_LEN 32
+
+static int _dm_info_device_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ char *repstr;
+ struct dm_info *info = (struct dm_info *) data;
+
+ if (!(repstr = dm_pool_zalloc(mem, MAJ_MIN_LEN))) {
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ if (dm_snprintf(repstr, MAJ_MIN_LEN, "%d:%d",
+ info->major, info->minor) < 0) {
+ dm_pool_free(mem, repstr);
+ log_error("dm_pool_alloc failed");
+ return 0;
+ }
+
+ return dm_report_field_raw(rh, mem, field, repstr);
+}
+
+static int _dm_tree_parent_maps_disp(struct dm_report *rh,
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+ void *t = NULL;
+ const char *name;
+ int first_node = 1;
+ char *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ while ((parent = dm_tree_next_child(&t, node, 1))) {
+ name = dm_tree_node_get_name(parent);
+ if (!name || !*name)
+ continue;
+ if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, name, strlen(name))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (first_node)
+ first_node = 0;
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ return 1;
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _dm_tree_parents_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+ void *t = NULL;
+ const struct dm_info *info;
+ int first_node = 1;
+ char buf[MAJ_MIN_LEN], *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ while ((parent = dm_tree_next_child(&t, node, 1))) {
+ info = dm_tree_node_get_info(parent);
+ if (!info->major && !info->minor)
+ continue;
+ if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (dm_snprintf(buf, MAJ_MIN_LEN, "%d:%d",
+ info->major, info->minor) < 0) {
+ log_error("dm_snprintf failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (first_node)
+ first_node = 0;
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+static int _dm_tree_parents_count_disp(struct dm_report *rh,
+ struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data)
+{
+ struct dm_tree_node *node = (struct dm_tree_node *) data;
+ int num_parent = dm_tree_node_num_children(node, 1);
+
+ return dm_report_field_int(rh, mem, field, &num_parent);
+}
+
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data)
+{
+ struct dm_deps *deps = (struct dm_deps *) data;
+ int i;
+ char buf[MAJ_MIN_LEN], *repstr;
+
+ if (!dm_pool_begin_object(mem, 256)) {
+ log_error("dm_pool_begin_object failed");
+ return 0;
+ }
+
+ for (i = 0; i < deps->count; i++) {
+ if (dm_snprintf(buf, sizeof(buf) - 1, "%d:%d",
+ (int) MAJOR(deps->device[i]),
+ (int) MINOR(deps->device[i])) < 0) {
+ log_error("dm_snprintf failed");
+ goto out_abandon;
+ }
+ if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+ }
+
+ if (!dm_pool_grow_object(mem, "\0", 1)) {
+ log_error("dm_pool_grow_object failed");
+ goto out_abandon;
+ }
+
+ repstr = dm_pool_end_object(mem);
+ return dm_report_field_raw(rh, mem, field, repstr);
+
+ out_abandon:
+ dm_pool_abandon_object(mem);
+ return 0;
+}
+
+/* Report object types */
+
+#define DESC1 "Device Mapper Device"
+#define DESC2 "Dependency"
+#define PREFIX "dm_"
+enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8 };
+
+struct dmsetup_report_obj {
+ struct dm_task *task;
+ struct dm_info *info;
+ struct dm_tree_node *tree;
+};
+
+static void *_task_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->task;
+}
+
+static void *_info_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->info;
+}
+
+static void *_tree_get_obj(void *obj)
+{
+ return ((struct dmsetup_report_obj *)obj)->tree;
+}
+
+static void *_deps_get_obj(void *obj)
+{
+ struct dm_task *dmt;
+
+ if (!(dmt = _task_get_obj((struct dmsetup_report_obj *)obj)))
+ return NULL;
+
+ return dm_task_get_deps(dmt);
+}
+
+static const struct dm_report_object_type _report_types[] = {
+ { DR_TASK, DESC1, PREFIX, _task_get_obj },
+ { DR_INFO, DESC1, PREFIX, _info_get_obj },
+ { DR_DEPS, DESC2, PREFIX, _deps_get_obj },
+ { DR_TREE, DESC2, PREFIX, _tree_get_obj },
+};
+
+/* Column definitions */
+static union {
+ struct dm_info _dm_info;
+ struct dm_deps _dm_deps;
+} _dummy;
+
+#define OFFSET_OF(struct, field) ((unsigned int) ((void *)&_dummy._ ## struct.field - (void *)&_dummy._ ## struct))
+#define STR (DM_REPORT_FIELD_STRING | DM_REPORT_FIELD_ALIGN_LEFT)
+#define NUM (DM_REPORT_FIELD_NUMBER | DM_REPORT_FIELD_ALIGN_RIGHT)
+#define FIELD_O(type, strct, sorttype, head, field, width, func, id) {DR_ ## type, id, OFFSET_OF(strct, field), head, width, sorttype, &dm_report_field_ ## func},
+#define FIELD_F(type, sorttype, head, width, func, id) {DR_ ## type, id, 0, head, width, sorttype, &_ ## func ## _disp},
+
+static const struct dm_report_field_type _report_fields[] = {
+/* *INDENT-OFF* */
+FIELD_F(TASK, STR, "Name", 16, dm_name, "name")
+FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid")
+FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "status")
+FIELD_F(INFO, STR, "Device", 6, dm_info_device, "device")
+FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major")
+FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor")
+FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open_count")
+FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "target_count")
+FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "event_nr")
+FIELD_O(DEPS, dm_deps, NUM, "Deps", count, 4, int32, "deps_count")
+FIELD_F(DEPS, STR, "Depend on", 10, dm_deps, "deps")
+FIELD_F(TREE, STR, "Parent Devices", 16, dm_tree_parents, "parents")
+FIELD_F(TREE, STR, "Parent Maps", 12, dm_tree_parent_maps, "parent_maps")
+FIELD_F(TREE, NUM, "Parents", 7, dm_tree_parents_count, "parents_count")
+/* *INDENT-ON* */
+};
+
+#undef STR
+#undef NUM
+#undef FIELD_O
+#undef FIELD_F
+
+static const char *default_report_options = "name,major,minor,status,open_count,target_count,event_nr,uuid";
+static unsigned int _num_report_fields = sizeof(_report_fields) / sizeof(_report_fields[0]);
+static unsigned int _num_report_types = sizeof(_report_types) / sizeof(_report_types[0]);
+
+static int _do_report(int argc, char **argv, void *data)
+{
+ const char *name = NULL;
+ struct dm_task *dmt;
+ struct dm_info info;
+ int r = 0;
+ struct dmsetup_report_obj obj;
+
+ if (data) {
+ if (argc == 0)
+ name = dm_task_get_name((struct dm_task *)data);
+ else
+ name = ((struct dm_names *)data)->name;
+ } else {
+ if (argc == 1)
+ return _process_all(argc, argv, 0, _report);
+ if (argc == 2)
+ name = argv[1];
+ }
+
+ if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+ return 0;
+
+ if (!_set_task_device(dmt, name, 0))
+ goto out;
+
+ if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, &info))
+ goto out;
+
+ obj.task = dmt;
+ obj.info = &info;
+ obj.tree = dm_tree_find_node(_dtree, info.major, info.minor);
+ dm_report_object(_rhandle, &obj);
+
+ r = 1;
+
+ out:
+ dm_task_destroy(dmt);
+ return r;
+}
+
+static int _report(int argc, char **argv, void *data)
+{
+ char *options = (char *) default_report_options;
+ const char *keys = "";
+ const char *separator = " ";
+ int aligned = 1, buffered = 1;
+ int headings = !_switches[NOHEADINGS_ARG];
+ uint32_t report_type = 0;
+
+ if (_rhandle)
+ return _do_report(argc, argv, data);
+
+ if (!(_dtree = dm_tree_create()))
+ return 0;
+ if (!_process_all(argc, argv, 0, _add_dep))
+ return 0;
+
+ if (_switches[OPTIONS_ARG] && _fields[OPTIONS_ARG]) {
+ if (*_fields[OPTIONS_ARG] == '+') {
+ int len = strlen(default_report_options) +
+ strlen(_fields[OPTIONS_ARG]);
+ if (!(options = dm_malloc(len))) {
+ err("Failed to malloc option string.");
+ return 0;
+ }
+ if (dm_snprintf(options, len, "%s,%s",
+ default_report_options,
+ &_fields[OPTIONS_ARG][1]) < 0) {
+ err("snprintf failed");
+ return 0;
+ }
+ } else
+ options = _fields[OPTIONS_ARG];
+ }
+ if (_switches[SORTKEYS_ARG] && _fields[SORTKEYS_ARG])
+ keys = _fields[SORTKEYS_ARG];
+ if (_switches[SEPARATOR_ARG] && _fields[SEPARATOR_ARG]) {
+ separator = _fields[SEPARATOR_ARG];
+ aligned = 0;
+ }
+
+ if (!(_rhandle = dm_report_init(options, keys, &report_type,
+ separator, aligned, buffered, headings,
+ _report_fields, _num_report_fields,
+ _report_types, _num_report_types,
+ NULL)))
+ return 0;
+
+ _do_report(argc, argv, data);
+
+ dm_report_output(_rhandle);
+ dm_report_free(_rhandle);
+ _rhandle = NULL;
+
+ if (_dtree) {
+ dm_tree_free(_dtree);
+ _dtree = NULL;
+ }
+
+ return 1;
+}
+
/*
* dispatch table
*/
@@ -1884,7 +2303,9 @@ static int _process_switches(int *argc,
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
{"notable", 0, &ind, NOTABLE_ARG},
{"options", 1, &ind, OPTIONS_ARG},
+ {"separator", 1, &ind, SEPARATOR_ARG},
{"showkeys", 0, &ind, SHOWKEYS_ARG},
+ {"sortkeys", 1, &ind, SORTKEYS_ARG},
{"table", 1, &ind, TABLE_ARG},
{"target", 1, &ind, TARGET_ARG},
{"tree", 0, &ind, TREE_ARG},
@@ -1914,7 +2335,7 @@ static int _process_switches(int *argc,
_switches[OPTIONS_ARG]++;
_switches[MAJOR_ARG]++;
_switches[MINOR_ARG]++;
- _fields = (char *) "name";
+ _fields[OPTIONS_ARG] = (char *) "name";
if (*argc == 3) {
_values[MAJOR_ARG] = atoi((*argv)[1]);
@@ -1946,7 +2367,7 @@ static int _process_switches(int *argc,
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:ru:Uv",
+ while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:O:ru:Uv",
long_options, NULL)) != -1) {
if (c == ':' || c == '?')
return 0;
@@ -1968,7 +2389,15 @@ static int _process_switches(int *argc,
_switches[NOTABLE_ARG]++;
if (c == 'o' || ind == OPTIONS_ARG) {
_switches[OPTIONS_ARG]++;
- _fields = optarg;
+ _fields[OPTIONS_ARG] = optarg;
+ }
+ if (ind == SEPARATOR_ARG) {
+ _switches[SEPARATOR_ARG]++;
+ _fields[SEPARATOR_ARG] = optarg;
+ }
+ if (c == 'O' || ind == SORTKEYS_ARG) {
+ _switches[SORTKEYS_ARG]++;
+ _fields[SORTKEYS_ARG] = optarg;
}
if (c == 'v' || ind == VERBOSE_ARG)
_switches[VERBOSE_ARG]++;
@@ -2027,13 +2456,7 @@ static int _process_switches(int *argc,
return 0;
}
- if (_switches[COLS_ARG] && _switches[OPTIONS_ARG] &&
- strcmp(_fields, "name")) {
- fprintf(stderr, "Only -o name is supported so far.\n");
- return 0;
- }
-
- if (_switches[TREE_ARG] && !_process_tree_options(_fields))
+ if (_switches[TREE_ARG] && !_process_tree_options(_fields[OPTIONS_ARG]))
return 0;
if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH] (4/4) LVM2 to use dm_report
2007-01-12 23:13 ` Jun'ichi Nomura
@ 2007-01-12 23:32 ` Jun'ichi Nomura
-1 siblings, 0 replies; 8+ messages in thread
From: Jun'ichi Nomura @ 2007-01-12 23:32 UTC (permalink / raw)
To: device-mapper development, LVM2 development
[-- Attachment #1: Type: text/plain, Size: 725 bytes --]
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
[-- Attachment #2: 04-lvm2-use-dm-report.patch --]
[-- Type: text/x-patch, Size: 74176 bytes --]
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;
}
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread