1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-26 01:44:19 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
761e4ef9ab commands: new method for defining commands
. Define a prototype for every lvm command.
. Verify every user command matches one.
. Generate help text and man pages from them.

The new file command-lines.in defines a prototype for every
unique lvm command.  A unique lvm command is a unique
combination of: command name + required option args +
required positional args.  Each of these prototypes also
includes the optional option args and optional positional
args that the command will accept, a description, and a
unique string ID for the definition.  Any valid command
will match one of the prototypes.

Here's an example of the lvresize command definitions from
command-lines.in, there are three unique lvresize commands:

lvresize --size SizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
--stripes Number, --stripesize SizeKB, --test, --poolmetadatasize SizeMB
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.

lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB,
--test
ID: lvresize_by_pv
DESC: Resize an LV by a specified PV.

lvresize --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat String, --stripes Number, --stripesize SizeKB,
--test
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize the metadata SubLV of a pool LV.

The three commands have separate definitions because they have
different required parameters.  Required parameters are specified
on the first line of the definition.  Optional options are
listed after OO, and optional positional args are listed after OP.

This data is used to generate corresponding command definition
structures for lvm in command-lines.h.  "usage" text is also
generated, so it is always in sync with the definitions.

Example of the corresponding generated structure in
command-lines.h for the first lvresize prototype
(these structures are never edited directly):

commands[78].name = "lvresize";
commands[78].command_line_id = "lvresize_by_size";
commands[78].command_line_enum = lvresize_by_size_CMD;
commands[78].fn = lvresize;
commands[78].ro_count = 1;
commands[78].rp_count = 1;
commands[78].oo_count = 22;
commands[78].op_count = 1;
commands[78].desc = "DESC: Resize an LV by a specified size.";
commands[78].usage = "lvresize --size Number[m|unit] LV"
" [ --alloc contiguous|cling|normal|anywhere|inherit,
   --autobackup y|n, --nofsck, --nosync, --reportformat String,
   --resizefs, --stripes Number, --stripesize Number[k|unit],
   --poolmetadatasize Number[m|unit] ]"
" [ PV ... ]";
commands[78].usage_common =
" [ --commandprofile String, --config String, --debug,
    --driverloaded y|n, --help, --profile String, --quiet,
    --verbose, --version, --yes, --force, --test, --noudevsync ]";
commands[78].required_opt_args[0].opt = size_ARG;
commands[78].required_opt_args[0].def.val_bits = val_enum_to_bit(sizemb_VAL);
commands[78].required_pos_args[0].pos = 1;
commands[78].required_pos_args[0].def.val_bits = val_enum_to_bit(lv_VAL);
commands[78].optional_opt_args[0].opt = commandprofile_ARG;
commands[78].optional_opt_args[0].def.val_bits = val_enum_to_bit(string_VAL);
commands[78].optional_opt_args[1].opt = config_ARG;
commands[78].optional_opt_args[1].def.val_bits = val_enum_to_bit(string_VAL);
commands[78].optional_opt_args[2].opt = debug_ARG;
commands[78].optional_opt_args[3].opt = driverloaded_ARG;
commands[78].optional_opt_args[3].def.val_bits = val_enum_to_bit(bool_VAL);
commands[78].optional_opt_args[4].opt = help_ARG;
commands[78].optional_opt_args[5].opt = profile_ARG;
commands[78].optional_opt_args[5].def.val_bits = val_enum_to_bit(string_VAL);
commands[78].optional_opt_args[6].opt = quiet_ARG;
commands[78].optional_opt_args[7].opt = verbose_ARG;
commands[78].optional_opt_args[8].opt = version_ARG;
commands[78].optional_opt_args[9].opt = yes_ARG;
commands[78].optional_opt_args[10].opt = alloc_ARG;
commands[78].optional_opt_args[10].def.val_bits = val_enum_to_bit(alloc_VAL);
commands[78].optional_opt_args[11].opt = autobackup_ARG;
commands[78].optional_opt_args[11].def.val_bits = val_enum_to_bit(bool_VAL);
commands[78].optional_opt_args[12].opt = force_ARG;
commands[78].optional_opt_args[13].opt = nofsck_ARG;
commands[78].optional_opt_args[14].opt = nosync_ARG;
commands[78].optional_opt_args[15].opt = noudevsync_ARG;
commands[78].optional_opt_args[16].opt = reportformat_ARG;
commands[78].optional_opt_args[16].def.val_bits = val_enum_to_bit(string_VAL);
commands[78].optional_opt_args[17].opt = resizefs_ARG;
commands[78].optional_opt_args[18].opt = stripes_ARG;
commands[78].optional_opt_args[18].def.val_bits = val_enum_to_bit(number_VAL);
commands[78].optional_opt_args[19].opt = stripesize_ARG;
commands[78].optional_opt_args[19].def.val_bits = val_enum_to_bit(sizekb_VAL);
commands[78].optional_opt_args[20].opt = test_ARG;
commands[78].optional_opt_args[21].opt = poolmetadatasize_ARG;
commands[78].optional_opt_args[21].def.val_bits = val_enum_to_bit(sizemb_VAL);
commands[78].optional_pos_args[0].pos = 2;
commands[78].optional_pos_args[0].def.val_bits = val_enum_to_bit(pv_VAL);
commands[78].optional_pos_args[0].def.flags = ARG_DEF_FLAG_MAY_REPEAT;

