1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-30 17:44:21 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
7ce3497889 commands: new method for defining commands
Only a command that conforms to one of the specifications
will be processed.  (LV type conformance is checked after
vg_read and before single_fn processing.)
2016-10-11 09:37:03 -05:00
14 changed files with 7901 additions and 6470 deletions

View File

@@ -89,7 +89,7 @@ struct cmd_context {
*/
const char *cmd_line;
struct command *command;
char **pos_arg_values;
char **argv;
struct arg_values *opt_arg_values;
struct dm_list arg_value_groups;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,215 +17,214 @@
* Put all long args that don't have a corresponding short option first.
*/
/* *INDENT-OFF* */
arg(abort_ARG, '\0', "abort", NULL, 0, 0)
arg(activationmode_ARG, '\0', "activationmode", string_arg, 0, 0)
arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE, 0)
arg(aligned_ARG, '\0', "aligned", NULL, 0, 0)
arg(alloc_ARG, '\0', "alloc", alloc_arg, 0, 0)
arg(atomic_ARG, '\0', "atomic", NULL, 0, 0)
arg(atversion_ARG, '\0', "atversion", string_arg, 0, 0)
arg(binary_ARG, '\0', "binary", NULL, 0, 0)
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", size_mb_arg, 0, 0)
arg(cache_long_ARG, '\0', "cache", NULL, 0, 0)
arg(cachemode_ARG, '\0', "cachemode", cachemode_arg, 0, 0)
arg(cachepool_ARG, '\0', "cachepool", string_arg, 0, 0)
arg(commandprofile_ARG, '\0', "commandprofile", string_arg, 0, 0)
arg(config_ARG, '\0', "config", string_arg, 0, 0)
arg(configreport_ARG, '\0', "configreport", string_arg, ARG_GROUPABLE, 1)
arg(configtype_ARG, '\0', "configtype", string_arg, 0, 0)
arg(corelog_ARG, '\0', "corelog", NULL, 0, 0)
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0, 0)
arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE, 0)
arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0, 0)
arg(discards_ARG, '\0', "discards", discards_arg, 0, 0)
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0, 0)
arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0, 0)
arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE, 0)
arg(foreign_ARG, '\0', "foreign", NULL, 0, 0)
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", NULL, 0, 0)
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0, 0)
arg(ignorelocal_ARG, '\0', "ignorelocal", NULL, 0, 0)
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0, 0)
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0, 0)
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0, 0)
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0, 0)
arg(labelsector_ARG, '\0', "labelsector", int_arg, 0, 0)
arg(lockopt_ARG, '\0', "lockopt", string_arg, 0, 0)
arg(lockstart_ARG, '\0', "lockstart", NULL, 0, 0)
arg(lockstop_ARG, '\0', "lockstop", NULL, 0, 0)
arg(locktype_ARG, '\0', "locktype", locktype_arg, 0, 0)
arg(logonly_ARG, '\0', "logonly", NULL, 0, 0)
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0, 0)
arg(merge_ARG, '\0', "merge", NULL, 0, 0)
arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0, 0)
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0, 0)
arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0, 0)
arg(metadataprofile_ARG, '\0', "metadataprofile", string_arg, 0, 0)
arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0, 0)
arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE, 0)
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0, 0)
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_arg, 0, 0)
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0, 0)
arg(mknodes_ARG, '\0', "mknodes", NULL, 0, 0)
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0, 0)
arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0, 0)
arg(noheadings_ARG, '\0', "noheadings", NULL, 0, 0)
arg(nohistory_ARG, '\0', "nohistory", NULL, 0, 0)
arg(nolocking_ARG, '\0', "nolocking", NULL, 0, 0)
arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0, 0)
arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0, 0)
arg(nosync_ARG, '\0', "nosync", NULL, 0, 0)
arg(notifydbus_ARG, '\0', "notifydbus", NULL, 0, 0)
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0, 0)
arg(originname_ARG, '\0', "originname", string_arg, 0, 0)
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0, 0)
arg(poll_ARG, '\0', "poll", yes_no_arg, 0, 0)
arg(polloperation_ARG, '\0', "polloperation", string_arg, 0, 0)
arg(pooldatasize_ARG, '\0', "pooldatasize", size_mb_arg, 0, 0)
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0, 0)
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0)
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
arg(raidwritebehind_ARG, '\0', "raidwritebehind", int_arg, 0, 0)
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0)
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)
arg(restorefile_ARG, '\0', "restorefile", string_arg, 0, 0)
arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0, 0)
arg(resync_ARG, '\0', "resync", NULL, 0, 0)
arg(rows_ARG, '\0', "rows", NULL, 0, 0)
arg(segments_ARG, '\0', "segments", NULL, 0, 0)
arg(separator_ARG, '\0', "separator", string_arg, 0, 0)
arg(shared_ARG, '\0', "shared", NULL, 0, 0)
arg(sinceversion_ARG, '\0', "sinceversion", string_arg, 0, 0)
arg(split_ARG, '\0', "split", NULL, 0, 0)
arg(splitcache_ARG, '\0', "splitcache", NULL, 0, 0)
arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0, 0)
arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0, 0)
arg(showdeprecated_ARG, '\0', "showdeprecated", NULL, 0, 0)
arg(showunsupported_ARG, '\0', "showunsupported", NULL, 0, 0)
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0, 0)
arg(syncaction_ARG, '\0', "syncaction", string_arg, 0, 0) /* FIXME Use custom validation fn */
arg(sysinit_ARG, '\0', "sysinit", NULL, 0, 0)
arg(systemid_ARG, '\0', "systemid", string_arg, 0, 0)
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0, 0)
arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0, 0)
arg(trustcache_ARG, '\0', "trustcache", NULL, 0, 0)
arg(type_ARG, '\0', "type", segtype_arg, 0, 0)
arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0, 0)
arg(uncache_ARG, '\0', "uncache", NULL, 0, 0)
arg(cachepolicy_ARG, '\0', "cachepolicy", string_arg, 0, 0)
arg(cachesettings_ARG, '\0', "cachesettings", string_arg, ARG_GROUPABLE, 0)
arg(unconfigured_ARG, '\0', "unconfigured", NULL, 0, 0)
arg(units_ARG, '\0', "units", string_arg, 0, 0)
arg(unquoted_ARG, '\0', "unquoted", NULL, 0, 0)
arg(usepolicies_ARG, '\0', "usepolicies", NULL, 0, 0)
arg(validate_ARG, '\0', "validate", NULL, 0, 0)
arg(version_ARG, '\0', "version", NULL, 0, 0)
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0, 0)
arg(withsummary_ARG, '\0', "withsummary", NULL, 0, 0)
arg(withcomments_ARG, '\0', "withcomments", NULL, 0, 0)
arg(withspaces_ARG, '\0', "withspaces", NULL, 0, 0)
arg(withversions_ARG, '\0', "withversions", NULL, 0, 0)
arg(writebehind_ARG, '\0', "writebehind", int_arg, 0, 0)
arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE, 0)
arg(abort_ARG, '\0', "abort", 0, 0, 0)
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
arg(aligned_ARG, '\0', "aligned", 0, 0, 0)
arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0)
arg(atomic_ARG, '\0', "atomic", 0, 0, 0)
arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0)
arg(binary_ARG, '\0', "binary", 0, 0, 0)
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0)
arg(cache_long_ARG, '\0', "cache", 0, 0, 0)
arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
arg(config_ARG, '\0', "config", string_VAL, 0, 0)
arg(configreport_ARG, '\0', "configreport", string_VAL, ARG_GROUPABLE, 1)
arg(configtype_ARG, '\0', "typeconfig", string_VAL, 0, 0)
arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0)
arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0)
arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0)
arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0)
arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0)
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0)
arg(foreign_ARG, '\0', "foreign", 0, 0, 0)
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0)
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0)
arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0)
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0)
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0)
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0)
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0)
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0)
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0)
arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0)
arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0)
arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
arg(merge_ARG, '\0', "merge", 0, 0, 0)
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0)
arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0)
arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0)
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0)
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0)
arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0)
arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0)
arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0)
arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0)
arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0)
arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0)
arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0)
arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0)
arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0)
arg(nosync_ARG, '\0', "nosync", 0, 0, 0)
arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0)
arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
arg(polloperation_ARG, '\0', "polloperation", string_VAL, 0, 0)
arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", number_VAL, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", string_VAL, ARG_GROUPABLE, 0)
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_VAL, 0, 0)
arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_VAL, ARG_GROUPABLE, 0)
arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
arg(repair_ARG, '\0', "repair", 0, 0, 0)
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
arg(reportformat_ARG, '\0', "reportformat", string_VAL, 0, 0)
arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
arg(resync_ARG, '\0', "resync", 0, 0, 0)
arg(rows_ARG, '\0', "rows", 0, 0, 0)
arg(segments_ARG, '\0', "segments", 0, 0, 0)
arg(separator_ARG, '\0', "separator", string_VAL, 0, 0)
arg(shared_ARG, '\0', "shared", 0, 0, 0)
arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0)
arg(split_ARG, '\0', "split", 0, 0, 0)
arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0)
arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0)
arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
arg(syncaction_ARG, '\0', "syncaction", string_VAL, 0, 0) /* FIXME Use custom VAL */
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0)
arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0)
arg(type_ARG, '\0', "type", segtype_VAL, 0, 0)
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0)
arg(uncache_ARG, '\0', "uncache", 0, 0, 0)
arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0)
arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0)
arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0)
arg(units_ARG, '\0', "units", units_VAL, 0, 0)
arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
arg(validate_ARG, '\0', "validate", 0, 0, 0)
arg(version_ARG, '\0', "version", 0, 0, 0)
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_VAL, 0, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
arg(writemostly_ARG, '\0', "writemostly", string_VAL, ARG_GROUPABLE, 0)
/* Allow some variations */
arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0, 0)
arg(available_ARG, '\0', "available", activation_arg, 0, 0)
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0, 0)
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
arg(available_ARG, '\0', "available", activation_VAL, 0, 0)
arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0)
/*
* ... and now the short args.
*/
arg(activate_ARG, 'a', "activate", activation_arg, 0, 0)
arg(all_ARG, 'a', "all", NULL, 0, 0)
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0, 0)
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0, 0)
arg(background_ARG, 'b', "background", NULL, 0, 0)
arg(backgroundfork_ARG, 'b', "background", NULL, 0, 0)
arg(basevgname_ARG, 'n', "basevgname", string_arg, 0, 0)
arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0, 0)
arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0, 0)
arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0, 0)
arg(colon_ARG, 'c', "colon", NULL, 0, 0)
arg(columns_ARG, 'C', "columns", NULL, 0, 0)
arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0, 0)
arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE, 0)
arg(exported_ARG, 'e', "exported", NULL, 0, 0)
arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0, 0)
arg(file_ARG, 'f', "file", string_arg, 0, 0)
arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE, 0)
arg(full_ARG, 'f', "full", NULL, 0, 0)
arg(help_ARG, 'h', "help", NULL, 0, 0)
arg(cache_ARG, 'H', "cache", NULL, 0, 0)
arg(history_ARG, 'H', "history", NULL, 0, 0)
arg(help2_ARG, '?', "", NULL, 0, 0)
arg(import_ARG, 'i', "import", NULL, 0, 0)
arg(interval_ARG, 'i', "interval", int_arg, 0, 0)
arg(iop_version_ARG, 'i', "iop_version", NULL, 0, 0)
arg(stripes_ARG, 'i', "stripes", int_arg, 0, 0)
arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0, 0)
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0, 0)
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0, 0)
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0, 0)
arg(list_ARG, 'l', "list", NULL, 0, 0)
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0, 0)
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0, 0)
arg(size_ARG, 'L', "size", size_mb_arg, 0, 0)
arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0, 0)
arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE, 0)
arg(setactivationskip_ARG, 'k', "setactivationskip", yes_no_arg, 0, 0)
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", NULL, 0, 0)
arg(maps_ARG, 'm', "maps", NULL, 0, 0)
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0, 0)
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0, 0)
arg(name_ARG, 'n', "name", string_arg, 0, 0)
arg(nofsck_ARG, 'n', "nofsck", NULL, 0, 0)
arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0, 0)
arg(oldpath_ARG, 'n', "oldpath", NULL, 0, 0)
arg(options_ARG, 'o', "options", string_arg, ARG_GROUPABLE, 0)
arg(sort_ARG, 'O', "sort", string_arg, ARG_GROUPABLE, 0)
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0, 0)
arg(permission_ARG, 'p', "permission", permission_arg, 0, 0)
arg(partial_ARG, 'P', "partial", NULL, 0, 0)
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0, 0)
arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE, 0)
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0, 0)
arg(resizefs_ARG, 'r', "resizefs", NULL, 0, 0)
arg(reset_ARG, 'R', "reset", NULL, 0, 0)
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0, 0)
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0, 0)
arg(snapshot_ARG, 's', "snapshot", NULL, 0, 0)
arg(short_ARG, 's', "short", NULL, 0, 0)
arg(stdin_ARG, 's', "stdin", NULL, 0, 0)
arg(select_ARG, 'S', "select", string_arg, ARG_GROUPABLE, 0)
arg(test_ARG, 't', "test", NULL, 0, 0)
arg(thin_ARG, 'T', "thin", NULL, 0, 0)
arg(uuid_ARG, 'u', "uuid", NULL, 0, 0)
arg(uuidstr_ARG, 'u', "uuid", string_arg, 0, 0)
arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0, 0)
arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE, 0)
arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0, 0)
arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0, 0)
arg(wipesignatures_ARG, 'W', "wipesignatures", yes_no_arg, 0, 0)
arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0, 0)
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0, 0)
arg(yes_ARG, 'y', "yes", NULL, 0, 0)
arg(zero_ARG, 'Z', "zero", yes_no_arg, 0, 0)
arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0)
arg(all_ARG, 'a', "all", 0, 0, 0)
arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0)
arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0)
arg(background_ARG, 'b', "background", 0, 0, 0)
arg(backgroundfork_ARG, 'b', "background", 0, 0, 0)
arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0)
arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0)
arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0)
arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0)
arg(colon_ARG, 'c', "colon", 0, 0, 0)
arg(columns_ARG, 'C', "columns", 0, 0, 0)
arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0)
arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0)
arg(exported_ARG, 'e', "exported", 0, 0, 0)
arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0)
arg(file_ARG, 'f', "file", string_VAL, 0, 0)
arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0)
arg(full_ARG, 'f', "full", 0, 0, 0)
arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0)
arg(cache_ARG, 'H', "cache", 0, 0, 0)
arg(history_ARG, 'H', "history", 0, 0, 0)
arg(help2_ARG, '?', "", 0, 0, 0)
arg(import_ARG, 'i', "import", 0, 0, 0)
arg(interval_ARG, 'i', "interval", number_VAL, 0, 0)
arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0)
arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0)
arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0)
arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0)
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0)
arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0)
arg(list_ARG, 'l', "list", 0, 0, 0)
arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0)
arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0)
arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0)
arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0)
arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0)
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0)
arg(maps_ARG, 'm', "maps", 0, 0, 0)
arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0)
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0)
arg(name_ARG, 'n', "name", string_VAL, 0, 0)
arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0)
arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0)
arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
arg(partial_ARG, 'P', "partial", 0, 0, 0)
arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0)
arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0)
arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0)
arg(reset_ARG, 'R', "reset", 0, 0, 0)
arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0)
arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0)
arg(snapshot_ARG, 's', "snapshot", 0, 0, 0)
arg(short_ARG, 's', "short", 0, 0, 0)
arg(stdin_ARG, 's', "stdin", 0, 0, 0)
arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0)
arg(test_ARG, 't', "test", 0, 0, 0)
arg(thin_ARG, 'T', "thin", 0, 0, 0)
arg(uuid_ARG, 'u', "uuid", 0, 0, 0)
arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0)
arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0)
arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0)
arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0)
arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0)
arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0)
arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0)
arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0)
arg(yes_ARG, 'y', "yes", 0, 0, 0)
arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0)
/* this should always be last */
arg(ARG_COUNT, '-', "", NULL, 0, 0)
arg(ARG_COUNT, '-', "", 0, 0, 0)
/* *INDENT-ON* */

