1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-04 09:18:36 +03:00

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).
This commit is contained in:
Alasdair G Kergon 2015-08-13 22:30:39 +01:00
parent b3cd5d2945
commit 043fb32c4b
5 changed files with 257 additions and 162 deletions

View File

@ -1,5 +1,11 @@
Version 1.02.105 - 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 more arg validation for dm_tree_node_add_cache_target().
Add --alldevices switch to replace use of --force for stats create / delete. Add --alldevices switch to replace use of --force for stats create / delete.

View File

@ -0,0 +1 @@
dm_report_is_empty

View File

@ -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); 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); int dm_report_output(struct dm_report *rh);
/* /*

View File

@ -4305,6 +4305,11 @@ static int _output_as_columns(struct dm_report *rh)
return 0; 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) int dm_report_output(struct dm_report *rh)
{ {
if (dm_list_empty(&rh->rows)) if (dm_list_empty(&rh->rows))

View File

@ -108,10 +108,46 @@ extern char *optarg;
/* program_id used for dmstats-managed statistics regions */ /* program_id used for dmstats-managed statistics regions */
#define DM_STATS_PROGRAM_ID "dmstats" #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 DMSETUP_CMD_NAME "dmsetup"
#define LOSETUP_CMD_NAME "losetup" #define LOSETUP_CMD_NAME "losetup"
#define DMLOSETUP_CMD_NAME "dmlosetup" #define DMLOSETUP_CMD_NAME "dmlosetup"
#define DMSTATS_CMD_NAME "dmstats" #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. * 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) */ DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */
} dev_name_t; } 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 _switches[NUM_SWITCHES];
static int _int_args[NUM_SWITCHES]; static int _int_args[NUM_SWITCHES];
static char *_string_args[NUM_SWITCHES]; static char *_string_args[NUM_SWITCHES];
@ -202,7 +240,8 @@ static int _num_devices;
static char *_uuid; static char *_uuid;
static char *_table; static char *_table;
static char *_target; 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 _read_ahead_flags;
static uint32_t _udev_cookie; static uint32_t _udev_cookie;
static int _udev_only; static int _udev_only;
@ -934,20 +973,20 @@ static int _load(CMD_ARGS)
} }
if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
if (argc == 1) { if (!argc) {
err("Please specify device.\n"); err("Please specify device.\n");
return 0; return 0;
} }
name = argv[1]; name = argv[0];
argc--; argc--;
argv++; argv++;
} else if (argc > 2) { } else if (argc > 1) {
err("Too many command line arguments.\n"); err("Too many command line arguments.\n");
return 0; return 0;
} }
if (argc == 2) if (argc == 1)
file = argv[1]; file = argv[0];
if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
return 0; return 0;
@ -992,13 +1031,13 @@ static int _create(CMD_ARGS)
uint32_t cookie = 0; uint32_t cookie = 0;
uint16_t udev_flags = 0; uint16_t udev_flags = 0;
if (argc == 3) if (argc == 2)
file = argv[2]; file = argv[1];
if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
return 0; return 0;
if (!dm_task_set_name(dmt, argv[1])) if (!dm_task_set_name(dmt, argv[0]))
goto out; goto out;
if (_switches[UUID_ARG] && !dm_task_set_uuid(dmt, _uuid)) 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) 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]) : return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) :
_do_rename(name, argv[argc - 1], NULL); _do_rename(name, argv[argc - 1], NULL);
@ -1152,22 +1191,22 @@ static int _message(CMD_ARGS)
if (!_set_task_device(dmt, NULL, 0)) if (!_set_task_device(dmt, NULL, 0))
goto out; goto out;
} else { } else {
if (!_set_task_device(dmt, argv[1], 0)) if (!_set_task_device(dmt, argv[0], 0))
goto out; goto out;
argc--; argc--;
argv++; argv++;
} }
sector = strtoull(argv[1], &endptr, 10); sector = strtoull(argv[0], &endptr, 10);
if (*endptr || endptr == argv[1]) { if (*endptr || endptr == argv[0]) {
err("invalid sector"); err("invalid sector");
goto out; goto out;
} }
if (!dm_task_set_sector(dmt, sector)) if (!dm_task_set_sector(dmt, sector))
goto out; goto out;
argc -= 2; argc--;
argv += 2; argv++;
if (argc <= 0) if (argc <= 0)
err("No message supplied.\n"); err("No message supplied.\n");
@ -1232,13 +1271,13 @@ static int _setgeometry(CMD_ARGS)
if (!_set_task_device(dmt, NULL, 0)) if (!_set_task_device(dmt, NULL, 0))
goto out; goto out;
} else { } else {
if (!_set_task_device(dmt, argv[1], 0)) if (!_set_task_device(dmt, argv[0], 0))
goto out; goto out;
argc--; argc--;
argv++; 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; goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) 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 }; struct dmsetup_report_obj obj = { NULL };
int r; int r;
if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM", if (!(obj.split_name = _get_split_name((argc == 2) ? argv[1] : "LVM",
argv[1], '\0'))) argv[0], '\0')))
return_0; return_0;
r = dm_report_object(_report, &obj); r = dm_report_object(_report, &obj);
@ -1308,7 +1347,7 @@ static int _udevflags(CMD_ARGS)
"PRIMARY_SOURCE", "PRIMARY_SOURCE",
0}; 0};
if (!(cookie = _get_cookie_value(argv[1]))) if (!(cookie = _get_cookie_value(argv[0])))
return 0; return 0;
flags = cookie >> DM_UDEV_FLAGS_SHIFT; flags = cookie >> DM_UDEV_FLAGS_SHIFT;
@ -1340,7 +1379,7 @@ static int _udevcomplete(CMD_ARGS)
{ {
uint32_t cookie; uint32_t cookie;
if (!(cookie = _get_cookie_value(argv[1]))) if (!(cookie = _get_cookie_value(argv[0])))
return 0; return 0;
/* /*
@ -1465,7 +1504,7 @@ static int _udevcreatecookie(CMD_ARGS)
static int _udevreleasecookie(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; return 0;
if (!_udev_cookie) { if (!_udev_cookie) {
@ -1515,7 +1554,7 @@ static int _udevcomplete_all(CMD_ARGS)
unsigned age = 0; unsigned age = 0;
time_t t; 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."); log_error("Failed to read age_in_minutes parameter.");
return 0; 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) 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) 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) 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) static int _wait(CMD_ARGS)
@ -1731,16 +1770,16 @@ static int _wait(CMD_ARGS)
const char *name = NULL; const char *name = NULL;
if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
if (argc == 1) { if (!argc) {
err("No device specified."); err("No device specified.");
return 0; return 0;
} }
name = argv[1]; name = argv[0];
argc--, argv++; argc--, argv++;
} }
return _simple(DM_DEVICE_WAITEVENT, name, 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, 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; uint64_t size;
int r = 0; int r = 0;
name = names ? names->name : argv[1]; name = names ? names->name : argv[0];
size = _get_device_size(name); size = _get_device_size(name);
@ -1875,7 +1914,7 @@ error:
static int _remove(CMD_ARGS) 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 * 'remove --force' option is doing 2 operations on the same device
* this is not compatible with the use of --udevcookie/DM_UDEV_COOKIE. * 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); (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) 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) 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) static int _exec_command(const char *name)
@ -1959,7 +1998,7 @@ static int _exec_command(const char *name)
return 0; return 0;
if (!argc) { if (!argc) {
c = _command; c = _command_to_exec;
while (argc < ARGS_MAX) { while (argc < ARGS_MAX) {
while (*c && isspace(*c)) while (*c && isspace(*c))
c++; c++;
@ -2015,9 +2054,9 @@ static int _status(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, NULL, argc, argv, 0, _status);
name = argv[1]; name = argv[0];
} }
if (!strcmp(cmd->name, "table")) if (!strcmp(cmd->name, "table"))
@ -2064,11 +2103,11 @@ static int _status(CMD_ARGS)
(!target_type || strcmp(target_type, _target))) (!target_type || strcmp(target_type, _target)))
continue; continue;
if (ls_only) { if (ls_only) {
if (!_switches[EXEC_ARG] || !_command || if (!_switches[EXEC_ARG] || !_command_to_exec ||
_switches[VERBOSE_ARG]) _switches[VERBOSE_ARG])
_display_dev(dmt, name); _display_dev(dmt, name);
next = NULL; next = NULL;
} else if (!_switches[EXEC_ARG] || !_command || } else if (!_switches[EXEC_ARG] || !_command_to_exec ||
_switches[VERBOSE_ARG]) { _switches[VERBOSE_ARG]) {
if (!matched && _switches[VERBOSE_ARG]) if (!matched && _switches[VERBOSE_ARG])
_display_info(dmt); _display_info(dmt);
@ -2098,7 +2137,7 @@ static int _status(CMD_ARGS)
if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only) if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
printf("\n"); printf("\n");
if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name)) if (matched && _switches[EXEC_ARG] && _command_to_exec && !_exec_command(name))
goto out; goto out;
r = 1; r = 1;
@ -2154,9 +2193,9 @@ static int _info(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, NULL, argc, argv, 0, _info);
name = argv[1]; name = argv[0];
} }
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
@ -2198,9 +2237,9 @@ static int _deps(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, NULL, argc, argv, 0, _deps);
name = argv[1]; name = argv[0];
} }
if (!(dmt = dm_task_create(DM_DEVICE_DEPS))) if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
@ -3930,14 +3969,20 @@ static int _report_init(const struct command *cmd)
size_t len = 0; size_t len = 0;
int r = 0; int r = 0;
if (cmd && !strcmp(cmd->name, "splitname")) if (cmd && !strcmp(cmd->name, "splitname")) {
options = (char *) splitname_report_options; 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; 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; options = (char *) _stats_list_options;
_report_type |= DR_STATS;
}
/* emulate old dmsetup behaviour */ /* emulate old dmsetup behaviour */
if (_switches[NOHEADINGS_ARG]) { if (_switches[NOHEADINGS_ARG]) {
@ -3962,10 +4007,12 @@ static int _report_init(const struct command *cmd)
if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) { if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
/* Count & interval forbidden for help. */ /* Count & interval forbidden for help. */
/* FIXME Detect "help" correctly and exit */
if (strstr(_string_args[OPTIONS_ARG], "help")) { if (strstr(_string_args[OPTIONS_ARG], "help")) {
_switches[COUNT_ARG] = 0; _switches[COUNT_ARG] = 0;
_count = 1; _count = 1;
_switches[INTERVAL_ARG] = 0; _switches[INTERVAL_ARG] = 0;
headings = 0;
} }
if (*_string_args[OPTIONS_ARG] != '+') if (*_string_args[OPTIONS_ARG] != '+')
@ -4055,7 +4102,7 @@ out:
static int _ls(CMD_ARGS) static int _ls(CMD_ARGS)
{ {
if ((_switches[TARGET_ARG] && _target) || if ((_switches[TARGET_ARG] && _target) ||
(_switches[EXEC_ARG] && _command)) (_switches[EXEC_ARG] && _command_to_exec))
return _status(cmd, NULL, argc, argv, NULL, 0); return _status(cmd, NULL, argc, argv, NULL, 0);
else if ((_switches[TREE_ARG])) else if ((_switches[TREE_ARG]))
return _display_tree(cmd, NULL, 0, NULL, NULL, 0); return _display_tree(cmd, NULL, 0, NULL, NULL, 0);
@ -4075,9 +4122,9 @@ static int _mangle(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, NULL, argc, argv, 0, _mangle);
name = argv[1]; name = argv[0];
} }
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
@ -4223,9 +4270,9 @@ static int _stats_clear(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, subcommand, argc, argv, 0, _stats_clear);
name = argv[1]; name = argv[0];
} }
region_id = (allregions) ? DM_STATS_REGIONS_ALL region_id = (allregions) ? DM_STATS_REGIONS_ALL
@ -4418,7 +4465,7 @@ static int _stats_create(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { else {
if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
if (!_switches[ALL_DEVICES_ARG]) { if (!_switches[ALL_DEVICES_ARG]) {
log_error("Please specify device(s) or use " log_error("Please specify device(s) or use "
"--alldevices."); "--alldevices.");
@ -4426,7 +4473,7 @@ static int _stats_create(CMD_ARGS)
} }
return _process_all(cmd, subcommand, argc, argv, 0, _stats_create); return _process_all(cmd, subcommand, argc, argv, 0, _stats_create);
} }
name = argv[1]; name = argv[0];
} }
if (_switches[AREAS_ARG]) if (_switches[AREAS_ARG])
@ -4506,7 +4553,7 @@ static int _stats_delete(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { else {
if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) { if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
if (!_switches[ALL_DEVICES_ARG]) { if (!_switches[ALL_DEVICES_ARG]) {
log_error("Please specify device(s) or use " log_error("Please specify device(s) or use "
"--alldevices."); "--alldevices.");
@ -4514,7 +4561,7 @@ static int _stats_delete(CMD_ARGS)
} }
return _process_all(cmd, subcommand, argc, argv, 0, _stats_delete); return _process_all(cmd, subcommand, argc, argv, 0, _stats_delete);
} }
name = argv[1]; name = argv[0];
} }
if (_switches[ALL_PROGRAMS_ARG]) if (_switches[ALL_PROGRAMS_ARG])
@ -4565,9 +4612,9 @@ static int _stats_list(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, subcommand, argc, argv, 0, _stats_list);
name = argv[1]; name = argv[0];
} }
if (_switches[PROGRAM_ID_ARG]) if (_switches[PROGRAM_ID_ARG])
@ -4661,9 +4708,9 @@ static int _stats_print(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); 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]; region_id = (uint64_t) _int_args[REGION_ID_ARG];
@ -4720,9 +4767,9 @@ static int _stats_report(CMD_ARGS)
if (names) if (names)
name = names->name; name = names->name;
else { 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); return _process_all(cmd, subcommand, argc, argv, 0, _info);
name = argv[1]; name = argv[0];
} }
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) 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}, {"load", "<device> [<table_file>]", 0, 2, 0, 0, _load},
{"clear", "<device>", 0, -1, 1, 0, _clear}, {"clear", "<device>", 0, -1, 1, 0, _clear},
{"reload", "<device> [<table_file>]", 0, 2, 0, 0, _load}, {"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}, {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, 0, _rename},
{"message", "<device> <sector> <message>", 2, -1, 0, 0, _message}, {"message", "<device> <sector> <message>", 2, -1, 0, 0, _message},
{"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, 0, _ls}, {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, 0, _ls},
@ -4840,12 +4887,18 @@ static struct command _dmsetup_commands[] = {
* Usage and help text. * 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) static void _stats_usage(FILE *out)
{ {
int i; int i;
fprintf(out, "Usage:\n"); fprintf(out, "Usage:\n\n");
fprintf(out, "stats [-h|--help]\n"); fprintf(out, "%s\n", _base_commands[_base_command].name);
fprintf(out, " [-h|--help]\n");
fprintf(out, " [-v|--verbose [-v|--verbose ...]]\n"); fprintf(out, " [-v|--verbose [-v|--verbose ...]]\n");
fprintf(out, " [--areas <nr_areas>] [--areasize <size>]\n"); fprintf(out, " [--areas <nr_areas>] [--areasize <size>]\n");
fprintf(out, " [--auxdata <data>] [--clear]\n"); fprintf(out, " [--auxdata <data>] [--clear]\n");
@ -4854,8 +4907,10 @@ static void _stats_usage(FILE *out)
fprintf(out, " [--programid <id>]\n"); fprintf(out, " [--programid <id>]\n");
fprintf(out, " [--start <start>] [--length <length>]\n"); fprintf(out, " [--start <start>] [--length <length>]\n");
fprintf(out, " [--segments] [--units <units>]\n\n"); fprintf(out, " [--segments] [--units <units>]\n\n");
for (i = 0; _stats_subcommands[i].name; i++) for (i = 0; _stats_subcommands[i].name; i++)
fprintf(out, "\t%s %s\n", _stats_subcommands[i].name, _stats_subcommands[i].help); 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 " fprintf(out, "<device> may be device name or -u <uuid> or "
"-j <major> -m <minor>\n"); "-j <major> -m <minor>\n");
fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\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; int i;
fprintf(out, "Usage:\n\n"); 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" " [-v|--verbose [-v|--verbose ...]]\n"
" [--checks] [--manglename <mangling_mode>]\n" " [--checks] [--manglename <mangling_mode>]\n"
" [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\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" " [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n" " [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
" [-S|--select <selection>] [--nameprefixes] [--noheadings]\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++) for (i = 0; _dmsetup_commands[i].name; i++)
fprintf(out, "\t%s %s\n", _dmsetup_commands[i].name, _dmsetup_commands[i].help); 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 " fprintf(out, "\n<device> may be device name or -u <uuid> or "
"-j <major> -m <minor>\n"); "-j <major> -m <minor>\n");
fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\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) static void _losetup_usage(FILE *out)
{ {
fprintf(out, "Usage:\n\n"); fprintf(out, "Usage:\n\n");
fprintf(out, LOSETUP_CMD_NAME " [-d|-a] [-e encryption] " fprintf(out, "%s [-d|-a] [-e encryption] "
"[-o offset] [-f|loop_device] [file]\n\n"); "[-o offset] [-f|loop_device] [file]\n\n",
_base_commands[_base_command].name);
}
static void _usage(FILE *out)
{
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);
}
} }
static int _stats_help(CMD_ARGS) static int _stats_help(CMD_ARGS)
{ {
_stats_usage(stderr); _usage(stderr);
/** if (_switches[COLS_ARG] || (argc && !strcmp(argv[0], "report"))) {
* 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]--;
if (_switches[COLS_ARG]) {
_switches[OPTIONS_ARG] = 1; _switches[OPTIONS_ARG] = 1;
_string_args[OPTIONS_ARG] = (char *) "help"; _string_args[OPTIONS_ARG] = (char *) "help";
_switches[SORT_ARG] = 0; _switches[SORT_ARG] = 0;
@ -4917,19 +4983,20 @@ static int _stats_help(CMD_ARGS)
dm_report_free(_report); dm_report_free(_report);
_report = NULL; _report = NULL;
} }
(void) _report_init(cmd);
}
/* help text already output: don't repeat from main */ (void) _report_init(cmd);
if (_report) {
dm_report_free(_report); dm_report_free(_report);
_report = NULL; _report = NULL;
}
}
return 1; return 1;
} }
static int _dmsetup_help(CMD_ARGS) static int _dmsetup_help(CMD_ARGS)
{ {
_dmsetup_usage(stderr); _usage(stderr);
if (_switches[COLS_ARG]) { if (_switches[COLS_ARG]) {
_switches[OPTIONS_ARG] = 1; _switches[OPTIONS_ARG] = 1;
@ -4941,6 +5008,10 @@ static int _dmsetup_help(CMD_ARGS)
_report = NULL; _report = NULL;
} }
(void) _report_init(cmd); (void) _report_init(cmd);
if (_report) {
dm_report_free(_report);
_report = NULL;
}
} }
return 1; return 1;
@ -4972,11 +5043,6 @@ static int _stats(CMD_ARGS)
{ {
const struct command *stats_cmd; const struct command *stats_cmd;
if (_switches[HELP_ARG]) {
stats_cmd = _find_stats_subcommand("help");
goto doit;
}
if (!(stats_cmd = _find_stats_subcommand(subcommand))) { if (!(stats_cmd = _find_stats_subcommand(subcommand))) {
log_error("Unknown stats command."); log_error("Unknown stats command.");
_stats_help(stats_cmd, NULL, argc, argv, NULL, multiple_devices); _stats_help(stats_cmd, NULL, argc, argv, NULL, multiple_devices);
@ -4993,7 +5059,6 @@ static int _stats(CMD_ARGS)
return 0; return 0;
} }
doit:
if (!stats_cmd->fn(stats_cmd, NULL, argc, argv, NULL, multiple_devices)) if (!stats_cmd->fn(stats_cmd, NULL, argc, argv, NULL, multiple_devices))
return 0; return 0;
@ -5249,29 +5314,29 @@ static int _process_losetup_switches(const char *base, int *argcp, char ***argvp
if (!*argcp) { if (!*argcp) {
fprintf(stderr, "%s: Please specify loop_device.\n", base); fprintf(stderr, "%s: Please specify loop_device.\n", base);
_losetup_usage(stderr); _usage(stderr);
return 0; return 0;
} }
if (!(device_name = parse_loop_device_name((*argvp)[0], dev_dir))) { if (!(device_name = parse_loop_device_name((*argvp)[0], dev_dir))) {
fprintf(stderr, "%s: Could not parse loop_device %s\n", fprintf(stderr, "%s: Could not parse loop_device %s\n",
base, (*argvp)[0]); base, (*argvp)[0]);
_losetup_usage(stderr); _usage(stderr);
return 0; return 0;
} }
if (delete) { if (delete) {
*argcp = 2; *argcp = 1;
(*argvp)[1] = device_name; (*argvp)[0] = device_name;
(*argvp)[0] = (char *) "remove"; _command = "remove";
return 1; return 1;
} }
if (*argcp != 2) { if (*argcp != 2) {
fprintf(stderr, "%s: Too few arguments\n", base); fprintf(stderr, "%s: Too few arguments\n", base);
_losetup_usage(stderr); _usage(stderr);
dm_free(device_name); dm_free(device_name);
return 0; 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]))) { if (!(loop_file = _get_abspath((*argvp)[(find) ? 0 : 1]))) {
fprintf(stderr, "%s: Could not parse loop file name %s\n", fprintf(stderr, "%s: Could not parse loop file name %s\n",
base, (*argvp)[1]); base, (*argvp)[1]);
_losetup_usage(stderr); _usage(stderr);
dm_free(device_name); dm_free(device_name);
return 0; return 0;
} }
@ -5294,8 +5359,9 @@ static int _process_losetup_switches(const char *base, int *argcp, char ***argvp
} }
_switches[TABLE_ARG]++; _switches[TABLE_ARG]++;
(*argvp)[0] = (char *) "create"; _command = "create";
(*argvp)[1] = device_name ; (*argvp)[0] = device_name ;
*argcp = 1;
return 1; return 1;
} }
@ -5349,9 +5415,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
const char *base; const char *base;
char *namebase, *s; char *namebase, *s;
static int ind; static int ind;
int c, r; int c, r, i;
/* "stats" command and sub-command when run as 'dmstats'. */
char *stats_p = NULL, *stats_c = NULL;
#ifdef HAVE_GETOPTLONG #ifdef HAVE_GETOPTLONG
static struct option long_options[] = { 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"); fprintf(stderr, "Failed to duplicate name.\n");
return 0; return 0;
} }
base = dm_basename(namebase); base = dm_basename(namebase);
if (!strcmp(base, "devmap_name")) { 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); free(namebase);
if (_base_command_type == DEVMAP_NAME_TYPE) {
_switches[COLS_ARG]++; _switches[COLS_ARG]++;
_switches[NOHEADINGS_ARG]++; _switches[NOHEADINGS_ARG]++;
_switches[OPTIONS_ARG]++; _switches[OPTIONS_ARG]++;
@ -5455,28 +5530,22 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
*argcp -= 1; *argcp -= 1;
*argvp += 1; *argvp += 1;
} else { } else {
fprintf(stderr, "Usage: devmap_name <major> <minor>\n"); _usage(stderr);
return 0; return 0;
} }
(*argvp)[0] = (char *) "info"; _command = "info";
(*argvp)++;
(*argcp)--;
return 1; return 1;
} }
if (!strcmp(base, LOSETUP_CMD_NAME) || !strcmp(base, DMLOSETUP_CMD_NAME)){ if (_base_command_type == LOSETUP_TYPE) {
r = _process_losetup_switches(base, argcp, argvp, dev_dir); r = _process_losetup_switches(_base_commands[_base_command].name, argcp, argvp, dev_dir);
free(namebase);
return r; 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; optarg = 0;
optind = OPTIND_INIT; optind = OPTIND_INIT;
while ((ind = -1, c = GETOPTLONG_FN(*argcp, *argvp, "cCfG:hj:m:M:no:O:rS:u:U:vy", 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]++; _switches[DEFERRED_ARG]++;
if (ind == EXEC_ARG) { if (ind == EXEC_ARG) {
_switches[EXEC_ARG]++; _switches[EXEC_ARG]++;
_command = optarg; _command_to_exec = optarg;
} }
if (ind == TARGET_ARG) { if (ind == TARGET_ARG) {
_switches[TARGET_ARG]++; _switches[TARGET_ARG]++;
@ -5725,12 +5794,20 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
*argvp += optind; *argvp += optind;
*argcp -= optind; *argcp -= optind;
/* preserve sub-command in argv[0] */ if (!*argcp)
if (stats_p) { _command = NULL;
(*argvp)--; else if (!strcmp((*argvp)[0], "stats")) {
(*argcp)++; _base_command = DMSETUP_STATS_CMD;
(*argvp)[0] = stats_p; _base_command_type = STATS_TYPE;
(*argvp)[1] = stats_c; _command = "stats";
(*argvp)++;
(*argcp)--;
} else if (_base_command == DMSTATS_CMD) {
_command = "stats";
} else if (*argcp) {
_command = (*argvp)[0];
(*argvp)++;
(*argcp)--;
} }
return 1; return 1;
@ -5738,16 +5815,15 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
static int _perform_command_for_all_repeatable_args(CMD_ARGS) 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 { 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"); fprintf(stderr, "Command failed\n");
return 1;
}
} while (cmd->repeatable_cmd && argc > 1);
return 0; return 0;
} }
} while (cmd->repeatable_cmd && argc-- > 1);
return 1;
}
static int _do_report_wait(void) static int _do_report_wait(void)
{ {
@ -5778,50 +5854,54 @@ int main(int argc, char **argv)
goto out; goto out;
} }
/* let stats do its own --help handling. */ if (_switches[HELP_ARG]) {
if (_switches[HELP_ARG] && strcmp("stats", argv[0])) { switch (_base_command_type) {
case STATS_TYPE:
if ((cmd = _find_stats_subcommand("help")))
goto doit;
goto unknown;
default:
if ((cmd = _find_dmsetup_command("help"))) if ((cmd = _find_dmsetup_command("help")))
goto doit; goto doit;
goto unknown; goto unknown;
} }
}
if (_switches[VERSION_ARG]) { if (_switches[VERSION_ARG]) {
switch (_base_command_type) {
case STATS_TYPE:
if ((cmd = _find_stats_subcommand("version")))
goto doit;
goto unknown;
default:
if ((cmd = _find_dmsetup_command("version"))) if ((cmd = _find_dmsetup_command("version")))
goto doit; goto doit;
goto unknown; goto unknown;
} }
}
if (argc == 0) { if (!_command) {
_dmsetup_usage(stderr); _usage(stderr);
goto out; goto out;
} }
if (!(cmd = _find_dmsetup_command(argv[0]))) { if (!(cmd = _find_dmsetup_command(_command))) {
unknown: unknown:
fprintf(stderr, "Unknown command\n"); fprintf(stderr, "Unknown command\n");
_dmsetup_usage(stderr); _usage(stderr);
goto out; goto out;
} }
if (argc < cmd->min_args + 1 || if (argc < cmd->min_args ||
(cmd->max_args >= 0 && argc > cmd->max_args + 1)) { (cmd->max_args >= 0 && argc > cmd->max_args)) {
fprintf(stderr, "Incorrect number of arguments\n"); fprintf(stderr, "Incorrect number of arguments\n");
if (!strcmp(cmd->name, "stats")) _usage(stderr);
_stats_usage(stderr);
else
_dmsetup_usage(stderr);
goto out; goto out;
} }
if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname")) if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname"))
_switches[COLS_ARG]++; _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")) { if (!strcmp(cmd->name, "stats")) {
_switches[COLS_ARG]++; _switches[COLS_ARG]++;
if (!_switches[UNITS_ARG]) { if (!_switches[UNITS_ARG]) {
@ -5865,7 +5945,7 @@ unknown:
* dmsetup <command> <subcommand> [args...] * dmsetup <command> <subcommand> [args...]
*/ */
if (cmd->has_subcommands) { if (cmd->has_subcommands) {
subcommand = argv[1]; subcommand = argv[0];
argc--, argv++; argc--, argv++;
} }
@ -5875,19 +5955,18 @@ unknown:
goto_out; goto_out;
doit: doit:
multiple_devices = (cmd->repeatable_cmd && argc != 2 && multiple_devices = (cmd->repeatable_cmd && argc != 1 &&
(argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG]))); (argc || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
do { do {
r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices); r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
if (_report) { if (_report) {
/* only output headings for repeating reports */ /* 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_column_headings(_report);
dm_report_output(_report); dm_report_output(_report);
if (_count > 1) { if (_count > 1 && r) {
printf("\n"); printf("\n");
/* wait for --interval and update timestamps */ /* wait for --interval and update timestamps */
if (!_do_report_wait()) if (!_do_report_wait())
@ -5895,12 +5974,11 @@ doit:
} }
} }
if (r) if (!r)
break; break;
} while (--_count); } while (--_count);
out: out:
if (_report) if (_report)
dm_report_free(_report); dm_report_free(_report);