Every user-entered command is compared against the set of
command structures, and matched with one.  An error is
reported if an entered command does not have the required
parameters for any definition.  The closest match is printed
as a suggestion, and running lvresize --help will display
the usage for each possible lvresize command, e.g.:

$ lvresize --help
  lvresize - Resize a logical volume

  Resize an LV by a specified size.
  lvresize --size Number[m|unit] LV
  	[ --alloc contiguous|cling|normal|anywhere|inherit,
	  --autobackup y|n,
	  --nofsck,
	  --nosync,
	  --reportformat String,
	  --resizefs,
	  --stripes Number,
	  --stripesize Number[k|unit],
	  --poolmetadatasize Number[m|unit] ]
  	[ PV ... ]

  Resize an LV by a specified PV.
  lvresize LV PV ...
  	[ --alloc contiguous|cling|normal|anywhere|inherit,
	  --autobackup y|n,
	  --nofsck,
	  --nosync,
	  --reportformat String,
	  --resizefs,
	  --stripes Number,
	  --stripesize Number[k|unit] ]

  Resize the metadata SubLV of a pool LV.
  lvresize --poolmetadatasize Number[m|unit] LV_thinpool
  	[ --alloc contiguous|cling|normal|anywhere|inherit,
	  --autobackup y|n,
	  --nofsck,
	  --nosync,
	  --reportformat String,
	  --stripes Number,
	  --stripesize Number[k|unit] ]
  	[ PV ... ]

  Common options:
  	[ --commandprofile String,
	  --config String,
	  --debug,
	  --driverloaded y|n,
	  --help,
	  --profile String,
	  --quiet,
	  --verbose,
	  --version,
	  --yes,
	  --force,
	  --test,
	  --noudevsync ]

  (Use --help --help for usage notes.)

$ lvresize --poolmetadatasize 4
  Failed to find a matching command definition.
  Closest command usage is:
  lvresize --poolmetadatasize Number[m|unit] LV_thinpool

Man page prototypes are also generated from the same original
command definitions, and are always in sync with the code
and help text.

Very early in command execution, a matching command definition
is found.  lvm then knows the operation being done, and that
the provided args conform to the definition.  This will allow
lots of ad hoc checking/validation to be removed throughout
the code.

Each command definition can also be routed to a specific
function to implement it.  The function is associated with
an enum value for the command definition (generated from
the ID string.)  These per-command-definition implementation
functions have not yet been created, so all commands
currently fall back to the existing implementation.

Using per-command-definition functions will allow lots of
code to be removed which tries to figure out what the
command is meant to do.  This is currently based on ad hoc
and complicated option analysis.  When using the new
functions, what the command is doing is already known
from the associated command definition.

So, this first phase validates every user-entered command
against the set of command prototypes, then calls the existing
implementation.  The second phase can associate an implementation
function with each definition, and take further advantage of the
known operation to avoid the complicated option analysis.
2016-10-13 16:59:53 -05:00
18 changed files with 8830 additions and 1529 deletions

View File

@@ -140,13 +140,6 @@ Makefile: Makefile.in
*) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_PROFILE_DIR#+$(DEFAULT_PROFILE_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;s+#DEFAULT_PID_DIR#+@DEFAULT_PID_DIR@+;s+#SYSTEMD_GENERATOR_DIR#+$(SYSTEMD_GENERATOR_DIR)+;s+#DEFAULT_MANGLING#+$(DEFAULT_MANGLING)+;" $< > $@ ;; \
esac
ccmd: ../tools/create-commands.c
$(CC) ../tools/create-commands.c -o ccmd
generate: ccmd
./ccmd --output man -s 0 -p 1 -c lvcreate ../tools/command-lines.in > lvcreate.8.a
cat lvcreate.8.a lvcreate.8.b > lvcreate.8.in
install_man5: $(MAN5)
$(INSTALL) -d $(MAN5DIR)
$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -56,7 +56,7 @@ fail lvcreate -l 1 --cachepool pool8 $vg
# no size specified
invalid lvcreate --cachepool pool $vg 2>&1 | tee err
# grep "specify either size or extents" err
grep "specify either size or extents" err
# Check nothing has been created yet
check vg_field $vg lv_count 0

View File

@@ -23,6 +23,7 @@ lvcreate -l 1 -n lv1 $vg "$dev1"
invalid vgextend
# --metadatacopies => use --pvmetadatacopies
invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out
grep -- "use --pvmetadatacopies" out
# VG name should exist
fail vgextend --restoremissing $vg-invalid "$dev1"

View File