View File

@@ -1,3 +1,3 @@
/* Do not edit. This file is generated by scripts/create-commands */
/* using command definitions from scripts/command-lines.in */
#define COMMAND_COUNT 144
#define COMMAND_COUNT 146

File diff suppressed because it is too large Load Diff

View File

@@ -32,58 +32,48 @@ typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv);
* The first positional arg has pos_arg.pos of 1.
*/
/* Number of string constants accepted after an option. */
#define MAX_STR_SET 16
/* arg_def flags */
#define ARG_DEF_FLAG_NEW 1
#define ARG_DEF_FLAG_MAY_REPEAT 2
#define ARG_DEF_FLAG_NEW 1 << 0
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
/* arg_def types, can be multiple */
/* arg_def lv_types */
enum {
ARG_DEF_TYPE_NONE = 0,
ARG_DEF_TYPE_BOOL = 1 << 0,
ARG_DEF_TYPE_NUM_ANY = 1 << 1,
ARG_DEF_TYPE_STR_ANY = 1 << 2,
ARG_DEF_TYPE_NUM_CONST = 1 << 3,
ARG_DEF_TYPE_STR_CONST = 1 << 4,
ARG_DEF_TYPE_STR_SET = 1 << 5,
ARG_DEF_TYPE_NAME_ANY = 1 << 6,
ARG_DEF_TYPE_NAME_PV = 1 << 7,
ARG_DEF_TYPE_NAME_VG = 1 << 8,
ARG_DEF_TYPE_NAME_LV = 1 << 9,
ARG_DEF_TYPE_TAG = 1 << 10,
ARG_DEF_TYPE_SELECT = 1 << 11,
ARG_DEF_LV_ANY = 0,
ARG_DEF_LV_LINEAR = 1 << 0,
ARG_DEF_LV_STRIPED = 1 << 1,
ARG_DEF_LV_SNAPSHOT = 1 << 2,
ARG_DEF_LV_MIRROR = 1 << 3,
ARG_DEF_LV_RAID = 1 << 4,
ARG_DEF_LV_RAID0 = 1 << 5,
ARG_DEF_LV_RAID1 = 1 << 6,
ARG_DEF_LV_RAID4 = 1 << 7,
ARG_DEF_LV_RAID5 = 1 << 8,
ARG_DEF_LV_RAID6 = 1 << 9,
ARG_DEF_LV_RAID10 = 1 << 10,
ARG_DEF_LV_THIN = 1 << 11,
ARG_DEF_LV_THINPOOL = 1 << 12,
ARG_DEF_LV_CACHE = 1 << 13,
ARG_DEF_LV_CACHEPOOL = 1 << 14,
ARG_DEF_LV_LAST = 1 << 15,
};
/* arg_def lv_types, can be multiple */
enum {
ARG_DEF_LV_ANY = 0,
ARG_DEF_LV_LINEAR = 1 << 0,
ARG_DEF_LV_STRIPED = 1 << 1,
ARG_DEF_LV_SNAPSHOT = 1 << 2,
ARG_DEF_LV_MIRROR = 1 << 3,
ARG_DEF_LV_RAID = 1 << 4,
ARG_DEF_LV_RAID0 = 1 << 5,
ARG_DEF_LV_RAID1 = 1 << 6,
ARG_DEF_LV_RAID4 = 1 << 7,
ARG_DEF_LV_RAID5 = 1 << 8,
ARG_DEF_LV_RAID6 = 1 << 9,
ARG_DEF_LV_RAID10 = 1 << 10,
ARG_DEF_LV_THIN = 1 << 11,
ARG_DEF_LV_THINPOOL = 1 << 12,
ARG_DEF_LV_CACHE = 1 << 13,
ARG_DEF_LV_CACHEPOOL = 1 << 14,
};
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
{
return (val_bits & (1 << val_enum)) ? 1 : 0;
}
static inline uint64_t val_enum_to_bit(int val_enum)
{
return 1 << val_enum;
}
/* Description a value that follows an option or exists in a position. */
struct arg_def {
uint32_t types; /* ARG_DEF_TYPE_, can be multiple */
uint32_t lv_types; /* ARG_DEF_LV_, can be multiple */
uint64_t num; /* a literal number for ARG_DEF_TYPE_NUM_CONST */
const char *str; /* a literal string for ARG_DEF_TYPE_STR_CONST */
const char *str_set[MAX_STR_SET]; /* literal strings for ARG_DEF_TYPE_STR_SET */
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
uint64_t num; /* a literal number for conststr_VAL */
const char *str; /* a literal string for constnum_VAL */
uint32_t lv_types; /* ARG_DEF_LV_, for lv_VAL, can be multiple */
uint32_t flags; /* ARG_DEF_FLAG_ */
};
@@ -120,11 +110,14 @@ struct pos_arg {
/* a register of the lvm commands */
struct command {
const char *name;
const char *desc;
const char *usage;
const char *desc; /* specific command description from command-lines.h */
const char *usage; /* excludes common options like --help, --debug */
const char *usage_common; /* includes commmon options like --help, --debug */
struct command_name *cname;
command_fn fn;
unsigned int flags;
unsigned int flags; /* copied from command_name.flags from commands.h */
unsigned int cmd_flags; /* CMD_FLAG_ */
@@ -151,4 +144,14 @@ struct command {
int pos_count;
};
struct command_name {
const char *name;
const char *desc; /* general command description from commands.h */
unsigned int flags;
/* union of {required,optional}_opt_args for all commands with this name */
int valid_args[ARG_COUNT];
int num_args;
};
#endif

View File

@@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state)
len = strlen(text);
}
while (i < _cmdline->num_commands)
if (!strncmp(text, _cmdline->commands[i++].name, len))
return strdup(_cmdline->commands[i - 1].name);
while (i < _cmdline->num_command_names)
if (!strncmp(text, _cmdline->command_names[i++].name, len))
return strdup(_cmdline->command_names[i - 1].name);
return NULL;
}
@@ -55,51 +55,50 @@ static char *_list_cmds(const char *text, int state)
/* List matching arguments */
static char *_list_args(const char *text, int state)
{
#if 0 /* FIXME: just go through args.h */
static int match_no = 0;
static size_t len = 0;
static struct command *com;
static struct command_name *cname;
/* Initialise if this is a new completion attempt */
if (!state) {
char *s = rl_line_buffer;
int j;
match_no = 0;
com = NULL;
cname = NULL;
len = strlen(text);
/* Find start of first word in line buffer */
while (isspace(*s))
s++;
/* Look for word in list of commands */
for (j = 0; j < _cmdline->num_commands; j++) {
/* Look for word in list of command names */
for (j = 0; j < _cmdline->num_command_names; j++) {
const char *p;
char *q = s;
p = _cmdline->commands[j].name;
p = _cmdline->command_names[j].name;
while (*p == *q) {
p++;
q++;
}
if ((!*p) && *q == ' ') {
com = _cmdline->commands + j;
cname = _cmdline->command_names + j;
break;
}
}
}
if (!com)
if (!cname)
return NULL;
/* Short form arguments */
if (len < 3) {
while (match_no < com->num_args) {
while (match_no < cname->num_args) {
char s[3];
char c;
if (!(c = (_cmdline->arg_props +
com->valid_args[match_no++])->short_arg))
cname->valid_args[match_no++])->short_arg))
continue;
sprintf(s, "-%c", c);
@@ -109,17 +108,17 @@ static char *_list_args(const char *text, int state)
}
/* Long form arguments */
if (match_no < com->num_args)
match_no = com->num_args;
if (match_no < cname->num_args)
match_no = cname->num_args;
while (match_no - com->num_args < com->num_args) {
while (match_no - cname->num_args < cname->num_args) {
const char *l;
l = (_cmdline->arg_props +
com->valid_args[match_no++ - com->num_args])->long_arg;
cname->valid_args[match_no++ - cname->num_args])->long_arg;
if (*(l + 2) && !strncmp(text, l, len))
return strdup(l);
}
#endif
return NULL;
}

