[lvm-devel] master - dmsetup: Restructure arg handling.

Alasdair Kergon agk at fedoraproject.org
Thu Aug 13 21:39:43 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=043fb32c4b67d1456a77ab7caf0d077f419fae88
Commit:        043fb32c4b67d1456a77ab7caf0d077f419fae88
Parent:        b3cd5d294503fcfa4b826456e17071a909d739e1
Author:        Alasdair G Kergon <agk at redhat.com>
AuthorDate:    Thu Aug 13 22:30:39 2015 +0100
Committer:     Alasdair G Kergon <agk at redhat.com>
CommitterDate: Thu Aug 13 22:30:39 2015 +0100

dmsetup: Restructure arg handling.

Introduce enums and global variables to record cleanly which command we
are processing and eliminate the historically inconsistent use of the
shifted argv[0] and fix assorted bugs discovered along the way.

Add dm_report_is_empty() to indicate there is no data awaiting output
and use this to suppress dmsetup report headings when no data is output
so we don't get a stray line saying 'Help' at the end of reporting help.

Define a report type (as the interface requires) so -o all selects
the right fields in splitname.  (A fix for stats list will follow.)

Exit immediately if no device is supplied to dmsetup wipe_table instead
of hitting errors later and failing.

Adjust the command name printed in usage/help output to match command
invoked (most of the time).
---
 WHATS_NEW_DM                        |    6 +
 libdm/.exported_symbols.DM_1_02_105 |    1 +
 libdm/libdevmapper.h                |    5 +
 libdm/libdm-report.c                |    5 +
 tools/dmsetup.c                     |  400 +++++++++++++++++++++--------------
 5 files changed, 256 insertions(+), 161 deletions(-)

diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 45db0e4..f3b62b1 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,11 @@
 Version 1.02.105 - 
 ===================================
+  Exit immediately if no device is supplied to dmsetup wipe_table.
+  Suppress dmsetup report headings when no data is output. (1.02.104)
+  Adjust dmsetup usage/help output selection to match command invoked.
+  Fix dmsetup -o all to select correct fields in splitname report.
+  Restructure internal dmsetup argument handling across all commands.
+  Add dm_report_is_empty() to indicate there is no data awaiting output.
   Add more arg validation for dm_tree_node_add_cache_target().
   Add --alldevices switch to replace use of --force for stats create / delete.
 
diff --git a/libdm/.exported_symbols.DM_1_02_105 b/libdm/.exported_symbols.DM_1_02_105
new file mode 100644
index 0000000..9b701f1
--- /dev/null
+++ b/libdm/.exported_symbols.DM_1_02_105
@@ -0,0 +1 @@
+dm_report_is_empty
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 192fd0f..303ed67 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -2396,6 +2396,11 @@ int dm_report_object_is_selected(struct dm_report *rh, void *object, int do_outp
  */
 int dm_report_compact_fields(struct dm_report *rh);
 
+/*
+ * Returns 1 if there is no data waiting to be output.
+ */
+int dm_report_is_empty(struct dm_report *rh);
+
 int dm_report_output(struct dm_report *rh);
 
 /*
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 17a7e13..84b1294 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -4305,6 +4305,11 @@ static int _output_as_columns(struct dm_report *rh)
 	return 0;
 }
 
+int dm_report_is_empty(struct dm_report *rh)
+{
+	return dm_list_empty(&rh->rows) ? 1 : 0;
+}
+
 int dm_report_output(struct dm_report *rh)
 {
 	if (dm_list_empty(&rh->rows))
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 1dcc7e3..b3820fe 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -108,10 +108,46 @@ extern char *optarg;
 /* program_id used for dmstats-managed statistics regions */
 #define DM_STATS_PROGRAM_ID "dmstats"
 
+/*
+ * Basic commands this code implments.
+ */
+typedef enum {
+	DMSETUP_CMD = 0,
+	LOSETUP_CMD = 1,
+	DMLOSETUP_CMD = 2,
+	DMSTATS_CMD = 3,
+	DMSETUP_STATS_CMD = 4,
+	DEVMAP_NAME_CMD = 5
+} cmd_name_t;
+
+typedef enum {
+	DMSETUP_TYPE = 0,
+	LOSETUP_TYPE = 1,
+	STATS_TYPE = 2,
+	DEVMAP_NAME_TYPE = 3
+} cmd_type_t;
+
 #define DMSETUP_CMD_NAME "dmsetup"
 #define LOSETUP_CMD_NAME "losetup"
 #define DMLOSETUP_CMD_NAME "dmlosetup"
 #define DMSTATS_CMD_NAME "dmstats"
+#define DMSETUP_STATS_CMD_NAME "dmsetup stats"
+#define DEVMAP_NAME_CMD_NAME "devmap_name"
+
+static const struct {
+	cmd_name_t command;
+	const char name[14];
+	cmd_type_t type;
+} _base_commands[] = {
+	{ DMSETUP_CMD, DMSETUP_CMD_NAME, DMSETUP_TYPE },
+	{ LOSETUP_CMD, LOSETUP_CMD_NAME, LOSETUP_TYPE },
+	{ DMLOSETUP_CMD, DMLOSETUP_CMD_NAME, LOSETUP_TYPE },
+	{ DMSTATS_CMD, DMSTATS_CMD_NAME, STATS_TYPE },
+	{ DMSETUP_STATS_CMD, DMSETUP_STATS_CMD_NAME, STATS_TYPE },
+	{ DEVMAP_NAME_CMD, DEVMAP_NAME_CMD_NAME, DEVMAP_NAME_TYPE },
+};
+
+static const int _num_base_commands = DM_ARRAY_SIZE(_base_commands);
 
 /*
  * We have only very simple switches ATM.
@@ -195,6 +231,8 @@ typedef enum {
 	DN_MAP		/* Map name (for dm devices only, equal to DN_BLK otherwise) */
 } dev_name_t;
 