@@ -76,7 +76,6 @@ SOURCES2 =\
TARGETS =\
.commands \
command-lines.h \
liblvm2cmd.a \
lvm
@@ -100,8 +99,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \
liblvm2cmd-static.a dmsetup.static lvm.static \
$(LDDEPS) .exported_symbols_generated \
ccmd command-lines.h command-lines-count.h
$(LDDEPS) .exported_symbols_generated
ifeq ("@CMDLIB@", "yes")
TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION)
@@ -173,13 +171,6 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
ccmd: create-commands.c
$(CC) create-commands.c -o ccmd
command-lines.h: ccmd
./ccmd --output struct command-lines.in > command-lines.h
./ccmd --output count command-lines.in > command-lines-count.h
ifneq ("$(CFLOW_CMD)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
-include $(top_builddir)/libdm/libdevmapper.cflow

View File

@@ -31,8 +31,8 @@ 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", configreport_VAL, ARG_GROUPABLE, 1)
arg(configtype_ARG, '\0', "typeconfig", configtype_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)
@@ -81,26 +81,26 @@ 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", polloperation_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", pvmetadatacopies_VAL, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 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", syncaction_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", writemostly_VAL, ARG_GROUPABLE, 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", reportformat_VAL, 0, 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)
@@ -116,7 +116,7 @@ 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", syncaction_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)
@@ -133,14 +133,14 @@ 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", vgmetadatacopies_VAL, 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", writemostly_VAL, ARG_GROUPABLE, 0)
arg(writemostly_ARG, '\0', "writemostly", string_VAL, ARG_GROUPABLE, 0)
/* Allow some variations */
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)

133
tools/command-lines-count.h Normal file
View File

@@ -0,0 +1,133 @@
/* Do not edit. This file is generated by scripts/create-commands */
/* using command definitions from scripts/command-lines.in */
#define COMMAND_COUNT 147
enum {
no_CMD,
lvchange_properties_CMD,
lvchange_resync_CMD,
lvchange_syncaction_CMD,
lvchange_rebuild_CMD,
lvchange_activate_CMD,
lvchange_refresh_CMD,
lvchange_monitor_CMD,
lvchange_poll_CMD,
lvchange_persistent_CMD,
lvconvert_merge_CMD,
lvconvert_combine_split_snapshot_CMD,
lvconvert_to_thin_with_external_CMD,
lvconvert_to_cache_vol_CMD,
lvconvert_to_thinpool_CMD,
lvconvert_to_cachepool_CMD,
lvconvert_to_mirror_CMD,
lvconvert_to_mirror_or_raid1_CMD,
lvconvert_raid1_to_mirror_CMD,
lvconvert_mirror_to_raid1_CMD,
lvconvert_general_to_raid_CMD,
lvconvert_change_mirror_images_CMD,
lvconvert_raid_to_striped_CMD,
lvconvert_raid_or_mirror_to_linear_CMD,
lvconvert_split_mirror_images_to_new_CMD,
lvconvert_split_mirror_images_and_track_CMD,
lvconvert_repair_pvs_or_thinpool_CMD,
lvconvert_replace_pv_CMD,
lvconvert_change_mirrorlog_CMD,
lvconvert_split_and_keep_cachepool_CMD,
lvconvert_split_and_delete_cachepool_CMD,
lvconvert_split_cow_snapshot_CMD,
lvconvert_poll_mirror_CMD,
lvconvert_swap_pool_metadata_CMD,
lvcreate_error_vol_CMD,
lvcreate_zero_vol_CMD,
lvcreate_linear_CMD,
lvcreate_striped_CMD,
lvcreate_mirror_CMD,
lvcreate_raid_any_CMD,
lvcreate_cow_snapshot_CMD,
lvcreate_cow_snapshot_with_virtual_origin_CMD,
lvcreate_thinpool_CMD,
lvcreate_cachepool_CMD,
lvcreate_thin_vol_CMD,
lvcreate_thin_snapshot_CMD,
lvcreate_thin_snapshot_of_external_CMD,
lvcreate_thin_vol_with_thinpool_CMD,
lvcreate_thin_vol_with_thinpool_or_sparse_snapshot_CMD,
lvcreate_convert_to_cache_vol_with_cachepool_CMD,
lvcreate_cache_vol_with_new_origin_CMD,
lvdisplay_general_CMD,
lvextend_by_size_CMD,
lvextend_by_pv_CMD,
lvextend_pool_metadata_by_size_CMD,
lvextend_by_policy_CMD,
lvmconfig_general_CMD,
lvreduce_general_CMD,
lvremove_general_CMD,
lvrename_vg_lv_lv_CMD,
lvrename_lv_lv_CMD,
lvresize_by_size_CMD,
lvresize_by_pv_CMD,
lvresize_pool_metadata_by_size_CMD,
lvs_general_CMD,
lvscan_general_CMD,
pvchange_properties_all_CMD,
pvchange_properties_some_CMD,
pvresize_general_CMD,
pvck_general_CMD,
pvcreate_general_CMD,
pvdisplay_general_CMD,
pvmove_one_CMD,
pvmove_any_CMD,
pvremove_general_CMD,
pvs_general_CMD,
pvscan_show_CMD,
pvscan_cache_CMD,
vgcfgbackup_general_CMD,
vgcfgrestore_by_vg_CMD,
vgcfgrestore_by_file_CMD,
vgchange_properties_CMD,
vgchange_monitor_CMD,
vgchange_poll_CMD,
vgchange_activate_CMD,
vgchange_refresh_CMD,
vgchange_lockstart_CMD,
vgchange_lockstop_CMD,
vgck_general_CMD,
vgconvert_general_CMD,
vgcreate_general_CMD,
vgdisplay_general_CMD,
vgexport_some_CMD,
vgexport_all_CMD,
vgextend_general_CMD,
vgimport_some_CMD,
vgimport_all_CMD,
vgimportclone_general_CMD,
vgmerge_general_CMD,
vgmknodes_general_CMD,
vgreduce_by_pv_CMD,
vgreduce_all_CMD,
vgreduce_missing_CMD,
vgremove_general_CMD,
vgrename_by_name_CMD,
vgrename_by_uuid_CMD,
vgs_general_CMD,
vgscan_general_CMD,
vgsplit_by_pv_to_existing_CMD,
vgsplit_by_lv_to_existing_CMD,
vgsplit_by_pv_to_new_CMD,
vgsplit_by_lv_to_new_CMD,
devtypes_general_CMD,
fullreport_general_CMD,
lastlog_general_CMD,
lvpoll_general_CMD,
formats_general_CMD,
help_general_CMD,
version_general_CMD,
pvdata_general_CMD,
segtypes_general_CMD,
systemid_general_CMD,
tags_general_CMD,
lvmchange_general_CMD,
lvmdiskscan_general_CMD,
lvmsadc_general_CMD,
lvmsar_general_CMD,
COMMAND_ID_COUNT,
};

