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

[dm-devel] [PATCH] (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)


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]) {

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