+static cmd_name_t _base_command = DMSETUP_CMD;	/* Default command is 'dmsetup' */
+static cmd_type_t _base_command_type = DMSETUP_TYPE;
 static int _switches[NUM_SWITCHES];
 static int _int_args[NUM_SWITCHES];
 static char *_string_args[NUM_SWITCHES];
@@ -202,7 +240,8 @@ static int _num_devices;
 static char *_uuid;
 static char *_table;
 static char *_target;
-static char *_command;
+static char *_command_to_exec;		/* --exec <command> */
+static const char *_command;		/* dmsetup <command> */
 static uint32_t _read_ahead_flags;
 static uint32_t _udev_cookie;
 static int _udev_only;
@@ -934,20 +973,20 @@ static int _load(CMD_ARGS)
 	}
 
 	if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
-		if (argc == 1) {
+		if (!argc) {
 			err("Please specify device.\n");
 			return 0;
 		}
-		name = argv[1];
+		name = argv[0];
 		argc--;
 		argv++;
-	} else if (argc > 2) {
+	} else if (argc > 1) {
 		err("Too many command line arguments.\n");
 		return 0;
 	}
 
-	if (argc == 2)
-		file = argv[1];
+	if (argc == 1)
+		file = argv[0];
 
 	if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
 		return 0;
@@ -992,13 +1031,13 @@ static int _create(CMD_ARGS)
 	uint32_t cookie = 0;
 	uint16_t udev_flags = 0;
 
-	if (argc == 3)
-		file = argv[2];
+	if (argc == 2)
+		file = argv[1];
 
 	if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
 		return 0;
 
-	if (!dm_task_set_name(dmt, argv[1]))
+	if (!dm_task_set_name(dmt, argv[0]))
 		goto out;
 
 	if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid))
@@ -1128,7 +1167,7 @@ static int _do_rename(const char *name, const char *new_name, const char *new_uu
 
 static int _rename(CMD_ARGS)
 {
-	const char *name = (argc == 3) ? argv[1] : NULL;
+	const char *name = (argc == 2) ? argv[0] : NULL;
 
 	return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) :
 					_do_rename(name, argv[argc - 1], NULL);
@@ -1152,22 +1191,22 @@ static int _message(CMD_ARGS)
 		if (!_set_task_device(dmt, NULL, 0))
 			goto out;
 	} else {
-		if (!_set_task_device(dmt, argv[1], 0))
+		if (!_set_task_device(dmt, argv[0], 0))
 			goto out;
 		argc--;
 		argv++;
 	}
 
-	sector = strtoull(argv[1], &endptr, 10);
-	if (*endptr || endptr == argv[1]) {
+	sector = strtoull(argv[0], &endptr, 10);
+	if (*endptr || endptr == argv[0]) {
 		err("invalid sector");
 		goto out;
 	}
 	if (!dm_task_set_sector(dmt, sector))
 		goto out;
 
-	argc -= 2;
-	argv += 2;
+	argc--;
+	argv++;
 
 	if (argc <= 0)
 		err("No message supplied.\n");
@@ -1232,13 +1271,13 @@ static int _setgeometry(CMD_ARGS)
 		if (!_set_task_device(dmt, NULL, 0))
 			goto out;
 	} else {
-		if (!_set_task_device(dmt, argv[1], 0))
+		if (!_set_task_device(dmt, argv[0], 0))
 			goto out;
 		argc--;
 		argv++;
 	}
 