8121
tools/command-lines.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -51,8 +51,8 @@ struct command_name {
*/
/* arg_def flags */
#define ARG_DEF_FLAG_NEW 1 << 0
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
#define ARG_DEF_FLAG_NEW 1 << 0
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
/* arg_def lv_types */
enum {
@@ -82,7 +82,7 @@ static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
static inline uint64_t val_enum_to_bit(int val_enum)
{
return (1ULL << val_enum);
return 1 << val_enum;
}
/* Description a value that follows an option or exists in a position. */
@@ -123,8 +123,7 @@ struct pos_arg {
* one or more from required_opt_args is required,
* then the rest are optional.
*/
#define CMD_FLAG_ONE_REQUIRED_OPT 1
#define CMD_FLAG_SECONDARY_SYNTAX 2
#define CMD_FLAG_ONE_REQUIRED_OPT 1
/* a register of the lvm commands */
struct command {

View File

@@ -30,12 +30,12 @@ void *cmdlib_lvm2_init(unsigned static_compile)
{
struct cmd_context *cmd;
lvm_register_commands();
init_is_static(static_compile);
if (!(cmd = init_lvm(1, 1)))
return NULL;
lvm_register_commands();
return (void *) cmd;
}

View File

@@ -733,194 +733,23 @@ int readahead_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_va
/*
* Non-zero, positive integer, "all", or "unmanaged"
*/
int vgmetadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcasecmp(av->value, "all")) {
av->ui_value = VGMETADATACOPIES_ALL;
return 1;
}
if (!strncmp(cmd->name, "vg", 2)) {
if (!strcasecmp(av->value, "all")) {
av->ui_value = VGMETADATACOPIES_ALL;
return 1;
}
if (!strcasecmp(av->value, "unmanaged")) {
av->ui_value = VGMETADATACOPIES_UNMANAGED;
return 1;
if (!strcasecmp(av->value, "unmanaged")) {
av->ui_value = VGMETADATACOPIES_UNMANAGED;
return 1;
}
}
return int_arg(cmd, av);
}
int pvmetadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
int num;
if (!int_arg(cmd, av))
return 0;
num = av->i_value;
if ((num != 0) && (num != 1) && (num != 2))
return 0;
return 1;
}
int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strncmp(cmd->name, "pv", 2))
return pvmetadatacopies_arg(cmd, av);
if (!strncmp(cmd->name, "vg", 2))
return vgmetadatacopies_arg(cmd, av);
return 0;
}
int polloperation_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "pvmove") ||
!strcmp(av->value, "convert") ||
!strcmp(av->value, "merge") ||
!strcmp(av->value, "merge_thin"))
return 1;
return 0;
}
int writemostly_arg(struct cmd_context *cmd, struct arg_values *av)
{
/* Could we verify that a PV arg looks like /dev/foo ? */
return 1;
}
int syncaction_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "check") ||
!strcmp(av->value, "repair"))
return 1;
return 0;
}
int reportformat_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "basic") ||
!strcmp(av->value, "json"))
return 1;
return 0;
}
int configreport_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "log") ||
!strcmp(av->value, "vg") ||
!strcmp(av->value, "lv") ||
!strcmp(av->value, "pv") ||
!strcmp(av->value, "pvseg") ||
!strcmp(av->value, "seg"))
return 1;
return 0;
}
int configtype_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "current") ||
!strcmp(av->value, "default") ||
!strcmp(av->value, "diff") ||
!strcmp(av->value, "full") ||
!strcmp(av->value, "list") ||
!strcmp(av->value, "missing") ||
!strcmp(av->value, "new") ||
!strcmp(av->value, "profilable") ||
!strcmp(av->value, "profilable-command") ||
!strcmp(av->value, "profilable-metadata"))
return 1;
return 0;
}
/*
* FIXME: there's been a confusing mixup among:
* resizeable, resizable, allocatable, allocation.
*
* resizeable and allocatable are the preferred,
* standard option names.
*
* The dispreferred "resizable" is always translated
* to the preferred resizeable.
*
* But, the dispreferred "allocation" name seems
* to translate to either or both resizeable
* and allocatable, it's not clear which.
*/
static int _opt_standard_to_synonym(const char *cmd_name, int opt)
{
switch (opt) {
case mirrorlog_ARG:
return corelog_ARG;
case resizeable_ARG:
return resizable_ARG;
case allocatable_ARG:
return allocation_ARG;
case activate_ARG:
return available_ARG;
case rebuild_ARG:
return raidrebuild_ARG;
case syncaction_ARG:
return raidsyncaction_ARG;
case writemostly_ARG:
return raidwritemostly_ARG;
case minrecoveryrate_ARG:
return raidminrecoveryrate_ARG;
case maxrecoveryrate_ARG:
return raidmaxrecoveryrate_ARG;
case writebehind_ARG:
return raidwritebehind_ARG;
case virtualsize_ARG:
return virtualoriginsize_ARG;
case pvmetadatacopies_ARG:
if (!strncmp(cmd_name, "pv", 2))
return metadatacopies_ARG;
return 0;
case vgmetadatacopies_ARG:
if (!strncmp(cmd_name, "vg", 2))
return metadatacopies_ARG;
return 0;
}
return 0;
}
static int _opt_synonym_to_standard(const char *cmd_name, int opt)
{
switch (opt) {
case corelog_ARG:
return mirrorlog_ARG;
case resizable_ARG:
return resizeable_ARG;
case allocation_ARG:
return allocatable_ARG;
case available_ARG:
return activate_ARG;
case raidrebuild_ARG:
return rebuild_ARG;
case raidsyncaction_ARG:
return syncaction_ARG;
case raidwritemostly_ARG:
return writemostly_ARG;
case raidminrecoveryrate_ARG:
return minrecoveryrate_ARG;
case raidmaxrecoveryrate_ARG:
return maxrecoveryrate_ARG;
case raidwritebehind_ARG:
return writebehind_ARG;
case virtualoriginsize_ARG:
return virtualsize_ARG;
case metadatacopies_ARG:
if (!strncmp(cmd_name, "pv", 2))
return pvmetadatacopies_ARG;
if (!strncmp(cmd_name, "vg", 2))
return vgmetadatacopies_ARG;
return 0;
}
return 0;
}
static void _add_getopt_arg(int arg_enum, char **optstrp, struct option **longoptsp);
/*
* The valid args for a command name in general is a union of
* required_opt_args and optional_opt_args for all commands[]
@@ -932,7 +761,6 @@ 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 opt_syn;
int i, ro, oo;
/*
@@ -946,7 +774,6 @@ static void _set_valid_args_for_command_name(int ci)
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;
@@ -956,36 +783,16 @@ static void _set_valid_args_for_command_name(int ci)
for (i = 0; i < ARG_COUNT; i++) {
if (all_args[i]) {
opt_enum = _cmdline.arg_props[i].arg_enum;
command_names[ci].valid_args[num_args] = opt_enum;
command_names[ci].valid_args[num_args] = _cmdline.arg_props[i].arg_enum;
num_args++;
/* Automatically recognize --extents in addition to --size. */
if (opt_enum == size_ARG) {
if (_cmdline.arg_props[i].arg_enum == size_ARG) {
command_names[ci].valid_args[num_args] = extents_ARG;
num_args++;
}
/* Recognize synonyms */
if ((opt_syn = _opt_standard_to_synonym(command_names[ci].name, opt_enum))) {
command_names[ci].valid_args[num_args] = opt_syn;
num_args++;
}
/*
* "--allocation" is a weird option that seems to be
* a synonym for either allocatable or resizeable,
* each which already have their own other synonyms,
* so just add allocation whenever either is seen.
*/
if ((opt_enum == allocatable_ARG) || (opt_enum == resizeable_ARG)) {
command_names[ci].valid_args[num_args] = allocation_ARG;
num_args++;
}
}
}
command_names[ci].num_args = num_args;
}
@@ -1054,25 +861,49 @@ void lvm_register_commands(void)
_set_valid_args_for_command_name(i);
}
/*
* Also see merge_synonym(). The command definitions
* are written using just one variation of the option
* name (opt below). This function checks if the user
* entered a synonym (arg_is_set).
*/
static int _opt_synonym_is_set(struct cmd_context *cmd, int opt_std)
static int _opt_equivalent_is_set(struct cmd_context *cmd, int opt)
{
int opt_syn = _opt_standard_to_synonym(cmd->name, opt_std);
if ((opt == mirrorlog_ARG) && arg_is_set(cmd, corelog_ARG))
return 1;
return opt_syn && arg_is_set(cmd, opt_syn);
if ((opt == resizeable_ARG) && arg_is_set(cmd, resizable_ARG))
return 1;
if ((opt == allocatable_ARG) && arg_is_set(cmd, allocation_ARG))
return 1;
if ((opt == resizeable_ARG) && arg_is_set(cmd, allocation_ARG))
return 1;
if ((opt == activate_ARG) && arg_is_set(cmd, available_ARG))
return 1;
if ((opt == rebuild_ARG) && arg_is_set(cmd, raidrebuild_ARG))
return 1;
if ((opt == syncaction_ARG) && arg_is_set(cmd, raidsyncaction_ARG))
return 1;
if ((opt == writemostly_ARG) && arg_is_set(cmd, raidwritemostly_ARG))
return 1;
if ((opt == minrecoveryrate_ARG) && arg_is_set(cmd, raidminrecoveryrate_ARG))
return 1;
if ((opt == maxrecoveryrate_ARG) && arg_is_set(cmd, raidmaxrecoveryrate_ARG))
return 1;
if ((opt == writebehind_ARG) && arg_is_set(cmd, raidwritebehind_ARG))
return 1;
return 0;
}
static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro)
{
int opt_enum = commands[ci].required_opt_args[ro].opt;
if (arg_is_set(cmd, opt_enum) || _opt_synonym_is_set(cmd, opt_enum))
if (arg_is_set(cmd, opt_enum))
goto check_val;
/*
@@ -1087,6 +918,9 @@ static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro
goto check_val;
}
if (_opt_equivalent_is_set(cmd, opt_enum))
goto check_val;
return 0;
/*
@@ -1118,13 +952,12 @@ check_val:
static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp, char **argv)
{
const char *name;
/*
* 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. */
@@ -1139,36 +972,6 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp
arg_is_set(cmd, select_ARG))
return 1;
/*
* For an lvcreate command with VG as the first required positional arg,
* the VG position is allowed to be empty if --name VG/LV is used, or if the
* LVM_VG_NAME env var is set.
*
* --thinpool VG/LV and --cachepool VG/LV can also function like --name
* to provide the VG name in place of the positional arg.
*/
if (!strcmp(cmd->name, "lvcreate") &&
(rp == 0) &&
val_bit_is_set(commands[ci].required_pos_args[rp].def.val_bits, vg_VAL) &&
(arg_is_set(cmd, name_ARG) || arg_is_set(cmd, thinpool_ARG) || arg_is_set(cmd, cachepool_ARG))) {
if ((name = arg_str_value(cmd, name_ARG, NULL))) {
if (strstr(name, "/") || getenv("LVM_VG_NAME"))
return 1;
}
/* FIXME: does LVM_VG_NAME also work with --thinpool/--cachepool ? */
if ((name = arg_str_value(cmd, thinpool_ARG, NULL))) {
if (strstr(name, "/"))
return 1;
}
if ((name = arg_str_value(cmd, cachepool_ARG, NULL))) {
if (strstr(name, "/"))
return 1;
}
}
return 0;
}
@@ -1333,14 +1136,17 @@ static void _print_description(int ci)
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) {
buf[bi] = '\0';
log_print("%s", buf);
memset(buf, 0, sizeof(buf));
bi = 0;
}
/* skip DESC: */
di += 5;
continue;
}
@@ -1354,10 +1160,8 @@ static void _print_description(int ci)
break;
}
if (bi) {
buf[bi] = '\0';
if (bi)
log_print("%s", buf);
}
}
/*
@@ -1382,22 +1186,14 @@ static void _print_description(int ci)
* cmd->argv[] in that pos can be NULL if arg_is_set(select_ARG)
*/
/* The max number of unused options we keep track of to warn about */
#define MAX_UNUSED_COUNT 8
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
{
const char *name;
int match_required, match_ro, match_rp, match_type, match_unused, mismatch_required;
int best_i = 0, best_required = 0, best_type = 0, best_unused = 0;
int close_i = 0, close_ro = 0, close_type;
int temp_unused_options[MAX_UNUSED_COUNT];
int temp_unused_count;
int best_unused_options[MAX_UNUSED_COUNT] = { 0 };
int best_unused_count = 0;
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, j;
int opt_enum, opt_i;
int accepted, count;
name = last_path_component(path);
@@ -1410,34 +1206,27 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
if (arg_is_set(cmd, help_ARG) || arg_is_set(cmd, help2_ARG) || arg_is_set(cmd, version_ARG))
return &commands[i];
match_required = 0; /* required parameters that match */
match_ro = 0; /* required opt_args that match */
match_rp = 0; /* required pos_args that match */
match_type = 0; /* type arg matches */
match_unused = 0; /* options set that are not accepted by command */
mismatch_required = 0; /* required parameters that do not match */
temp_unused_count = 0;
memset(&temp_unused_options, 0, sizeof(temp_unused_options));
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)
match_required = 1;
match_count = 1;
/* match required_opt_args */
for (ro = 0; ro < commands[i].ro_count; ro++) {
if (_command_required_opt_matches(cmd, i, ro)) {
/* log_warn("match %d ro opt %d", i, commands[i].required_opt_args[ro].opt); */
match_required++;
match_ro++;
if (commands[i].required_opt_args[ro].opt == type_ARG)
match_type = 1;
match_count++;
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); */
mismatch_required++;
mismatch_count++;
}
}
@@ -1446,12 +1235,12 @@ 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 (match_ro) {
if (match_count_ro) {
/* one or more of the required_opt_args is used */
mismatch_required = 0;
mismatch_count = 0;
} else {
/* not even one of the required_opt_args is used */
mismatch_required = 1;
mismatch_count = 1;
}
}
@@ -1460,139 +1249,134 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
for (rp = 0; rp < commands[i].rp_count; 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_required++;
match_rp++;
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); */
mismatch_required++;
mismatch_count++;
}
}
/* if cmd is missing any required opt/pos args, it can't be this command. */
if (mismatch_required) {
if (mismatch_count) {
/* save "closest" command that doesn't match */
if ((match_type && !close_type) ||
((match_type == close_type) && (match_ro > close_ro))) {
close_i = i;
close_ro = match_ro;
close_type = match_type;
if (match_count_ro && (match_count_ro > closest_count_ro)) {
closest_i = i;
closest_count_ro = match_count_ro;
}
continue;
}
if (!match_required)
if (!match_count)
continue;
/* 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_ro || match_rp))
match_required++;
if ((commands[i].ro_count || commands[i].rp_count) &&
(match_count_ro || match_count_rp))
match_count++;
/* log_warn("command %d has match_required %d match_ro %d match_rp %d",
i, match_required, match_ro, match_rp); */
/* Count how many options cmd has set that are not accepted by commands[i]. */
/* FIXME: also count unused positional args? */
for (opt_i = 0; opt_i < ARG_COUNT; opt_i++) {
if (!arg_is_set(cmd, opt_i))
continue;
if (!(opt_enum = _opt_synonym_to_standard(cmd->name, opt_i)))
opt_enum = opt_i;
/* extents are not used in command definitions */
if (opt_enum == extents_ARG)
continue;
accepted = 0;
/* NB in some cases required_opt_args are optional */
for (j = 0; j < commands[i].ro_count; j++) {
if (commands[i].required_opt_args[j].opt == opt_enum) {
accepted = 1;
break;
}
}
if (accepted)
continue;
for (j = 0; j < commands[i].oo_count; j++) {
if (commands[i].optional_opt_args[j].opt == opt_enum) {
accepted = 1;
break;
}
}
if (!accepted) {
match_unused++;
if (temp_unused_count < MAX_UNUSED_COUNT)
temp_unused_options[temp_unused_count++] = opt_enum;
}
}
/* 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}.
*
* A match is better if:
* . more required opt/pos args match
* . type arg matches when other doesn't
* . those being equal, less unused options
*/
if (!best_required || (match_required > best_required) || (match_type > best_type) ||
((match_required == best_required) && (match_type == best_type) && (match_unused < best_unused))) {
/* log_warn("best %d has match_required %d match_ro %d match_rp %d",
i, match_required, match_ro, match_rp); */
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_required = match_required;
best_type = match_type;
best_unused = match_unused;
best_unused_count = temp_unused_count;
memcpy(&best_unused_options, &temp_unused_options, sizeof(best_unused_options));
best_count = match_count;
}
}
if (!best_required) {
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 (close_ro) {
if (closest_count_ro) {
log_warn("Closest command usage is:");
_print_usage(_cmdline.commands[close_i].usage, 1);
_print_usage(_cmdline.commands[closest_i].usage, 1);
}
return NULL;
}
/*
* If the user passed an option that is not accepted by the matched
* command, then fail.
*
* FIXME: it might be nice to have a config setting that would turn
* these into warnings, and just ignore the unused options.
* 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.
*/
if (best_unused_count) {
for (i = 0; i < best_unused_count; i++) {
log_error("Invalid option for command (%s %d): %s.",
commands[best_i].command_line_id, best_i,
arg_long_option_name(best_unused_options[i]));
/*
* Warn about options that are set but are not used by the command.
*/
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;
}
/* --extents is a special case which is accepted in place of --size */
if (!accepted && (i != extents_ARG)) {
log_error("Invalid option for the specified command (%s %d): %s.",
commands[best_i].command_line_id, best_i, arg_long_option_name(i));
return NULL;
#if 0
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;
#endif
}
return NULL;
}
/*
* If the user provided a positional arg that is not accepted by
* the mached command, then fail.
* 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.
*
* FIXME: same question as above, should there be a config setting
* to just warn/ignore about unused positional args?
* Otherwise, warn about positional args that exist beyond the number of
* required + optional pos_args.
*/
count = commands[best_i].rp_count;
@@ -1608,15 +1392,10 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
break;
if (count >= (commands[best_i].rp_count + commands[best_i].op_count)) {
log_error("Invalid positional argument for command (%s %d): %s.",
commands[best_i].command_line_id, best_i, argv[count]);
/* FIXME: to warn/ignore, clear so it can't be used when processing. */
/*
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)--;
*/
return NULL;
}
}
out:
@@ -1647,9 +1426,6 @@ static int _usage(const char *name, int help_count)
if (strcmp(_cmdline.commands[i].name, name))
continue;
if ((_cmdline.commands[i].cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && (help_count < 3))
continue;
if (strlen(_cmdline.commands[i].desc))
_print_description(i);
@@ -1679,18 +1455,11 @@ static int _usage(const char *name, int help_count)
log_print(". --size Number can be replaced with --extents NumberExtents.");
log_print(". When --name is omitted from lvcreate, a new LV name is");
log_print(" generated with the \"lvol\" prefix and a unique numeral suffix.");
log_print(". The required VG parameter in lvcreate may be omitted when");
log_print(" the VG name is included in another option, e.g. --name VG/LV.");
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(". The default output unit is specified by letter, followed by |unit");
log_print(" which represents other possible units: hHbBsSkKmMgGtTpPeE.");
log_print(". Output units are 1024 SI base, regardless of unit capitalization.");
log_print(". Use --help --help --help to print secondary command syntax");
log_print(" formats that are recognized, e.g. for compatibility.");
log_print(". See man pages for short option equivalents of long option names,");
log_print(" and for more detailed descriptions of variable parameters.");
}

View File

@@ -801,7 +801,10 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
return 0;
}
if (arg_is_set(cmd, vgmetadatacopies_ARG))
if (arg_is_set(cmd, metadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else if (arg_is_set(cmd, vgmetadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else
@@ -2552,14 +2555,10 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
* 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 (%s %d) on LV %s with type %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lv), seg->segtype->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 (%s %d) on LV %s with type %s.",
cmd->command->command_line_id, cmd->command->command_line_enum,
display_lvname(lv), seg->segtype->name);
log_warn("Operation not permitted on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
}
continue;
}
@@ -4001,6 +4000,11 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
if (pp->pva.pvmetadatacopies < 0)
pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
if (pp->pva.pvmetadatacopies > 2) {
log_error("Metadatacopies may only be 0, 1 or 2");
return 0;
}
pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
return 1;

View File

@@ -159,15 +159,7 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
int locktype_arg(struct cmd_context *cmd, struct arg_values *av);
int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
/* we use the enums to access the switches */
unsigned arg_count(const struct cmd_context *cmd, int a);

View File

@@ -57,13 +57,11 @@
* 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
* generally making the parsing function recognize a new
* word, and making the implementation code also recognize
* that word to do something different. 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, and perhaps in a single place, perhaps in
* struct val_props.
* 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
@@ -94,9 +92,9 @@
* should avoid suggesting the upper case letters.
*/
val(none_VAL, NULL, "None", "ERR") /* unused, for enum value 0 */
val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
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)
@@ -118,19 +116,21 @@ 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")
/* FIXME: cling_by_tags is left out of help text because it makes the line wrap */
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|normal|anywhere|inherit")
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin")
val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]")
val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
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
*/

