Skip to contentSkip to conversation

(1/4) dm_report support in libdevmapper

PATCH New Jun'ichi Nomura 1 participant 4 messages Jan 12, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 (1/4) dm_report support in libdevmapper

Hi,

Attached patch adds dm_report API to libdevmapper. The code is based on LVM2 lib/report with a enhancement to option format (e.g. "name=a" to report objects whose "name" field is "a") and generalizations.

I would like to use this from dmsetup to make "dmsetup info -c" more flexible like LVM2 lvs/pvs/vgs commands.

Also, LVM2 can use this API instead of its own lib/report.

(Patches for dmsetup and LVM2 will follow.)

Comments are welcome.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

New dm_report API.
The code is based on LVM2 reporter function and act much like lvs/pvs/vgs commands.

Main APIs are:
- dm_report_init
Register definition of reported object types and fields
and set options.
Returns a handle for following calls.
- dm_report_object
Generate report for one object.
The result will be sorted and bufferred until dm_report_output is called if requested.
- dm_report_output
Output bufferred report.
- dm_report_free
Abandon the report handle.

There are some other functions for types and fields definition.

Details can be found in the patch.

And each field name passed by format parameter of dm_report_init can be followed by the following comparison operator and the value or string:

    =   : equal to the value or string
    !=  : not equal to the value or string
    >=  : greater than or equal to the value
    <=  : lesser than or equal to the value
    <   : lesser than the value
    >   : greater than the value
    =~  : contains the string
    !~  : not contain the string

=~^ : contains the string as prefix
!~^ : not contain the string as prefix

If the field name is prefixed by "-" in "-o" option string, the field is used only to check the condition and not displayed.

lib/libdevmapper.h +66 -1
Index: device-mapper/lib/libdevmapper.h
===================================================================
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2007 NEC Corporation
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -623,4 +624,68 @@ int dm_snprintf(char *buf, size_t bufsiz
  */
 char *dm_basename(const char *path);
 
+/*********************
+ * report function
+ *********************/
+
+struct dm_report_field;
+struct dm_report;
+
+/* Definition of reported object */
+struct dm_report_object_type {
+	uint32_t id;		/* must be a power of 2 */
+	const char *desc;	/* description of the object type */
+	const char *prefix;	/* default prefix of id string (if any) */
+	void * (*get) (void *object); /* callback from report_object() */
+};
+
+/* Definition of field */
+#define DM_REPORT_FIELD_ALIGN_LEFT	0x00000001
+#define DM_REPORT_FIELD_ALIGN_RIGHT	0x00000002
+#define DM_REPORT_FIELD_STRING	0x00000004
+#define DM_REPORT_FIELD_NUMBER	0x00000008
+struct dm_report_field_type {
+	uint32_t type;		/* object type id */
+	const char id[32];	/* string used to specify the field */
+	unsigned int offset;	/* byte offset in the object */
+	const char heading[32];	/* string printed in header */
+	int width;		/* default width */
+	uint32_t flags;		/* string or number, alignment */
+	int (*report_fn) (struct dm_report * rh, struct dm_pool * mem,
+			  struct dm_report_field * field, const void *data);
+};
+
+/*
+ * Report API
+ */
+struct dm_report *dm_report_init(const char *format, const char *keys,
+				 uint32_t *report_types, const char *separator,
+				 int aligned, int buffered, int headings,
+				 const struct dm_report_field_type *fds,
+				 int num_fds,
+				 const struct dm_report_object_type *types,
+				 int num_types,
+				 void *private);
+void dm_report_free(struct dm_report *rh);
+int dm_report_object(struct dm_report *rh, void *object);
+int dm_report_output(struct dm_report *rh);
+void * dm_report_get_private(struct dm_report *rh);
+
+/* report functions for common types */
+int dm_report_field_string(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field, const void *data);
+int dm_report_field_int32(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field, const void *data);
+int dm_report_field_uint32(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field, const void *data);
+int dm_report_field_int(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field, const void *data);
+int dm_report_field_uint64(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field, const void *data);
+
+/* helper functions for custom report functions */
+int dm_report_field_raw(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field, const void *data);
+void dm_report_field_set_string(struct dm_report_field *field, const char *string);
+void dm_report_field_set_sort_value(struct dm_report_field *field, const void *value);
 #endif				/* LIB_DEVICE_MAPPER_H */
lib/libdm-report.c new file +1111 -0

1,111 lines not on this page · raw message

lib/Makefile.in +1 -0
Index: device-mapper/lib/Makefile.in
===================================================================
@@ -24,6 +24,7 @@ SOURCES =\
 	libdm-file.c \
 	libdm-deptree.c \
 	libdm-string.c \
+	libdm-report.c \
 	mm/dbg_malloc.c \
 	mm/pool.c \
 	$(interface)/libdm-iface.c
lib/.exported_symbols +13 -0
Index: device-mapper/lib/.exported_symbols
===================================================================
@@ -115,3 +115,16 @@ dm_split_lvm_name
 dm_split_words
 dm_snprintf
 dm_basename
+dm_report_init
+dm_report_object
+dm_report_output
+dm_report_free
+dm_report_get_private
+dm_report_field_string
+dm_report_field_int32
+dm_report_field_uint32
+dm_report_field_int
+dm_report_field_uint64
+dm_report_field_raw
+dm_report_field_set_string
+dm_report_field_set_sort_value
#1 lore raw

PATCH 1/1 (2/4) dmsetup info to use dm_report

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

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)

