diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM index 45db0e446..f3b62b153 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 000000000..9b701f147 --- /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 192fd0f87..303ed673c 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 17a7e13b2..84b129449 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 1dcc7e3b8..b3820fe3c 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 */ +static const char *_command; /* dmsetup */ 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", " []", 0, 2, 0, 0, _load}, {"clear", "", 0, -1, 1, 0, _clear}, {"reload", " []", 0, 2, 0, 0, _load}, - {"wipe_table", "", 0, -1, 1, 0, _error_device}, + {"wipe_table", "", 1, -1, 1, 0, _error_device}, {"rename", " [--setuuid] ", 1, 2, 0, 0, _rename}, {"message", " ", 2, -1, 0, 0, _message}, {"ls", "[--target ] [--exec ] [-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 " \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 ] [--areasize ]\n"); fprintf(out, " [--auxdata ] [--clear]\n"); fprintf(out, " [--count ] [--interval ]\n"); fprintf(out, " [-o ] [-O|--sort ]\n"); - fprintf(out, " [--programid ]\n"); + fprintf(out, " [--programid ]\n"); fprintf(out, " [--start ] [--length ]\n"); fprintf(out, " [--segments] [--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, " may be device name or -u or " "-j -m \n"); fprintf(out, " 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 ]\n" " [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n" @@ -4875,9 +4931,12 @@ static void _dmsetup_usage(FILE *out) " [-y|--yes] [--readahead [+]|auto|none] [--retry]\n" " [-c|-C|--columns] [-o ] [-O|--sort ]\n" " [-S|--select ] [--nameprefixes] [--noheadings]\n" - " [--separator ]\n\n"); + " [--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 may be device name or -u or " "-j -m \n"); fprintf(out, " 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 \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 [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);