View File

@@ -19,9 +19,11 @@
struct cmd_context;
struct cmdline_context {
struct arg_props *arg_props;
struct command *commands;
int num_commands;
struct arg_props *arg_props;
struct command *commands;
int num_commands;
struct command_name *command_names;
int num_command_names;
};
int lvm2_main(int argc, char **argv);

View File

@@ -57,7 +57,7 @@ int lvm2_run(void *handle, const char *cmdline)
cmd = (struct cmd_context *) handle;
cmd->pos_arg_values = argv;
cmd->argv = argv;
if (!(cmdcopy = dm_strdup(cmdline))) {
log_error("Cmdline copy failed.");

View File

@@ -52,7 +52,16 @@ extern char *optarg;
#include "command-lines-count.h" /* #define COMMAND_COUNT, generated from command-lines.in */
/*
* Table of valid switches
* Table of valid --option values.
*/
static struct val_props _val_props[VAL_COUNT + 1] = {
#define val(a, b, c, d) {a, b, c, d},
#include "vals.h"
#undef val
};
/*
* Table of valid --option's
*/
static struct arg_props _arg_props[ARG_COUNT + 1] = {
#define arg(a, b, c, d, e, f) {a, b, "", "--" c, d, e, f},
@@ -64,12 +73,6 @@ static struct arg_props _arg_props[ARG_COUNT + 1] = {
* Table of valid command names
*/
#define MAX_COMMAND_NAMES 64
struct command_name {
const char *name;
const char *desc;
unsigned int flags;
};
struct command_name command_names[MAX_COMMAND_NAMES] = {
#define xx(a, b, c...) { # a, b, c },
#include "commands.h"
@@ -731,6 +734,46 @@ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
return int_arg(cmd, av);
}
/*
* The valid args for a command name in general is a union of
* required_opt_args and optional_opt_args for all commands[]
* with the given name.
*/
static void _set_valid_args_for_command_name(int ci)
{
int all_args[ARG_COUNT] = { 0 };
int num_args = 0;
int opt_enum; /* foo_ARG from args.h */
int i, ro, oo;
/*
* all_args is indexed by the foo_ARG enum vals
*/
for (i = 0; i < COMMAND_COUNT; i++) {
if (strcmp(commands[i].name, command_names[ci].name))
continue;
for (ro = 0; ro < commands[i].ro_count; ro++) {
opt_enum = commands[i].required_opt_args[ro].opt;
all_args[opt_enum] = 1;
}
for (oo = 0; oo < commands[i].oo_count; oo++) {
opt_enum = commands[i].optional_opt_args[oo].opt;
all_args[opt_enum] = 1;
}
}
for (i = 0; i < ARG_COUNT; i++) {
if (all_args[i]) {
command_names[ci].valid_args[num_args] = _cmdline.arg_props[i].arg_enum;
num_args++;
}
}
command_names[ci].num_args = num_args;
}
static struct command_name *_find_command_name(const char *name)
{
int i;
@@ -765,8 +808,20 @@ void lvm_register_commands(void)
for (i = 0; i < COMMAND_COUNT; i++) {
if (!(cname = _find_command_name(commands[i].name)))
log_error(INTERNAL_ERROR "Failed to find command name %s.", commands[i].name);
commands[i].cname = cname;
commands[i].flags = cname->flags;
}
_cmdline.command_names = command_names;
for (i = 0; i < MAX_COMMAND_NAMES; i++) {
if (!command_names[i].name)
break;
_cmdline.num_command_names++;
}
for (i = 0; i < _cmdline.num_command_names; i++)
_set_valid_args_for_command_name(i);
}
/*
@@ -787,8 +842,8 @@ void lvm_register_commands(void)
* any one item from commands[i].required_opt_args needs to be
* set to match.
*
* required_pos_args[0].flags & ARG_DEF_TYPE_SELECT means
* cmd->pos_arg_values[0] can be NULL if arg_is_set(select_ARG)
* required_pos_args[0].types & select_VAL means
* cmd->argv[] in that pos can be NULL if arg_is_set(select_ARG)
*/
static int _opt_equivalent_is_set(struct cmd_context *cmd, int opt)
@@ -831,32 +886,64 @@ static int _opt_equivalent_is_set(struct cmd_context *cmd, int opt)
static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro)
{
if (arg_is_set(cmd, commands[ci].required_opt_args[ro].opt))
return 1;
int opt_enum = commands[ci].required_opt_args[ro].opt;
if (arg_is_set(cmd, opt_enum))
goto check_val;
/*
* For some commands, --size and --extents are interchanable,
* For some commands, --size and --extents are interchangable,
* but command[] definitions use only --size.
*/
if ((commands[ci].required_opt_args[ro].opt == size_ARG) && arg_is_set(cmd, extents_ARG)) {
if ((opt_enum == size_ARG) && arg_is_set(cmd, extents_ARG)) {
if (!strcmp(commands[ci].name, "lvcreate") ||
!strcmp(commands[ci].name, "lvresize") ||
!strcmp(commands[ci].name, "lvextend") ||
!strcmp(commands[ci].name, "lvreduce"))
return 1;
goto check_val;
}
/* TODO: for lvmconfig, recognize --type in place of --typeconfig? */
if (_opt_equivalent_is_set(cmd, commands[ci].required_opt_args[ro].opt))
return 1;
if (_opt_equivalent_is_set(cmd, opt_enum))
goto check_val;
return 0;
/*
* If the definition requires a literal string or number, check
* that the arg value matches.
*/
check_val:
if (val_bit_is_set(commands[ci].required_opt_args[ro].def.val_bits, conststr_VAL)) {
if (!strcmp(commands[ci].required_opt_args[ro].def.str, arg_str_value(cmd, opt_enum, "")))
return 1;
/* Special case: "raid0" (any raid<N>), matches command def "raid" */
if (!strcmp(commands[ci].required_opt_args[ro].def.str, "raid") &&
!strncmp(arg_str_value(cmd, opt_enum, ""), "raid", 4))
return 1;
return 0;
}
if (val_bit_is_set(commands[ci].required_opt_args[ro].def.val_bits, constnum_VAL)) {
if (commands[ci].required_opt_args[ro].def.num == arg_int_value(cmd, opt_enum, 0))
return 1;
return 0;
}
return 1;
}
static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp)
static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp, char **argv)
{
if (cmd->pos_arg_values[rp]) {
/*
* rp is the index in required_pos_args[] of the required positional arg.
* The pos values begin with 1, so the first positional arg has
* pos 1, rp 0.
*/
if (argv[rp]) {
/* FIXME: can we match object type better than just checking something exists? */
/* Some cases could be validated by looking at defs.types and at the value. */
return 1;
@@ -866,22 +953,201 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp
* If Select is specified as a pos arg, then that pos arg can be
* empty if --select is used.
*/
if ((commands[ci].required_pos_args[rp].def.types & ARG_DEF_TYPE_SELECT) &&
if ((val_bit_is_set(commands[ci].required_pos_args[rp].def.val_bits, select_VAL)) &&
arg_is_set(cmd, select_ARG))
return 1;
return 0;
}
static struct command *_find_command(struct cmd_context *cmd, const char *path)
#define HELP_LINE_SIZE 1024
static void _print_usage(const char *usage, int only_required)
{
char buf[HELP_LINE_SIZE];
int optional_ui = 0;
int optional_pos_ui = 0;
int ui;
int bi;
if (!usage || !strlen(usage))
return;
/*
* copy the required opt_args/pos_args
*
* The optional portions of the usage string are enclosed
* in [] and follow the required portions.
*
* The optional portion begins with [ followed by a space,
* i.e. "[ " to distinguish the option usage which may
* include [ in cases like --option Number[units].
*/
memset(buf, 0, sizeof(buf));
bi = 0;
for (ui = 0; ui < strlen(usage); ui++) {
if (!bi && ((usage[ui] == ' ') || (usage[ui] == '\n')))
continue;
/* The first "[ " indicates the start of the optional opt_args. */
if ((usage[ui] == '[') && (usage[ui+1] == ' ')) {
optional_ui = ui;
break;
}
if (usage[ui] == '\0')
break;
buf[bi++] = usage[ui];
if (usage[ui] == ',') {
buf[bi++] = '\n';
buf[bi++] = '\t';
buf[bi++] = ' ';
}
if (bi == (HELP_LINE_SIZE - 1))
break;
}
/*
* print the required opt_args/pos_args
*/
if (bi)
log_print("%s", buf);
if (only_required)
return;
/*
* copy the optional opt_args
*/
if (!optional_ui)
goto out;
memset(buf, 0, sizeof(buf));
bi = 0;
for (ui = optional_ui; ui < strlen(usage); ui++) {
/* The second "[ " indicates the start of the optional pos_args. */
if ((ui > optional_ui) && (usage[ui] == '[') && (usage[ui+1] == ' ')) {
optional_pos_ui = ui;
break;
}
if (usage[ui] == '\0')
break;
if (usage[ui] == '\n')
break;
if (!bi)
buf[bi++] = '\t';
buf[bi++] = usage[ui];
if (usage[ui] == ',') {
buf[bi++] = '\n';
buf[bi++] = '\t';
buf[bi++] = ' ';
}
if (bi == (HELP_LINE_SIZE - 1))
break;
}
/*
* print the optional opt_args
*/
if (bi)
log_print("%s", buf);
/*
* copy the optional pos_args
*/
if (!optional_pos_ui)
goto out;
memset(buf, 0, sizeof(buf));
bi = 0;
for (ui = optional_pos_ui; ui < strlen(usage); ui++) {
if (usage[ui] == '\0')
break;
if (usage[ui] == '\n')
break;
if (!bi)
buf[bi++] = '\t';
buf[bi++] = usage[ui];
if (bi == (HELP_LINE_SIZE - 1))
break;
}
/*
* print the optional pos_args
*/
if (bi)
log_print("%s", buf);
out:
return;
}
static void _print_description(int ci)
{
const char *desc = _cmdline.commands[ci].desc;
char buf[HELP_LINE_SIZE] = {0};
int di = 0;
int bi = 0;
for (di = 0; di < strlen(desc); di++) {
if (desc[di] == '\0')
break;
if (desc[di] == '\n')
continue;
if (!strncmp(&desc[di], "DESC:", 5)) {
if (bi) {
log_print("%s", buf);
memset(buf, 0, sizeof(buf));
bi = 0;
}
di += 5;
continue;
}
if (!bi && desc[di] == ' ')
continue;
buf[bi++] = desc[di];
if (bi == (HELP_LINE_SIZE - 1))
break;
}
if (bi)
log_print("%s", buf);
}
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
{
const char *name;
int match_count, mismatch_count;
int best_match_i = 0, best_match_count = 0;
int closest_i = 0, closest_count = 0;
int ro_matches;
int match_count, match_count_ro, match_count_rp, mismatch_count;
int best_i = 0, best_count = 0;
int closest_i = 0, closest_count_ro = 0;
int ro, rp;
int i;
int i, j;
int accepted, count;
name = last_path_component(path);
@@ -889,16 +1155,19 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path)
if (strcmp(name, commands[i].name))
continue;
match_count = 0;
mismatch_count = 0;
ro_matches = 0;
/* For help and version just return the first entry with matching name. */
if (arg_is_set(cmd, help_ARG) || arg_is_set(cmd, help2_ARG) || arg_is_set(cmd, version_ARG))
return &commands[i];
match_count = 0; /* total parameters that match */
match_count_ro = 0; /* required opt_args that match */
match_count_rp = 0; /* required pos_args that match */
mismatch_count = 0; /* total parameters that do not match */
/* if the command name alone is enough, then that's a match */
if (!commands[i].ro_count && !commands[i].rp_count) {
/* log_warn("match %d command name %s", i, name); */
if (!commands[i].ro_count && !commands[i].rp_count)
match_count = 1;
}
/* match required_opt_args */
@@ -906,7 +1175,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path)
if (_command_required_opt_matches(cmd, i, ro)) {
/* log_warn("match %d ro opt %d", i, commands[i].required_opt_args[ro].opt); */
match_count++;
ro_matches++;
match_count_ro++;
} else {
/* cmd is missing a required opt arg */
/* log_warn("mismatch %d ro opt %d", i, commands[i].required_opt_args[ro].opt); */
@@ -919,7 +1188,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path)
* if one required_opt_arg did match.
*/
if (commands[i].cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) {
if (ro_matches) {
if (match_count_ro) {
/* one or more of the required_opt_args is used */
mismatch_count = 0;
} else {
@@ -931,9 +1200,10 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path)
/* match required_pos_args */
for (rp = 0; rp < commands[i].rp_count; rp++) {
if (_command_required_pos_matches(cmd, i, rp)) {
if (_command_required_pos_matches(cmd, i, rp, argv)) {
/* log_warn("match %d rp %d", i, commands[i].required_pos_args[rp].pos); */
match_count++;
match_count_rp++;
} else {
/* cmd is missing a required pos arg */
/* log_warn("mismatch %d rp %d", i, commands[i].required_pos_args[rp].pos); */
@@ -944,45 +1214,140 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path)
/* if cmd is missing any required opt/pos args, it can't be this command. */
if (mismatch_count) {
/* save i/match_count for "closest" command that doesn't match */
if (!closest_count || (match_count > closest_count)) {
/* save "closest" command that doesn't match */
if (match_count_ro && (match_count_ro > closest_count_ro)) {
closest_i = i;
closest_count = match_count;
closest_count_ro = match_count_ro;
}
continue;
}
/* use command that has the most matching required opt/pos */
if (!match_count)
continue;
if (!best_match_count || (match_count > best_match_count)) {
/* log_warn("match best i %d count %d", i, match_count); */
best_match_i = i;
best_match_count = match_count;
/* Count the command name as a match if all the required opt/pos args match. */
if ((commands[i].ro_count || commands[i].rp_count) &&
(match_count_ro || match_count_rp))
match_count++;
/* log_warn("command %d has match_count %d match_ro %d match_rp %d",
i, match_count, match_count_ro, match_count_rp); */
/*
* Choose the best match, which in general is the command with
* the most matching required_{opt,pos}.
*/
if (!best_count || (match_count > best_count)) {
/* log_warn("best %d has match_count %d match_ro %d match_rp %d",
i, match_count, match_count_ro, match_count_rp); */
best_i = i;
best_count = match_count;
}
}
if (!best_match_count) {
if (!best_count) {
/* cmd did not have all the required opt/pos args of any command */
log_error("Failed to find a matching command definition.");
if (closest_count) {
if (closest_count_ro) {
log_warn("Closest command usage is:");
/* FIXME: _print_usage_required(commands[closest_i].usage); with new lines, aligned, etc */
log_warn("%s", commands[closest_i].usage);
_print_usage(_cmdline.commands[closest_i].usage, 1);
}
return NULL;
}
/*
* Check if all arg_is_set values from cmd are accepted as
* optional_opt_args, and warn (or fail per config?) if options are set
* in cmd that are not accepted by the chosen command[i].
*
* Same for pos args.
* FIXME: should there be a config setting to fail the command if an
* unused option or pos arg is set? Or a user prompt to continue or
* not without the ignored args? There are ad hoc checks in various
* commands to fail sometimes if an unused option or pos arg is set.
* Does this mean a per-command flag is needed to determine if that
* command ignores or fails with unused args? e.g. "pvscan vg" would
* fail based on the vg arg, but now it's just ignored.
*/
/* log_warn("command matched: %.256s ...", commands[best_match_i].usage); */
/*
* Warn about options that are set but are not used by the command.
*/
return &commands[best_match_i];
for (i = 0; i < ARG_COUNT; i++) {
if (!arg_is_set(cmd, i))
continue;
accepted = 0;
/* NB in some cases required_opt_args are optional */
for (j = 0; j < commands[best_i].ro_count; j++) {
if (commands[best_i].required_opt_args[j].opt == i) {
accepted = 1;
break;
}
}
if (accepted)
continue;
for (j = 0; j < commands[best_i].oo_count; j++) {
if (commands[best_i].optional_opt_args[j].opt == i) {
accepted = 1;
break;
}
}
/*
* --type is one option that when set but not accepted by the
* command, will not be ignored to make a match. Perhaps there
* are others like this, and perhaps this is a property that
* should be encoded in args.h?
*/
if (!accepted && (i == type_ARG)) {
log_error("Failed to find a matching command definition with --type.");
return NULL;
}
if (!accepted) {
log_warn("Ignoring option which is not used by the specified command: %s.",
arg_long_option_name(i));
/* clear so it can't be used when processing. */
cmd->opt_arg_values[i].count = 0;
cmd->opt_arg_values[i].value = NULL;
}
}
/*
* Warn about positional args that are set but are not used by the command.
*
* If the last required_pos_arg or the last optional_pos_arg may repeat,
* then there won't be unused positional args.
*
* Otherwise, warn about positional args that exist beyond the number of
* required + optional pos_args.
*/
count = commands[best_i].rp_count;
if (count && (commands[best_i].required_pos_args[count - 1].def.flags & ARG_DEF_FLAG_MAY_REPEAT))
goto out;
count = commands[best_i].op_count;
if (count && (commands[best_i].optional_pos_args[count - 1].def.flags & ARG_DEF_FLAG_MAY_REPEAT))
goto out;
for (count = 0; ; count++) {
if (!argv[count])
break;
if (count >= (commands[best_i].rp_count + commands[best_i].op_count)) {
log_warn("Ignoring positional argument which is not used by this command: %s.", argv[count]);
/* clear so it can't be used when processing. */
argv[count] = NULL;
(*argc)--;
}
}
out:
log_debug("Command definition (%d): %s", best_i, commands[best_i].usage);
return &commands[best_i];
}
static void _short_usage(const char *name)
@@ -990,18 +1355,61 @@ static void _short_usage(const char *name)
log_error("Run `%s --help' for more information.", name);
}
static int _usage(const char *name)
static int _usage(const char *name, int help_count)
{
struct command_name *cname = _find_command_name(name);
const char *usage_common = NULL;
int i;
if (!cname) {
log_print("%s: no such command.", name);
return 0;
}
/* FIXME: print usage strings from matching commands[] entries? */
log_print("%s - %s\n", name, cname->desc);
for (i = 0; i < _cmdline.num_commands; i++) {
if (strcmp(_cmdline.commands[i].name, name))
continue;
if (strlen(_cmdline.commands[i].desc))
_print_description(i);
usage_common = _cmdline.commands[i].usage_common;
_print_usage(_cmdline.commands[i].usage, 0);
log_print(" "); /* for built-in \n */
}
/* Common options are printed once for all variants of a command name. */
if (usage_common) {
log_print("Common options:");
_print_usage(usage_common, 0);
log_print(" "); /* for built-in \n */
}
if (help_count > 1) {
/*
* Excluding commonly understood syntax style like the meanings of:
* [ ] for optional, ... for repeatable, | for one of the following,
* -- for an option name, lower case strings and digits for literals.
*/
log_print("Usage notes:");
log_print(". Variable parameters are: Number, String, PV, VG, LV, Tag.");
log_print(". Select indicates that a required positional parameter can");
log_print(" be omitted if the --select option is used.");
log_print(". --size Number can be replaced with --extents NumberExtents.");
log_print(". --name is usually specified for lvcreate, but is not among");
log_print(" the required parameters because names can be generated.");
log_print(". For required options listed in parentheses, e.g. (--A, --B),");
log_print(" any one is required, after which the others are optional.");
log_print(". The _new suffix indicates the VG or LV must not yet exist.");
log_print(". LV followed by _<type> indicates that an LV of the given type");
log_print(" is required. (raid represents any raid<N> type.)");
log_print(". See man pages for short option equivalents of long option names,");
log_print(" and for more detailed descriptions of variable parameters.");
}
log_print("%s: %s", cname->name, cname->desc);
return 1;
}
@@ -1038,7 +1446,7 @@ static void _add_getopt_arg(int arg_enum, char **optstrp, struct option **longop
if (a->short_arg) {
*(*optstrp)++ = a->short_arg;
if (a->fn)
if (a->val_enum)
*(*optstrp)++ = ':';
}
#ifdef HAVE_GETOPTLONG
@@ -1046,7 +1454,7 @@ static void _add_getopt_arg(int arg_enum, char **optstrp, struct option **longop
if (*(a->long_arg + 2)) {
(*longoptsp)->name = a->long_arg + 2;
(*longoptsp)->has_arg = a->fn ? 1 : 0;
(*longoptsp)->has_arg = a->val_enum ? 1 : 0;
(*longoptsp)->flag = NULL;
/*
@@ -1071,35 +1479,63 @@ static void _add_getopt_arg(int arg_enum, char **optstrp, struct option **longop
#endif
}
static int _find_arg(int goval)
/*
* getopt_long() has returned goval which indicates which option it's found.
* We need to translate that goval to an enum value from the args array.
*
* For options with both long and short forms, goval is the character value
* of the short option. For options with only a long form, goval is the
* corresponding enum value plus 128.
*
* The trick with character values is that different long options share the
* same single-letter short form. So, we have to translate goval to an
* enum using only the set of valid options for the given command. And,
* a command name is not allowed to use two different long options that
* have the same single-letter short form.
*/
static int _find_arg(const char *cmd_name, int goval)
{
struct command_name *cname;
int arg_enum;
int i;
for (i = 0; i < ARG_COUNT; i++) {
if (!(cname = _find_command_name(cmd_name)))
return -1;
for (i = 0; i < cname->num_args; i++) {
arg_enum = cname->valid_args[i];
/* assert arg_enum == _cmdline.arg_props[arg_enum].arg_enum */
/* the value returned by getopt matches the ascii value of single letter option */
if (_cmdline.arg_props[i].short_arg && (goval == _cmdline.arg_props[i].short_arg))
return _cmdline.arg_props[i].enum_val;
if (_cmdline.arg_props[arg_enum].short_arg && (goval == _cmdline.arg_props[arg_enum].short_arg))
return arg_enum;
/* the value returned by getopt matches the enum value plus 128 */
if (!_cmdline.arg_props[i].short_arg && (goval == _cmdline.arg_props[i].enum_val + 128))
return _cmdline.arg_props[i].enum_val;
if (!_cmdline.arg_props[arg_enum].short_arg && (goval == (arg_enum + 128)))
return arg_enum;
}
return -1;
}
static int _process_command_line(struct cmd_context *cmd, int *argc,
char ***argv)
static int _process_command_line(struct cmd_context *cmd, const char *cmd_name,
int *argc, char ***argv)
{
char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str;
struct option opts[ARG_COUNT + 1], *o = opts;
struct arg_props *a;
struct arg_values *av;
struct arg_value_group_list *current_group = NULL;
struct command_name *cname;
int arg_enum; /* e.g. foo_ARG */
int goval; /* the number returned from getopt_long identifying what it found */
int i;
if (!(cname = _find_command_name(cmd_name)))
return_0;
if (!(cmd->opt_arg_values = dm_pool_zalloc(cmd->mem, sizeof(*cmd->opt_arg_values) * ARG_COUNT))) {
log_fatal("Unable to allocate memory for command line arguments.");
return 0;
@@ -1110,13 +1546,12 @@ static int _process_command_line(struct cmd_context *cmd, int *argc,
* array (opts) to pass to the getopt_long() function. IOW we generate
* the arguments to pass to getopt_long() from the args.h/arg_props data.
*/
for (i = 0; i < ARG_COUNT; i++)
_add_getopt_arg(_cmdline.arg_props[i].enum_val, &ptr, &o);
for (i = 0; i < cname->num_args; i++)
_add_getopt_arg(cname->valid_args[i], &ptr, &o);
*ptr = '\0';
memset(o, 0, sizeof(*o));
/* initialise getopt_long & scan for command line switches */
optarg = 0;
optind = OPTIND_INIT;
while ((goval = GETOPTLONG_FN(*argc, *argv, str, opts, NULL)) >= 0) {
@@ -1126,9 +1561,9 @@ static int _process_command_line(struct cmd_context *cmd, int *argc,
/*
* translate the option value used by getopt into the enum
* value (e.g. foo_ARG) from the args array....
* value (e.g. foo_ARG) from the args array.
*/
if ((arg_enum = _find_arg(goval)) < 0) {
if ((arg_enum = _find_arg(cmd_name, goval)) < 0) {
log_fatal("Unrecognised option.");
return 0;
}
@@ -1170,7 +1605,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc,
return 0;
}
if (a->fn) {
if (a->val_enum) {
if (!optarg) {
log_error("Option requires argument.");
return 0;
@@ -1178,7 +1613,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc,
av->value = optarg;
if (!a->fn(cmd, av)) {
if (!_val_props[a->val_enum].fn(cmd, av)) {
log_error("Invalid argument for %s: %s", a->long_arg, optarg);
return 0;
}
@@ -1262,15 +1697,10 @@ int version(struct cmd_context *cmd __attribute__((unused)),
return ECMD_PROCESSED;
}
static int _get_settings(struct cmd_context *cmd)
static void _get_output_settings(struct cmd_context *cmd)
{
const char *activation_mode;
cmd->current_settings = cmd->default_settings;
if (arg_is_set(cmd, debug_ARG))
cmd->current_settings.debug = _LOG_FATAL +
(arg_count(cmd, debug_ARG) - 1);
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
if (arg_is_set(cmd, verbose_ARG))
cmd->current_settings.verbose = arg_count(cmd, verbose_ARG);
@@ -1280,6 +1710,19 @@ static int _get_settings(struct cmd_context *cmd)
cmd->current_settings.verbose = 0;
cmd->current_settings.silent = (arg_count(cmd, quiet_ARG) > 1) ? 1 : 0;
}
}
static void _apply_output_settings(struct cmd_context *cmd)
{
init_debug(cmd->current_settings.debug);
init_debug_classes_logged(cmd->default_settings.debug_classes);
init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
init_silent(cmd->current_settings.silent);
}
static int _get_settings(struct cmd_context *cmd)
{
const char *activation_mode;
if (arg_is_set(cmd, test_ARG))
cmd->current_settings.test = arg_is_set(cmd, test_ARG);
@@ -1406,7 +1849,10 @@ static int _get_settings(struct cmd_context *cmd)
static int _process_common_commands(struct cmd_context *cmd)
{
if (arg_is_set(cmd, help_ARG) || arg_is_set(cmd, help2_ARG)) {
_usage(cmd->command->name);
_usage(cmd->command->name, arg_count(cmd, help_ARG));
if (arg_count(cmd, help_ARG) < 2)
log_print("(Use --help --help for usage notes.)");
return ECMD_PROCESSED;
}
@@ -1426,10 +1872,10 @@ static void _display_help(void)
log_error("Use 'lvm help <command>' for more information");
log_error(" ");
for (i = 0; i < _cmdline.num_commands; i++) {
struct command *com = _cmdline.commands + i;
for (i = 0; i < _cmdline.num_command_names; i++) {
struct command_name *cname = _cmdline.command_names + i;
log_error("%-16.16s%s", com->name, com->desc);
log_error("%-16.16s%s", cname->name, cname->desc);
}
}
@@ -1442,7 +1888,7 @@ int help(struct cmd_context *cmd __attribute__((unused)), int argc, char **argv)
else {
int i;
for (i = 0; i < argc; i++)
if (!_usage(argv[i]))
if (!_usage(argv[i], 0))
ret = EINVALID_CMD_LINE;
}
@@ -1451,10 +1897,6 @@ int help(struct cmd_context *cmd __attribute__((unused)), int argc, char **argv)
static void _apply_settings(struct cmd_context *cmd)
{
init_debug(cmd->current_settings.debug);
init_debug_classes_logged(cmd->default_settings.debug_classes);
init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
init_silent(cmd->current_settings.silent);
init_test(cmd->current_settings.test);
init_full_scan_done(0);
init_mirror_in_sync(0);
@@ -1769,18 +2211,28 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
*arg_new = '\0';
}
/* The cmd_line string is only used for logging, not processing. */
if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv)))
return_ECMD_FAILED;
log_debug("Parsing: %s", cmd->cmd_line);
if (!_process_command_line(cmd, &argc, &argv)) {
if (!_process_command_line(cmd, cmd_name, &argc, &argv)) {
log_error("Error during parsing of command line.");
return EINVALID_CMD_LINE;
}
if (!(cmd->command = _find_command(cmd, cmd_name)))
return ENO_SUCH_CMD;
/*
* log_debug() can be enabled now that we know the settings
* from the command. Previous calls to log_debug() will
* do nothing.
*/
cmd->current_settings = cmd->default_settings;
_get_output_settings(cmd);
_apply_output_settings(cmd);
log_debug("Parsing: %s", cmd->cmd_line);
if (!(cmd->command = _find_command(cmd, cmd_name, &argc, argv)))
return_ECMD_FAILED;
set_cmd_name(cmd_name);
@@ -2408,7 +2860,7 @@ int lvm2_main(int argc, char **argv)
if (!(cmd = init_lvm(0, 0)))
return -1;
cmd->pos_arg_values = argv;
cmd->argv = argv;
lvm_register_commands();

View File

@@ -105,7 +105,7 @@ int become_daemon(struct cmd_context *cmd, int skip_lvm)
init_verbose(VERBOSE_BASE_LEVEL);
#endif /* DEBUG_CHILD */
strncpy(*cmd->pos_arg_values, "(lvm2)", strlen(*cmd->pos_arg_values));
strncpy(*cmd->argv, "(lvm2)", strlen(*cmd->argv));
lvmetad_disconnect();
@@ -2346,8 +2346,12 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
struct dm_str_list *sl;
struct dm_list final_lvs;
struct lv_list *final_lvl;
struct dm_list found_arg_lvnames;
struct glv_list *glvl, *tglvl;
int do_report_ret_code = 1;
uint32_t lv_types;
struct logical_volume *lv;
struct lv_segment *seg;
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
@@ -2356,6 +2360,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
stack;
dm_list_init(&final_lvs);
dm_list_init(&found_arg_lvnames);
if (!vg_check_status(vg, EXPORTED_VG)) {
ret_max = ECMD_FAILED;
@@ -2449,6 +2454,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) {
/* Remove LV from list of unprocessed LV names */
str_list_del(arg_lvnames, lvl->lv->name);
str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name);
process_lv = 1;
}
@@ -2496,6 +2502,64 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
if (lv_is_removed(lvl->lv))
continue;
/*
* If the command definition specifies one required positional
* LV (possibly repeatable), and specifies accepted LV types,
* then verify that the LV being processed matches one of those
* types.
*
* process_each_lv() can only be used for commands that have
* one positional LV arg (optionally repeating, where each is
* processed independently.) It cannot work for commands that
* have different required LVs in designated positions, like
* 'lvrename LV1 LV2', where each LV is not processed
* independently. That means that this LV type check only
* needs to check the lv_type of the first positional arg.
*
* There is one command that violates this rule by stealing
* the first positional LV arg before calling process_each_lv:
* lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
* This code cannot validate that case. process_each_lv() sees
* a single LV name arg, but it's in pos 2. Could we work around
* this by looking at the final positional arg rather than always
* looking at pos 1?
*
* This only validates types for required LV positional args
* (currently there are no command specifications that include
* specific LV types in optional positional args.)
*/
if ((cmd->command->rp_count == 1) &&
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
cmd->command->required_pos_args[0].def.lv_types) {
lv_types = cmd->command->required_pos_args[0].def.lv_types;
lv = lvl->lv;
seg = first_seg(lv);
if ((lv_is_cow(lv) && !(lv_types & ARG_DEF_LV_SNAPSHOT)) ||
(lv_is_thin_volume(lv) && !(lv_types & ARG_DEF_LV_THIN)) ||
(lv_is_thin_pool(lv) && !(lv_types & ARG_DEF_LV_THINPOOL)) ||
(lv_is_cache(lv) && !(lv_types & ARG_DEF_LV_CACHE)) ||
(lv_is_cache_pool(lv) && !(lv_types & ARG_DEF_LV_CACHEPOOL)) ||
(lv_is_mirror(lv) && !(lv_types & ARG_DEF_LV_MIRROR)) ||
(lv_is_raid(lv) && !(lv_types & (ARG_DEF_LV_RAID | ARG_DEF_LV_RAID0 | ARG_DEF_LV_RAID1 | ARG_DEF_LV_RAID4 | ARG_DEF_LV_RAID5 | ARG_DEF_LV_RAID6 | ARG_DEF_LV_RAID10))) ||
(segtype_is_striped(seg->segtype) && !(lv_types & ARG_DEF_LV_STRIPED)) ||
(segtype_is_linear(seg->segtype) && !(lv_types & ARG_DEF_LV_LINEAR))) {
/*
* If a named LV arg cannot be processed it's an error, otherwise
* the LV is skipped and doesn't cause the command to fail.
*/
if (str_list_match_item(&found_arg_lvnames, lv->name)) {
log_error("Operation not permitted on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
ret_max = ECMD_FAILED;
} else {
log_warn("Operation not permitted on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
}
continue;
}
}
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
ret = process_single_lv(cmd, lvl->lv, handle);

View File

@@ -44,26 +44,33 @@
#include "toollib.h"
#include "lvmnotify.h"
#include "command.h"
#include <ctype.h>
#include <sys/types.h>
#define CMD_LEN 256
#define MAX_ARGS 64
/* command functions */
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
#include "commands.h"
#undef xx
/* define the enums for the values accepted by command line --options */
enum {
#define val(a, b, c, d) a ,
#include "vals.h"
#undef val
};
/* define the enums for the command line switches */
/* define the enums for the command line --options */
enum {
#define arg(a, b, c, d, e, f) a ,
#include "args.h"
#undef arg
};
/* command functions */
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
#include "commands.h"
#undef xx
#include "command.h"
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
#define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */
@@ -79,14 +86,13 @@ struct arg_values {
/* void *ptr; // Currently not used. */
};
/* a global table of possible arguments */
/* a global table of possible --option's */
struct arg_props {
int enum_val;
int arg_enum; /* foo_ARG from args.h */
const char short_arg;
char _padding[7];
const char *long_arg;
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
int val_enum; /* foo_VAL from vals.h */
uint32_t flags;
uint32_t prio;
};
@@ -97,6 +103,14 @@ struct arg_value_group_list {
uint32_t prio;
};
/* a global table of possible --option values */
struct val_props {
int val_enum; /* foo_VAL from vals.h */
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
const char *name;
const char *usage;
};
#define CACHE_VGMETADATA 0x00000001
#define PERMITTED_READ_ONLY 0x00000002
/* Process all VGs if none specified on the command line. */

135
tools/vals.h Normal file
View File

@@ -0,0 +1,135 @@
/*
* Define value types which describe values accepted
* by the --option's in args.h, and can also describe
* the values accepted as positional args.
*
* Previously, accepted values were only "described"
* by identifying the parsing function to use.
*
* Some standard val types are used by many options,
* e.g. many options (aa_ARG, bb_ARG, cc_ARG) all
* accept a number_VAL.
*
* Other special val types are used by only one option,
* e.g. only mirrorlog_ARG accepts a mirrorlog_VAL.
* This typically means that there are some specific
* words that are recognized after the option.
*
* Some options currently take a standard val type,
* (esp string_VAL), but they could be given their
* own custom val type. The advantage of using a
* custom val type is the possibility of validating
* the value when parsing it with a custom parsing
* function, and the possibility of displaying the
* actual accepted values in the command usage.
* Without a custom val type, the code must do ad hoc
* validation of the string values, and the usage
* output for the option will only say "String"
* rather than giving the accepted string values.
* Even without a custom parsing function, there is
* reason to define a custom x_VAL enum so that a
* more descriptive usage string can be specified
* as opposed to just "String".
*
* Most of the val types defined here are used after
* --option's, and are referenced in foo_ARG entries
* in args.h. But, some val types are only used to
* represent positional values in command definitions,
* e.g. vg_VAL.
*
* val(a, b, c, d)
*
* a: foo_VAL enums
* b: the function to parse and set the value
* c: the name used to reference this value in command defs
* d: what to display in usage output for this value
*
* command defintions will use --option NAME, where NAME
* is shown in val() field c. NAME will be translated to
* foo_VAL enum in field a, which is used in commands[]
* structs.
*
* option definitions (arg.h) will reference foo_VAL enum
* in field a.
*
* FIXME: for specialized val types, the set of recognized
* words is not defined or stored in a consistent way,
* but is just whatever the parsing function happens to look
* for, so adding a new accepted value for the val type is
* often just making the parsing function recognize a new
* word. This new word should then also be added to the
* usage string for the val type here. It would be nice
* if the accepted values could be defined in a more
* consistent way, perhaps in struct val_props.
*
* The usage text for an option is not always the full
* set of words accepted for an option, but may be a
* subset. i.e. an outdated word that no longer does
* anything may not be shown, but may still be recognized
* and ignored, or an option that shouldn't be used in
* general isn't shown to avoid suggesting it.
* e.g. for --activate we show the most common "y|n|ay"
* without showing the lvmlockd variations "ey|sy" which
* are not applicable in general.
*
* FIXME: are there some specialized or irrelevant
* options included in the usage text below that should
* be removed? Should "lvm1" be removed?
*
* For Number args that take optional units, a full usage
* could be "Number[bBsSkKmMgGtTpPeE]" (with implied |),
* but repeating this full specification produces cluttered
* output, and doesn't indicate which unit is the default.
* "Number[units]" would be cleaner, as would a subset of
* common units, e.g. "Number[kmg...]", but neither helps
* with default. "Number[k|unit]" and "Number[m|unit]" show
* the default, and "unit" indicates that other units
* are possible without listing them all. This also
* suggests using the preferred lower case letters, because
* --size and other option args treat upper/lower letters
* the same, all as 1024 SI base. For this reason, we
* should avoid suggesting the upper case letters.
*/
val(none_VAL, NULL, "None", "") /* unused, for enum value 0 */
val(conststr_VAL, NULL, "ConstString", "") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "") /* used only for command defs */
val(bool_VAL, yes_no_arg, "Bool", "y|n")
val(number_VAL, int_arg, "Number", NULL)
val(string_VAL, string_arg, "String", NULL)
val(vg_VAL, string_arg, "VG", NULL)
val(lv_VAL, string_arg, "LV", NULL)
val(pv_VAL, string_arg, "PV", NULL)
val(tag_VAL, tag_arg, "Tag", NULL)
val(select_VAL, NULL, "Select", NULL) /* used only for command defs */
val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete")
val(activation_VAL, activation_arg, "Active", "y|n|ay")
val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback")
val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore")
val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%{VG|PVS|FREE}]")
val(permission_VAL, permission_arg, "Permission", "rw|r")
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool")
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
val(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Number")
/* this should always be last */
val(VAL_COUNT, NULL, NULL, NULL)
/*
* I suspect many of the following are good candidates for a custom VAL enum
* for the benefit of custom parsing, or custom usage, or both:
*
* configreport_ARG, configtype_ARG, polloperation_ARG, raidrebuild_ARG,
* raidsyncaction_ARG, raidwritemostly_ARG, reportformat_ARG, syncaction_ARG,
* cachepolicy_ARG, cachesettings_ARG, writemostly_ARG
*/