View File

@@ -482,9 +482,6 @@ static int _vgchange_metadata_copies(struct cmd_context *cmd,
{
uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES);
log_warn("vgchange_metadata_copies new %u vg_mda_copies %u D %u",
mda_copies, vg_mda_copies(vg), DEFAULT_VGMETADATACOPIES);
if (mda_copies == vg_mda_copies(vg)) {
if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED)
log_warn("Number of metadata copies for VG %s is already unmanaged.",

View File

@@ -157,12 +157,24 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, metadatacopies_ARG)) {
log_error("Invalid option --metadatacopies, "
"use --pvmetadatacopies instead.");
return EINVALID_CMD_LINE;
}
if (!(cmd->fmt->features & FMT_MDAS) &&
arg_is_set(cmd, pvmetadatacopies_ARG)) {
(arg_is_set(cmd, pvmetadatacopies_ARG) ||
arg_is_set(cmd, metadatasize_ARG))) {
log_error("Metadata parameters only apply to text format");
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, pvmetadatacopies_ARG) &&
arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
log_error("Metadatacopies may only be 0, 1 or 2");
return EINVALID_CMD_LINE;
}
if (!(cmd->fmt->features & FMT_BAS) &&
arg_is_set(cmd, bootloaderareasize_ARG)) {
log_error("Bootloader area parameters only apply to text format");

View File

@@ -136,6 +136,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_is_set(cmd, metadatacopies_ARG)) {
log_error("Invalid option --metadatacopies, "
"use --pvmetadatacopies instead.");
return EINVALID_CMD_LINE;
}
vg_name = skip_dev_dir(cmd, argv[0], NULL);
argc--;
argv++;