-	if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
+	if (!dm_task_set_geometry(dmt, argv[0], argv[1], argv[2], argv[3]))
 		goto out;
 
 	if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
@@ -1267,8 +1306,8 @@ static int _splitname(CMD_ARGS)
 	struct dmsetup_report_obj obj = { NULL };
 	int r;
 
-	if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
-					       argv[1], '\0')))
+	if (!(obj.split_name = _get_split_name((argc == 2) ? argv[1] : "LVM",
+					       argv[0], '\0')))
 		return_0;
 
 	r = dm_report_object(_report, &obj);
@@ -1308,7 +1347,7 @@ static int _udevflags(CMD_ARGS)
 					      "PRIMARY_SOURCE",
 					       0};
 
-	if (!(cookie = _get_cookie_value(argv[1])))
+	if (!(cookie = _get_cookie_value(argv[0])))
 		return 0;
 
 	flags = cookie >> DM_UDEV_FLAGS_SHIFT;
@@ -1340,7 +1379,7 @@ static int _udevcomplete(CMD_ARGS)
 {
 	uint32_t cookie;
 
-	if (!(cookie = _get_cookie_value(argv[1])))
+	if (!(cookie = _get_cookie_value(argv[0])))
 		return 0;
 
 	/*
@@ -1465,7 +1504,7 @@ static int _udevcreatecookie(CMD_ARGS)
 
 static int _udevreleasecookie(CMD_ARGS)
 {
-	if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
+	if (argv[0] && !(_udev_cookie = _get_cookie_value(argv[0])))
 		return 0;
 
 	if (!_udev_cookie) {
@@ -1515,7 +1554,7 @@ static int _udevcomplete_all(CMD_ARGS)
 	unsigned age = 0;
 	time_t t;
 
-	if (argc == 2 && (sscanf(argv[1], "%u", &age) != 1)) {
+	if (argc == 1 && (sscanf(argv[0], "%u", &age) != 1)) {
 		log_error("Failed to read age_in_minutes parameter.");
 		return 0;
 	}
@@ -1713,17 +1752,17 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
 
 static int _suspend(CMD_ARGS)
 {
-	return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
+	return _simple(DM_DEVICE_SUSPEND, argc ? argv[0] : NULL, 0, 1);
 }
 
 static int _resume(CMD_ARGS)
 {
-	return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
+	return _simple(DM_DEVICE_RESUME, argc ? argv[0] : NULL, 0, 1);
 }
 
 static int _clear(CMD_ARGS)
 {
-	return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
+	return _simple(DM_DEVICE_CLEAR, argc ? argv[0] : NULL, 0, 1);
 }
 
 static int _wait(CMD_ARGS)
@@ -1731,16 +1770,16 @@ static int _wait(CMD_ARGS)
 	const char *name = NULL;
 
 	if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
-		if (argc == 1) {
+		if (!argc) {
 			err("No device specified.");
 			return 0;
 		}
-		name = argv[1];
+		name = argv[0];
 		argc--, argv++;
 	}
 
 	return _simple(DM_DEVICE_WAITEVENT, name,
-		       (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
+		       (argc) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
 }
 
 static int _process_all(const struct command *cmd, const char *subcommand, int argc, char **argv, int silent,
@@ -1833,7 +1872,7 @@ static int _error_device(CMD_ARGS)
 	uint64_t size;
 	int r = 0;
 
-	name = names ? names->name : argv[1];
+	name = names ? names->name : argv[0];
 
 	size = _get_device_size(name);
 
@@ -1875,7 +1914,7 @@ error:
 
 static int _remove(CMD_ARGS)
 {
-	if (_switches[FORCE_ARG] && argc > 1) {
+	if (_switches[FORCE_ARG] && argc) {
 		/*
 		 * 'remove --force' option is doing 2 operations on the same device
 		 * this is not compatible with the use of --udevcookie/DM_UDEV_COOKIE.
@@ -1886,7 +1925,7 @@ static int _remove(CMD_ARGS)
 		(void) _error_device(cmd, NULL, argc, argv, NULL, 0);
 	}
 
-	return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
+	return _simple(DM_DEVICE_REMOVE, argc ? argv[0] : NULL, 0, 0);
 }
 
 static int _count_devices(CMD_ARGS)
@@ -1936,7 +1975,7 @@ static void _display_dev(struct dm_task *dmt, const char *name)
 
 static int _mknodes(CMD_ARGS)
 {
-	return dm_mknodes(argc > 1 ? argv[1] : NULL);
+	return dm_mknodes(argc ? argv[0] : NULL);
 }
 
 static int _exec_command(const char *name)
@@ -1959,7 +1998,7 @@ static int _exec_command(const char *name)
 		return 0;
 
 	if (!argc) {
-		c = _command;
+		c = _command_to_exec;
 		while (argc < ARGS_MAX) {
 			while (*c && isspace(*c))
 				c++;
@@ -2015,9 +2054,9 @@ static int _status(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, NULL, argc, argv, 0, _status);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (!strcmp(cmd->name, "table"))
@@ -2064,11 +2103,11 @@ static int _status(CMD_ARGS)
 		    (!target_type || strcmp(target_type, _target)))
 			continue;
 		if (ls_only) {
-			if (!_switches[EXEC_ARG] || !_command ||
+			if (!_switches[EXEC_ARG] || !_command_to_exec ||
 			    _switches[VERBOSE_ARG])
 				_display_dev(dmt, name);
 			next = NULL;
-		} else if (!_switches[EXEC_ARG] || !_command ||
+		} else if (!_switches[EXEC_ARG] || !_command_to_exec ||
 			   _switches[VERBOSE_ARG]) {
 			if (!matched && _switches[VERBOSE_ARG])
 				_display_info(dmt);
@@ -2098,7 +2137,7 @@ static int _status(CMD_ARGS)
 	if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
 		printf("\n");
 
-	if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
+	if (matched && _switches[EXEC_ARG] && _command_to_exec && !_exec_command(name))
 		goto out;
 
 	r = 1;
@@ -2154,9 +2193,9 @@ static int _info(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, NULL, argc, argv, 0, _info);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
@@ -2198,9 +2237,9 @@ static int _deps(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, NULL, argc, argv, 0, _deps);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
@@ -3930,14 +3969,20 @@ static int _report_init(const struct command *cmd)
 	size_t len = 0;
 	int r = 0;
 
-	if (cmd && !strcmp(cmd->name, "splitname"))
+	if (cmd && !strcmp(cmd->name, "splitname")) {
 		options = (char *) splitname_report_options;
+		_report_type |= DR_NAME;
+	}
 
-	if (cmd && !strcmp(cmd->name, "stats"))
+	if (cmd && !strcmp(cmd->name, "stats")) {
 		options = (char *) _stats_default_report_options;
+		_report_type |= DR_STATS;
+	}
 
-	if (cmd && !strcmp(cmd->name, "list"))
+	if (cmd && !strcmp(cmd->name, "list")) {
 		options = (char *) _stats_list_options;
+		_report_type |= DR_STATS;
+	}
 
 	/* emulate old dmsetup behaviour */
 	if (_switches[NOHEADINGS_ARG]) {
@@ -3962,10 +4007,12 @@ static int _report_init(const struct command *cmd)
 
 	if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
 		/* Count & interval forbidden for help. */
+		/* FIXME Detect "help" correctly and exit */
 		if (strstr(_string_args[OPTIONS_ARG], "help")) {
 			_switches[COUNT_ARG] = 0;
 			_count = 1;
 			_switches[INTERVAL_ARG] = 0;
+			headings = 0;
 		}
 
 		if (*_string_args[OPTIONS_ARG] != '+')
@@ -4055,7 +4102,7 @@ out:
 static int _ls(CMD_ARGS)
 {
 	if ((_switches[TARGET_ARG] && _target) ||
-	    (_switches[EXEC_ARG] && _command))
+	    (_switches[EXEC_ARG] && _command_to_exec))
 		return _status(cmd, NULL, argc, argv, NULL, 0);
 	else if ((_switches[TREE_ARG]))
 		return _display_tree(cmd, NULL, 0, NULL, NULL, 0);
@@ -4075,9 +4122,9 @@ static int _mangle(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, NULL, argc, argv, 0, _mangle);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
@@ -4223,9 +4270,9 @@ static int _stats_clear(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, subcommand, argc, argv, 0, _stats_clear);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	region_id = (allregions) ? DM_STATS_REGIONS_ALL
@@ -4418,7 +4465,7 @@ static int _stats_create(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
 			if (!_switches[ALL_DEVICES_ARG]) {
 				log_error("Please specify device(s) or use "
 					  "--alldevices.");
@@ -4426,7 +4473,7 @@ static int _stats_create(CMD_ARGS)
 			}
 			return _process_all(cmd, subcommand, argc, argv, 0, _stats_create);
 		}
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (_switches[AREAS_ARG])
@@ -4506,7 +4553,7 @@ static int _stats_delete(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
 			if (!_switches[ALL_DEVICES_ARG]) {
 				log_error("Please specify device(s) or use "
 					  "--alldevices.");
@@ -4514,7 +4561,7 @@ static int _stats_delete(CMD_ARGS)
 			}
 			return _process_all(cmd, subcommand, argc, argv, 0, _stats_delete);
 		}
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (_switches[ALL_PROGRAMS_ARG])
@@ -4565,9 +4612,9 @@ static int _stats_list(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, subcommand, argc, argv, 0, _stats_list);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (_switches[PROGRAM_ID_ARG])
@@ -4661,9 +4708,9 @@ static int _stats_print(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, subcommand, argc, argv, 0, _stats_print);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	region_id = (uint64_t) _int_args[REGION_ID_ARG];
@@ -4720,9 +4767,9 @@ static int _stats_report(CMD_ARGS)
 	if (names)
 		name = names->name;
 	else {
-		if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
 			return _process_all(cmd, subcommand, argc, argv, 0, _info);
-		name = argv[1];
+		name = argv[0];
 	}
 
 	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
@@ -4811,7 +4858,7 @@ static struct command _dmsetup_commands[] = {
 	{"load", "<device> [<table_file>]", 0, 2, 0, 0, _load},
 	{"clear", "<device>", 0, -1, 1, 0, _clear},
 	{"reload", "<device> [<table_file>]", 0, 2, 0, 0, _load},
-	{"wipe_table", "<device>", 0, -1, 1, 0, _error_device},
+	{"wipe_table", "<device>", 1, -1, 1, 0, _error_device},
 	{"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, 0, _rename},
 	{"message", "<device> <sector> <message>", 2, -1, 0, 0, _message},
 	{"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, 0, _ls},
@@ -4840,22 +4887,30 @@ static struct command _dmsetup_commands[] = {
  * Usage and help text.
  */
 
+static void _devmap_name_usage(FILE *out)
+{
+	fprintf(out, "Usage: " DEVMAP_NAME_CMD_NAME " <major> <minor>\n\n");
+}
+
 static void _stats_usage(FILE *out)
 {
 	int i;
 
-	fprintf(out, "Usage:\n");
-	fprintf(out, "stats [-h|--help]\n");
+	fprintf(out, "Usage:\n\n");
+	fprintf(out, "%s\n", _base_commands[_base_command].name);
+	fprintf(out, "        [-h|--help]\n");
 	fprintf(out, "        [-v|--verbose [-v|--verbose ...]]\n");
 	fprintf(out, "        [--areas <nr_areas>] [--areasize <size>]\n");
 	fprintf(out, "        [--auxdata <data>] [--clear]\n");
 	fprintf(out, "        [--count <count>] [--interval <seconds>]\n");
 	fprintf(out, "        [-o <fields>] [-O|--sort <sort_fields>]\n");
-	fprintf(out, "	   [--programid <id>]\n");
+	fprintf(out, "	      [--programid <id>]\n");
 	fprintf(out, "        [--start <start>] [--length <length>]\n");
 	fprintf(out, "        [--segments] [--units <units>]\n\n");
+
 	for (i = 0; _stats_subcommands[i].name; i++)
 		fprintf(out, "\t%s %s\n", _stats_subcommands[i].name, _stats_subcommands[i].help);
+
 	fprintf(out, "<device> may be device name or -u <uuid> or "
 		     "-j <major> -m <minor>\n");
 	fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
@@ -4867,7 +4922,8 @@ static void _dmsetup_usage(FILE *out)
 	int i;
 
 	fprintf(out, "Usage:\n\n");
-	fprintf(out, DMSETUP_CMD_NAME " [--version] [-h|--help [-c|-C|--columns]]\n"
+	fprintf(out, "%s\n"
+		"        [--version] [-h|--help [-c|-C|--columns]]\n"
 		"        [-v|--verbose [-v|--verbose ...]]\n"
 		"        [--checks] [--manglename <mangling_mode>]\n"
 		"        [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
@@ -4875,9 +4931,12 @@ static void _dmsetup_usage(FILE *out)
 		"        [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
 		"        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
 		"        [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
-		"        [--separator <separator>]\n\n");
+		"        [--separator <separator>]\n\n",
+		_base_commands[_base_command].name);
+
 	for (i = 0; _dmsetup_commands[i].name; i++)
 		fprintf(out, "\t%s %s\n", _dmsetup_commands[i].name, _dmsetup_commands[i].help);
+
 	fprintf(out, "\n<device> may be device name or -u <uuid> or "
 		     "-j <major> -m <minor>\n");
 	fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
@@ -4892,23 +4951,30 @@ static void _dmsetup_usage(FILE *out)
 static void _losetup_usage(FILE *out)
 {
 	fprintf(out, "Usage:\n\n");
-	fprintf(out, LOSETUP_CMD_NAME " [-d|-a] [-e encryption] "
-		     "[-o offset] [-f|loop_device] [file]\n\n");
+	fprintf(out, "%s [-d|-a] [-e encryption] "
+		     "[-o offset] [-f|loop_device] [file]\n\n",
+		     _base_commands[_base_command].name);
 }
 
-static int _stats_help(CMD_ARGS)
+static void _usage(FILE *out)
 {
-	_stats_usage(stderr);
+	switch (_base_commands[_base_command].type) {
+	case DMSETUP_TYPE:
+		return _dmsetup_usage(out);
+	case LOSETUP_TYPE:
+		return _losetup_usage(out);
+	case STATS_TYPE:
+		return _stats_usage(out);
+	case DEVMAP_NAME_TYPE:
+		return _devmap_name_usage(out);
+	}
+}
 
-	/**
-	 * main() increments this to ensure reports are set up for
-	 * stats use so decrement that count here; if the counter is
-	 * still non-zero then the user explicitly requested the
-	 * columns help output.
-	 */
-	_switches[COLS_ARG]--;
+static int _stats_help(CMD_ARGS)
+{
+	_usage(stderr);
 
-	if (_switches[COLS_ARG]) {
+	if (_switches[COLS_ARG] || (argc && !strcmp(argv[0], "report"))) {
 		_switches[OPTIONS_ARG] = 1;
 		_string_args[OPTIONS_ARG] = (char *) "help";
 		_switches[SORT_ARG] = 0;
@@ -4917,19 +4983,20 @@ static int _stats_help(CMD_ARGS)
 			dm_report_free(_report);
 			_report = NULL;
 		}
+
 		(void) _report_init(cmd);
+		if (_report) {
+			dm_report_free(_report);
+			_report = NULL;
+		}
 	}
 
-	/* help text already output: don't repeat from main */
-	dm_report_free(_report);
-	_report = NULL;
-
 	return 1;
 }
 
 static int _dmsetup_help(CMD_ARGS)
 {
-	_dmsetup_usage(stderr);
+	_usage(stderr);
 
 	if (_switches[COLS_ARG]) {
 		_switches[OPTIONS_ARG] = 1;
@@ -4941,6 +5008,10 @@ static int _dmsetup_help(CMD_ARGS)
 			_report = NULL;
 		}
 		(void) _report_init(cmd);
+		if (_report) {
+			dm_report_free(_report);
+			_report = NULL;
+		}
 	}
 
 	return 1;
@@ -4972,11 +5043,6 @@ static int _stats(CMD_ARGS)
 {
 	const struct command *stats_cmd;
 
-	if (_switches[HELP_ARG]) {
-		stats_cmd = _find_stats_subcommand("help");
-		goto doit;
-	}
-
 	if (!(stats_cmd = _find_stats_subcommand(subcommand))) {
 		log_error("Unknown stats command.");
 		_stats_help(stats_cmd, NULL, argc, argv, NULL, multiple_devices);
@@ -4993,7 +5059,6 @@ static int _stats(CMD_ARGS)
 		return 0;
 	}
 
-doit:
 	if (!stats_cmd->fn(stats_cmd, NULL, argc, argv, NULL, multiple_devices))
 		return 0;
 
@@ -5249,29 +5314,29 @@ static int _process_losetup_switches(const char *base, int *argcp, char ***argvp
 
 	if (!*argcp) {
 		fprintf(stderr, "%s: Please specify loop_device.\n", base);
-		_losetup_usage(stderr);
+		_usage(stderr);
 		return 0;
 	}
 
 	if (!(device_name = parse_loop_device_name((*argvp)[0], dev_dir))) {
 		fprintf(stderr, "%s: Could not parse loop_device %s\n",
 			base, (*argvp)[0]);
-		_losetup_usage(stderr);
+		_usage(stderr);
 		return 0;
 	}
 
 	if (delete) {
-		*argcp = 2;
+		*argcp = 1;
 
-		(*argvp)[1] = device_name;
-		(*argvp)[0] = (char *) "remove";
+		(*argvp)[0] = device_name;
+		_command = "remove";
 
 		return 1;
 	}
 
 	if (*argcp != 2) {
 		fprintf(stderr, "%s: Too few arguments\n", base);
-		_losetup_usage(stderr);
+		_usage(stderr);
 		dm_free(device_name);
 		return 0;
 	}
@@ -5280,7 +5345,7 @@ static int _process_losetup_switches(const char *base, int *argcp, char ***argvp
 	if (!(loop_file = _get_abspath((*argvp)[(find) ? 0 : 1]))) {
 		fprintf(stderr, "%s: Could not parse loop file name %s\n",
 			base, (*argvp)[1]);
-		_losetup_usage(stderr);
+		_usage(stderr);
 		dm_free(device_name);
 		return 0;
 	}
@@ -5294,8 +5359,9 @@ static int _process_losetup_switches(const char *base, int *argcp, char ***argvp
 	}
 	_switches[TABLE_ARG]++;
 
-	(*argvp)[0] = (char *) "create";
-	(*argvp)[1] = device_name ;
+	_command = "create";
+	(*argvp)[0] = device_name ;
+	*argcp = 1;
 
 	return 1;
 }
@@ -5349,9 +5415,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 	const char *base;
 	char *namebase, *s;
 	static int ind;
-	int c, r;
-	/* "stats" command and sub-command when run as 'dmstats'. */
-	char *stats_p = NULL, *stats_c = NULL;
+	int c, r, i;
 
 #ifdef HAVE_GETOPTLONG
 	static struct option long_options[] = {
@@ -5432,10 +5496,21 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 		fprintf(stderr, "Failed to duplicate name.\n");
 		return 0;
 	}
+
 	base = dm_basename(namebase);
 
-	if (!strcmp(base, "devmap_name")) {
-		free(namebase);
+	i = 0;
+	do {
+		if (!strcmp(base, _base_commands[i].name)) {
+			_base_command = _base_commands[i].command;
+			_base_command_type = _base_commands[i].type;
+			break;
+		}
+	} while (++i < _num_base_commands);
+
+	free(namebase);
+
+	if (_base_command_type == DEVMAP_NAME_TYPE) {
 		_switches[COLS_ARG]++;
 		_switches[NOHEADINGS_ARG]++;
 		_switches[OPTIONS_ARG]++;
@@ -5455,28 +5530,22 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 			*argcp -= 1;
 			*argvp += 1;
 		} else {
-			fprintf(stderr, "Usage: devmap_name <major> <minor>\n");
+			_usage(stderr);
 			return 0;
 		}
 
-		(*argvp)[0] = (char *) "info";
+		_command = "info";
+		(*argvp)++;
+		(*argcp)--;
+
 		return 1;
 	}
 
-	if (!strcmp(base, LOSETUP_CMD_NAME) || !strcmp(base, DMLOSETUP_CMD_NAME)){
-		r = _process_losetup_switches(base, argcp, argvp, dev_dir);
-		free(namebase);
+	if (_base_command_type == LOSETUP_TYPE) {
+		r = _process_losetup_switches(_base_commands[_base_command].name, argcp, argvp, dev_dir);
 		return r;
 	}
 
-	if (!strcmp(base, DMSTATS_CMD_NAME)) {
-		/* save the offset to the 'stats' in 'dmstats' */
-		stats_p = (*argvp)[0] + strlen(namebase) - strlen(base) + 2;
-		stats_c = (*argvp)[1]; /* stats command */
-	}
-
-	free(namebase);
-
 	optarg = 0;
 	optind = OPTIND_INIT;
 	while ((ind = -1, c = GETOPTLONG_FN(*argcp, *argvp, "cCfG:hj:m:M:no:O:rS:u:U:vy",
@@ -5608,7 +5677,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 			_switches[DEFERRED_ARG]++;
 		if (ind == EXEC_ARG) {
 			_switches[EXEC_ARG]++;
-			_command = optarg;
+			_command_to_exec = optarg;
 		}
 		if (ind == TARGET_ARG) {
 			_switches[TARGET_ARG]++;
@@ -5725,12 +5794,20 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 	*argvp += optind;
 	*argcp -= optind;
 
-	/* preserve sub-command in argv[0] */
-	if (stats_p) {
-		(*argvp)--;
-		(*argcp)++;
-		(*argvp)[0] = stats_p;
-		(*argvp)[1] = stats_c;
+	if (!*argcp)
+		_command = NULL;
+	else if (!strcmp((*argvp)[0], "stats")) {
+		_base_command = DMSETUP_STATS_CMD;
+		_base_command_type = STATS_TYPE;
+		_command = "stats";
+		(*argvp)++;
+		(*argcp)--;
+	} else if (_base_command == DMSTATS_CMD) {
+		_command = "stats";
+	} else if (*argcp) {
+		_command = (*argvp)[0];
+		(*argvp)++;
+		(*argcp)--;
 	}
 
 	return 1;
@@ -5738,15 +5815,14 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 
 static int _perform_command_for_all_repeatable_args(CMD_ARGS)
 {
-	/* FIXME Shift args to remove argv[0] that fn is not allowed to access? */
 	do {
-		if (!cmd->fn(cmd, subcommand, argc--, argv++, NULL, multiple_devices)) {
+		if (!cmd->fn(cmd, subcommand, argc, argv++, NULL, multiple_devices)) {
 			fprintf(stderr, "Command failed\n");
-			return 1;
+			return 0;
 		}
-	} while (cmd->repeatable_cmd && argc > 1);
+	} while (cmd->repeatable_cmd && argc-- > 1);
 
-	return 0;
+	return 1;
 }
 
 static int _do_report_wait(void)
@@ -5778,50 +5854,54 @@ int main(int argc, char **argv)
 		goto out;
 	}
 
-	/* let stats do its own --help handling. */
-	if (_switches[HELP_ARG] && strcmp("stats", argv[0])) {
-		if ((cmd = _find_dmsetup_command("help")))
-			goto doit;
-		goto unknown;
+	if (_switches[HELP_ARG]) {
+		switch (_base_command_type) {
+		case STATS_TYPE:
+			if ((cmd = _find_stats_subcommand("help")))
+				goto doit;
+			goto unknown;
+		default:
+			if ((cmd = _find_dmsetup_command("help")))
+				goto doit;
+			goto unknown;
+		}
 	}
 
 	if (_switches[VERSION_ARG]) {
-		if ((cmd = _find_dmsetup_command("version")))
-			goto doit;
-		goto unknown;
+		switch (_base_command_type) {
+		case STATS_TYPE:
+			if ((cmd = _find_stats_subcommand("version")))
+				goto doit;
+			goto unknown;
+		default:
+			if ((cmd = _find_dmsetup_command("version")))
+				goto doit;
+			goto unknown;
+		}
 	}
 
-	if (argc == 0) {
-		_dmsetup_usage(stderr);
+	if (!_command) {
+		_usage(stderr);
 		goto out;
 	}
 
-	if (!(cmd = _find_dmsetup_command(argv[0]))) {
+	if (!(cmd = _find_dmsetup_command(_command))) {
 unknown:
 		fprintf(stderr, "Unknown command\n");
-		_dmsetup_usage(stderr);
+		_usage(stderr);
 		goto out;
 	}
 
-	if (argc < cmd->min_args + 1 ||
-	    (cmd->max_args >= 0 && argc > cmd->max_args + 1)) {
+	if (argc < cmd->min_args ||
+	    (cmd->max_args >= 0 && argc > cmd->max_args)) {
 		fprintf(stderr, "Incorrect number of arguments\n");
-		if (!strcmp(cmd->name, "stats"))
-			_stats_usage(stderr);
-		else
-			_dmsetup_usage(stderr);
+		_usage(stderr);
 		goto out;
 	}
 
 	if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname"))
 		_switches[COLS_ARG]++;
 
-	/**
-	 * Unconditionally increment for "stats" commands; the only
-	 * command to not require this is non-columns "stats help".
-	 * In that case _stats_help will remove the extra count
-	 * before displaying the help message.
-	 */
 	if (!strcmp(cmd->name, "stats")) {
 		_switches[COLS_ARG]++;
 		if (!_switches[UNITS_ARG]) {
@@ -5865,7 +5945,7 @@ unknown:
 	 * dmsetup <command> <subcommand> [args...]
 	 */
 	if (cmd->has_subcommands) {
-		subcommand = argv[1];
+		subcommand = argv[0];
 		argc--, argv++;
 	}
 
@@ -5875,19 +5955,18 @@ unknown:
 			goto_out;
 
 doit:
-	multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
-			    (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
+	multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
+			    (argc || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
 
 	do {
 		r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
-
 		if (_report) {
 			/* only output headings for repeating reports */
-			if (_int_args[COUNT_ARG] != 1)
+			if (_int_args[COUNT_ARG] != 1 && !dm_report_is_empty(_report))
 				dm_report_column_headings(_report);
 			dm_report_output(_report);
 
-			if (_count > 1) {
+			if (_count > 1 && r) {
 				printf("\n");
 				/* wait for --interval and update timestamps */
 				if (!_do_report_wait())
@@ -5895,12 +5974,11 @@ doit:
 			}
 		}
 
-		if (r)
+		if (!r)
 			break;
 	} while (--_count);
 
 out:
-
 	if (_report)
 		dm_report_free(_report);
 




More information about the lvm-devel mailing list