dmsetup/dmsetup.c +436 -13
Index: device-mapper/dmsetup/dmsetup.c
===================================================================
@@ -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]) {
#2 lore raw

PATCH 1/1 (3/4) Remove old codes for "info -c" from dmsetup

In reply to Jun'ichi Nomura

Hi,

This patch removes _display_info_cols*() functions used for "dmsetup info -c" implementation.
These can be replaced by the new code using dm_report.

Thanks,
--
Jun'ichi Nomura, NEC Corporation of America

Replace old _display_info_cols{_noheadings} by _report()

Slight incompatibility is introduced:
Output of verbose + column is changed.
e.g. dmsetup table -v -c

    # dmsetup.old table -c -v
    Name             Maj Min Stat Open Targ Event  UUID
    d4               254   6 L--w    0    1      0 
    0 409600 linear 7:0 1638400

d3 254 5 L--w 0 1 0
0 409600 linear 7:0 1228800
...

# dmsetup.new table -c -v
Name Maj Min Stat Open Targ Event UUID
d4 254 6 L--w 0 1 0
0 409600 linear 7:0 1638400

Name Maj Min Stat Open Targ Event UUID
d3 254 5 L--w 0 1 0
0 409600 linear 7:0 1228800
...

Field head used to be displayed only once but now it's displayed for every tables.

dmsetup/dmsetup.c +1 -65
Index: device-mapper/dmsetup/dmsetup.c
===================================================================
@@ -225,68 +225,6 @@ static int _parse_file(struct dm_task *d
 	return r;
 }
 
-static void _display_info_cols_noheadings(struct dm_task *dmt,
-					  struct dm_info *info)
-{
-	const char *uuid;
-
-	if (!info->exists)
-		return;
-
-	uuid = dm_task_get_uuid(dmt);
-
-	if (_switches[OPTIONS_ARG])
-		printf("%s\n", dm_task_get_name(dmt));
-	else
-		printf("%s:%d:%d:%s%s%s%s:%d:%d:%" PRIu32 ":%s\n",
-		       dm_task_get_name(dmt),
-		       info->major, info->minor,
-		       info->live_table ? "L" : "-",
-		       info->inactive_table ? "I" : "-",
-		       info->suspended ? "s" : "-",
-		       info->read_only ? "r" : "w",
-		       info->open_count, info->target_count, info->event_nr,
-		       uuid && *uuid ? uuid : "");
-}
-
-static void _display_info_cols(struct dm_task *dmt, struct dm_info *info)
-{
-	static int _headings = 0;
-	const char *uuid;
-
-	if (!info->exists) {
-		printf("Device does not exist.\n");
-		return;
-	}
-
-	if (!_headings) {
-		if (_switches[OPTIONS_ARG])
-			printf("Name\n");
-		else
-			printf("Name             Maj Min Stat Open Targ "
-			       "Event  UUID\n");
-		_headings = 1;
-	}
-
-	if (_switches[OPTIONS_ARG])
-		printf("%s\n", dm_task_get_name(dmt));
-	else {
-		printf("%-16s %3d %3d %s%s%s%s %4d %4d %6" PRIu32 " ",
-		       dm_task_get_name(dmt),
-		       info->major, info->minor,
-		       info->live_table ? "L" : "-",
-		       info->inactive_table ? "I" : "-",
-		       info->suspended ? "s" : "-",
-		       info->read_only ? "r" : "w",
-		       info->open_count, info->target_count, info->event_nr);
-
-		if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
-			printf("%s", uuid);
-
-		printf("\n");
-	}
-}
-
 static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
 {
 	const char *uuid;
@@ -336,10 +274,8 @@ static int _display_info(struct dm_task 
 
 	if (!_switches[COLS_ARG])
 		_display_info_long(dmt, &info);
-	else if (_switches[NOHEADINGS_ARG])
-		_display_info_cols_noheadings(dmt, &info);
 	else
-		_display_info_cols(dmt, &info);
+		_report(0, NULL, dmt);
 
 	return info.exists ? 1 : 0;
 }
#3 lore raw

PATCH 1/1 (4/4) LVM2 to use dm_report

In reply to Jun'ichi Nomura

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.

lib/Makefile.in +0 -1
Index: LVM2.02.17/lib/Makefile.in
===================================================================
@@ -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
lib/report/columns.h deleted +0 -84

84 lines not on this page · raw message

lib/report/report.c deleted +0 -1572

1,572 lines not on this page · raw message

lib/report/report.h deleted +0 -38
Index: LVM2.02.17/lib/report/report.h
===================================================================
@@ -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
tools/columns.h new file +85 -0

85 lines not on this page · raw message

tools/reporter.c +905 -10

986 lines not on this page · raw message