1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-30 17:18:21 +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 -
===================================
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.

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);
/*
* 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);
/*

View File

@ -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))

View File

@ -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 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)
{
_stats_usage(stderr);
_usage(stderr);
/**
* 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]) {
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);
}
/* help text already output: don't repeat from main */
dm_report_free(_report);
_report = NULL;
(void) _report_init(cmd);
if (_report) {
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);