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
f4544b6ea1 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-19 16:00:56 -05:00
10 changed files with 5064 additions and 3776 deletions

View File

@@ -70,15 +70,27 @@
# in these definitions to keep them simpler. --extents is
# automatically included and recognized as an alternative to --size.
#
# lvcreate generally requires a VG arg in position 1 and does not
# require the --name option (when --name is omitted, a name is
# generated). But, all commands of that form have a variant which
# is not defined here, but which is automatically recognized as
# being equivalent. That variant allows the required VG arg to
# be omitted when --name VG/LV is specified, or when the
# LVM_VG_NAME env var is set and --name LV is specified.
# The lvcreate variants with --name and without a VG arg are
# automatically recognized as an alternative to the defined
# command forms requiring the VG and no --name.
# Also, --thinpool VG/LV or --cachepool VG/LV can be used in
# place of --name to provide the VG name instead of pos 1.
#
# Some options have multiple names, but only one form of the name
# is used in these definitions. Synonyms will be recognized when
# matching a command to a command definition.
#
# used in definitions below (equivalent but not used in definitions)
# mirrorlog core (corelog)
# resizeable (resizable)
# mirrorlog core (not corelog)
# resizeable (resizable or allocation)
# allocatable (allocation)
# resizeable (allocation)
# activate (available)
# rebuild (raidrebuild)
# syncaction (raidsyncaction)
@@ -86,11 +98,21 @@
# minrecoveryrate (raidminrecoveryrate)
# maxrecoveryrate (raidmaxrecoveryrate)
# writebehind (raidwritebehind)
# virtualsize (virtualoriginsize)
#
# metadatacopies/pvmetadatacopies/vgmetadatacopies are not considered
# synonyms for the purpose of command definitions, but each variant is
# specified when it is accepted.
#
# "---" is like a comment line, used to separate text for readability
#
# ID: A unique string identifying the command.
# ID: A unique string identifying the command. Two commands that do
# the same thing, but are alternate syntaxes can share the same ID,
# in which case the implementation would have to sort out which
# args to look at for the required parameters. Or, the two commands
# could use differnet IDs, in which case the implementation would
# know where to look for each parameter.
#
# DESC: A description of the command.
#
@@ -198,7 +220,7 @@ ID: lvchange_activate
DESC: Activate or deactivate an LV.
lvchange --refresh VG|LV|Tag|Select ...
OO: OO_LVCHANGE
OO: --partial, OO_LVCHANGE
ID: lvchange_refresh
lvchange --monitor Bool VG|LV|Tag|Select ...
@@ -217,7 +239,7 @@ ID: lvchange_persistent
---
OO_LVCONVERT_RAID: --mirrors SNumber, --stripes_long Number,
--stripesize SizeKB, --regionsize SizeMB
--stripesize SizeKB, --regionsize SizeMB, --interval Number
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
@@ -270,88 +292,112 @@ OO: --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV.
# alternate form of lvconvert --type snapshot
lvconvert --snapshot LV_linear_striped_raid LV_snapshot
OO: --chunksize SizeKB, --zero Bool, OO_LVCONVERT
ID: lvconvert_combine_split_snapshot
DESC: Combine LV with a previously split snapshot LV
DESC: (variant, infers --type snapshot).
---
lvconvert --type thin --thinpool LV LV_linear_striped_raid
OO: --thin, --originname LV_new, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thin_with_external
DESC: Convert LV to type thin with an external origin.
# alternate form of lvconvert --type thin
lvconvert --thin --thinpool LV LV_linear_striped_raid
OO: --type thin, --originname LV_new, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --type thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thin_with_external
DESC: Convert LV to type thin with an external origin
DESC: (variant, infers --type thin).
---
# FIXME: I don't think --zero applies when creating cache LV,
# but it's used in a test. Should the test be fixed and
# --zero removed here?
lvconvert --type cache --cachepool LV LV_linear_striped_raid_thinpool
OO: --cache, --cachepolicy String, --cachesettings String, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --cache, --cachemode CacheMode, --cachepolicy String,
--cachesettings String, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_cache_vol
DESC: Convert LV to type cache.
# alternate form of lvconvert --type cache
lvconvert --cache --cachepool LV LV_linear_striped_raid_thinpool
OO: --type cache, --cachepolicy String, --cachesettings String, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --type cache, --cachemode CacheMode, --cachepolicy String,
--cachesettings String, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_cache_vol
DESC: Convert LV to type cache (variant, infers --type cache).
---
# FIXME: stripes is an odd option, but if the pool metadata LV
# is created by the command, that LV is created with the
# specified number of stripes. Maybe we could separate the
# command definitions for cases where pool metadata LV is
# created and limit the use of stripes to that case?
lvconvert --type thin-pool LV_linear_striped_raid_cache
OO: --discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thinpool
DESC: Convert LV to type thin-pool.
# alternate form of lvconvert --type thin-pool
# deprecated because of non-standard syntax (missing positional arg)
lvconvert --thinpool LV
OO: OO_LVCONVERT_POOL, OO_LVCONVERT
lvconvert --thinpool LV_linear_striped_raid_cache
OO: --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thinpool
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
---
# FIXME: I don't think that --cachemode, --cachepolicy, --cachesettings
# are meant to be used when creating a cache pool, but they are used
# in one test. Should that test be fixed and these options removed?
lvconvert --type cache-pool LV_linear_striped_raid
OO: OO_LVCONVERT_POOL, OO_LVCONVERT
OO: OO_LVCONVERT_POOL, OO_LVCONVERT,
--cachemode CacheMode, --cachepolicy String, --cachesettings String
ID: lvconvert_to_cachepool
DESC: Convert LV to type cache-pool.
# alternate form of lvconvert --type cache-pool
# deprecated because of non-standard syntax (missing positional arg)
lvconvert --cachepool LV
OO: OO_LVCONVERT_POOL, OO_LVCONVERT
lvconvert --cachepool LV_linear_striped_raid
OO: --type cache-pool, OO_LVCONVERT_POOL, OO_LVCONVERT,
--cachemode CacheMode, --cachepolicy String, --cachesettings String
ID: lvconvert_to_cachepool
DESC: Convert LV to type cache-pool (variant, use --type cache-pool).
---
lvconvert --type mirror --mirrors SNumber LV_linear_striped
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
# FIXME: we should be able to remove LV_mirror from the list of accepted
# LV types, but there are some dubious commands in the test suite that
# fail without it (the tests should be cleaned up to avoid using commands
# that don't make sense.)
#
# FIXME: it would be nice to remove LV_raid1 from the list of accepted
# LV types and let raid1 be covered by just the second definition, but
# unfortunatley lvconvert --type mirror --mirrors N LV_raid1 will
# match the first definition since LV type cannot be used when
# matching command definitions.
lvconvert --type mirror --mirrors SNumber LV_linear_striped_raid1_mirror
OO: --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror
DESC: Convert LV to type mirror, adding mirror images.
# alternate form of lvconvert --type raid1|mirror
lvconvert --mirrors SNumber LV_linear_striped
OO: --type raid1, --type mirror, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror_or_raid1
DESC: Convert LV to type raid1 or mirror
DESC: (variant, infers --type raid1|mirror).
---
DESC: Convert LV to type mirror.
lvconvert --type mirror LV_raid1
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OO: --mirrors SNumber, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid1_to_mirror
DESC: Convert LV to type mirror, keeping mirror images.
lvconvert --type raid1 LV_mirror
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
ID: lvconvert_mirror_to_raid1
DESC: Convert LV to type raid1, keeping mirror images.
DESC: Convert LV from type raid1 to type mirror.
---
@@ -362,13 +408,13 @@ DESC: Convert LV to type raid1, keeping mirror images.
# FIXME: there are two different operations here, and it would
# be nice to split them into to unambiguous command lines:
#
# 1. lvconvert --type raid LV_linear_striped
# 1. lvconvert --type raid LV_linear_striped_mirror
# DESC: Convert LV to type raid.
#
# 2. lvconvert --type raid LV_raid
# DESC: Change LV raid type.
lvconvert --type raid LV_linear_striped_raid
lvconvert --type raid LV_linear_striped_mirror_raid
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_general_to_raid
@@ -377,11 +423,35 @@ DESC: Change LV raid type.
---
lvconvert --mirrors SNumber LV_raid_mirror
OO: OO_LVCONVERT
# FIXME: there are two unique operations here that differ
# by only the LV type, so they have to be defined together.
# We don't know what this command is going to do until after
# the LV is read. It would be better if the alternate form
# variant were dropped to remove the ambiguity
# (then --type raid1|mirror would be required to change a
# linear or striped LV to raid1|mirror.)
#
# First command definition
# this changes the number of mirror images in a raid1|mirror LV.
# lvconvert --mirrors SNumber LV_raid_mirror
# ID: lvconvert_change_mirror_images
# DESC: Change the number of mirror images in the LV.
#
# Second command definition
# alternate form of: lvconvert --type raid1|mirror LV_linear_striped
# lvconvert --mirrors SNumber LV_linear_striped
# ID: lvconvert_to_raid1_or_mirror
# DESC: Convert LV to type raid1 or mirror
# DESC: (variant, infers --type raid1|mirror).
# first def is unique, second def is alternate form of lvconvert --type raid1|mirror
lvconvert --mirrors SNumber LV_raid_mirror_linear_striped
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_change_mirror_images
DESC: Change the number of mirror images in the LV.
ID: lvconvert_to_mirrored_or_change_image_count
DESC: Change the number of mirror images in a raid1 or mirror LV.
DESC: Convert a linear or striped LV to type raid1 or mirror
DESC: (variant, infers --type raid1|mirror).
---
@@ -398,15 +468,27 @@ OO: OO_LVCONVERT
ID: lvconvert_raid_or_mirror_to_linear
DESC: Convert LV to type linear.
# FIXME: the 'mirrors 0' trick as an alias for linear
# is used inconsistently, confusing things and making
# definitions difficult.
# alternate form of lvconvert --type linear
lvconvert --mirrors 0 LV_raid_mirror
OO: --type linear, --type mirror, OO_LVCONVERT
ID: lvconvert_raid_or_mirror_to_linear
DESC: Convert LV to type linear (variant, infers --type linear).
---
lvconvert --splitmirrors Number --name LV_new LV_raid1_mirror_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images_to_new
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images_and_track
DESC: Split images from a raid1 LV and track changes to origin.
@@ -444,6 +526,7 @@ DESC: Replace specific PV(s) in a raid* LV with another PV.
lvconvert --mirrorlog MirrorLog LV_mirror
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_change_mirrorlog
DESC: Change the type of log used by LV.
@@ -500,7 +583,13 @@ OO_LVCREATE_CACHE: --cachemode CacheMode, --cachepolicy String, --cachesettings
OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool
# FIXME: it's silly to include --mirrors 0 here. Fix the tests to not use
# --mirrors 0 in commands that do not accept any non-zero --mirrors
# option, and then remove this. Accepting an option, only so that the
# option's value can invalidate the use of the option is not general
# practice.
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool, --mirrors 0
OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
--regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB
@@ -521,14 +610,18 @@ DESC: Create an LV that returns zeros when read.
---
# FIXME: consider removing the --mirrors 0, --stripes 1 options
# and just reporting an error (or ignoring) if mirrors or stripes
# options are given.
lvcreate --type linear --size SizeMB VG
OO: OO_LVCREATE
OO: --mirrors 0, --stripes 1, OO_LVCREATE
OP: PV ...
ID: lvcreate_linear
DESC: Create a linear LV.
lvcreate --size SizeMB VG
OO: --type linear, OO_LVCREATE
OO: --type linear, --mirrors 0, --stripes 1, OO_LVCREATE
OP: PV ...
ID: lvcreate_linear
DESC: Create a linear LV (default --type linear).
@@ -551,14 +644,14 @@ DESC: Create a striped LV (infers --type striped).
---
lvcreate --type mirror --size SizeMB VG
OO: --mirrors SNumber, --mirrorlog MirrorLog, --corelog, --regionsize SizeMB, OO_LVCREATE
OO: --mirrors SNumber, --mirrorlog MirrorLog, --regionsize SizeMB, --stripes Number, OO_LVCREATE
OP: PV ...
ID: lvcreate_mirror
DESC: Create a mirror LV.
# alternate form of lvcreate --type raid1|mirror
lvcreate --mirrors SNumber --size SizeMB VG
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, --corelog, OO_LVCREATE_RAID, OO_LVCREATE
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, --stripes Number, OO_LVCREATE_RAID, OO_LVCREATE
OP: PV ...
ID: lvcreate_mirror
DESC: Create a raid1 or mirror LV (variant, infers --type raid1|mirror).
@@ -573,43 +666,90 @@ DESC: Create a raid LV (a specific raid level must be used, e.g. raid1.)
---
# FIXME: the LV created by these commands actually has type linear or striped,
# not snapshot as specified by the command. If LVs never have type
# snapshot, perhaps "snapshot" should not be considered an LV type, but
# another new LV property?
lvcreate --type snapshot --size SizeMB LV
OO: --snapshot, OO_LVCREATE
OO: --snapshot, --chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_cow_snapshot
DESC: Create a COW snapshot LV from an origin LV.
# alternate form of lvcreate --type snapshot
lvcreate --snapshot --size SizeMB LV
OO: --type snapshot, OO_LVCREATE
OO: --type snapshot, --stripes Number, --stripesize SizeKB,
--chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_cow_snapshot
DESC: Create a COW snapshot LV from an origin LV
DESC: (infers --type snapshot).
# If this snapshot+striped command was merged with lvcreate_cow_snapshot
# by adding --stripes in OO, then this command would be difficult to
# distiguish from lvcreate_striped based on required options. But, it may
# work if command matching used optional options to score matches rather
# than only using required options.
lvcreate --type snapshot --stripes Number --size SizeMB LV
OO: --snapshot, --stripes Number, --stripesize SizeKB,
--chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_striped_cow_snapshot
DESC: Create a striped COW snapshot LV from an origin LV.
# alternate form of lvcreate --type snapshot --stripes
lvcreate --snapshot --stripes Number --size SizeMB LV
OO: --type snapshot, --stripes Number, --stripesize SizeKB,
--chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_striped_cow_snapshot
DESC: Create a striped COW snapshot LV from an origin LV
DESC: (infers --type snapshot).
---
lvcreate --type snapshot --size SizeMB --virtualsize SizeMB VG
OO: --snapshot, --virtualoriginsize SizeMB, OO_LVCREATE
OO: --snapshot, --chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_cow_snapshot_with_virtual_origin
DESC: Create a sparse COW snapshot LV of a virtual origin LV.
# alternate form of lvcreate --type snapshot
lvcreate --snapshot --size SizeMB --virtualsize SizeMB VG
OO: --type snapshot, --chunksize SizeKB, OO_LVCREATE
OP: PV ...
ID: lvcreate_cow_snapshot_with_virtual_origin
DESC: Create a sparse COW snapshot LV of a virtual origin LV
DESC: (infers --type snapshot).
---
lvcreate --type thin-pool --size SizeMB VG
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thinpool
DESC: Create a thin pool.
# alternate form of lvcreate --type thin-pool
lvcreate --thin --size SizeMB VG
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thinpool
DESC: Create a thin pool (variant, infers --type thin-pool).
# alternate form of lvcreate --type thin-pool
lvcreate --size SizeMB --thinpool LV_new VG
OO: --thin, --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thinpool
DESC: Create a thin pool named by the --thinpool arg
DESC: (variant, infers --type thin-pool).
---
lvcreate --type cache-pool --size SizeMB VG
@@ -625,26 +765,63 @@ OP: PV ...
ID: lvcreate_cachepool
DESC: Create a cache pool (variant, infers --type cache-pool).
# alternate form of lvcreate --type cache-pool
lvcreate --type cache-pool --size SizeMB --cachepool LV_new VG
OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
OP: PV ...
ID: lvcreate_cachepool
DESC: Create a cache pool named by the --cachepool arg
DESC: (variant, uses --cachepool in place of --name).
---
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: VG
ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool.
# alternate form of lvcreate --type thin
lvcreate --type thin --virtualsize SizeMB LV_thinpool
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool named in arg pos 1
DESC: (variant, also see --thinpool).
# alternate form of lvcreate --type thin
lvcreate --virtualsize SizeMB --thinpool LV_thinpool
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
OP: VG
ID: lvcreate_thin_vol
DESC: Create a thin LV in a thin pool (variant, infers --type thin).
# alternate form of lvcreate --type thin
lvcreate --virtualsize SizeMB LV_thinpool
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
ID: lvcreate_thin_vol
DESC: Create a thin LV in the thin pool named in arg pos 1
DESC: (variant, infers --type thin, also see --thinpool).
---
# FIXME: in addition to confusing and unpredictable,
# this jumble of variations of the same thing is inconsistent:
# lvcreate --thin LV_thin and lvcreate --snapshot LV_thin
# are the same command, both creating a thin snapshot,
# but lvcreate --thin --snapshot LV_thin does not.
lvcreate --type thin LV_thin
OO: OO_LVCREATE_THIN, OO_LVCREATE
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
ID: lvcreate_thin_snapshot
DESC: Create a thin LV that is a snapshot of an existing thin LV.
# alternate form of lvcreate --type thin
lvcreate --thin LV_thin
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
ID: lvcreate_thin_snapshot
DESC: Create a thin LV that is a snapshot of an existing thin LV
DESC: (infers --type thin).
# alternate form of lvcreate --type thin LV_thin
lvcreate --snapshot LV_thin
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
@@ -666,8 +843,13 @@ DESC: (infers --type thin).
---
# stripes option is not intuitive when creating a thin LV,
# but here it applies to creating the new thin pool that
# is used for the thin LV
lvcreate --type thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool
DESC: Create a thin LV, first creating a thin pool for it,
@@ -675,7 +857,8 @@ DESC: where the new thin pool is named by the --thinpool arg.
# alternate form of lvcreate --type thin
lvcreate --thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool
DESC: Create a thin LV, first creating a thin pool for it,
@@ -683,14 +866,16 @@ DESC: where the new thin pool is named by the --thinpool arg,
DESC: (variant, infers --type thin).
lvcreate --type thin --virtualsize SizeMB --size SizeMB LV_new
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool
DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool is named in arg pos 1.
lvcreate --thin --virtualsize SizeMB --size SizeMB LV_new
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool
DESC: Create a thin LV, first creating a thin pool for it,
@@ -698,7 +883,8 @@ DESC: where the new thin pool is named in arg pos 1,
DESC: (variant, infers --type thin).
lvcreate --type thin --virtualsize SizeMB --size SizeMB VG
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool
DESC: Create a thin LV, first creating a thin pool for it.
@@ -706,8 +892,8 @@ DESC: Create a thin LV, first creating a thin pool for it.
---
lvcreate --size SizeMB --virtualsize SizeMB VG
OO: --type thin, --type snapshot, --thin, --snapshot,
--virtualoriginsize SizeMB, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OO: --type thin, --type snapshot, --thin, --snapshot, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
DESC: Create a thin LV, first creating a thin pool for it
@@ -719,31 +905,87 @@ DESC: confing setting sparse_segtype_default.
---
# FIXME: this should be done by lvconvert, and this command deprecated
# stripes option is not intuitive when creating a cache LV,
# but here it applies to creating the new origin that
# is used to create the cache LV
lvcreate --type cache --size SizeMB LV
OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
OP: PV ...
ID: lvcreate_convert_to_cache_vol_with_cachepool
DESC: Convert the specified LV to type cache after creating a new
DESC: cache pool LV to use.
---
lvcreate --type cache --size SizeMB --cachepool LV_cachepool
OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
lvcreate --type cache --size SizeMB --cachepool LV_cachepool VG
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_cache_vol_with_new_origin
DESC: Create a cache LV, first creating a new origin LV,
DESC: then combining it with the existing cache pool in arg pos 1.
DESC: then combining it with the existing cache pool named
DESC: by the --cachepool arg.
lvcreate --size SizeMB --cachepool LV_cachepool
OO: --type cache, OO_LVCREATE_CACHE, OO_LVCREATE
# alternate form of lvcreate --type cache
lvcreate --size SizeMB --cachepool LV_cachepool VG
OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_cache_vol_with_new_origin
DESC: Create a cache LV, first creating a new origin LV,
DESC: then combining it with the existing cache pool in arg pos 1.
DESC: (variant, infers --type cache).
DESC: then combining it with the existing cache pool named
DESC: by the --cachepool arg (variant, infers --type cache).
# alternate form of lvcreate --type cache
lvcreate --type cache --size SizeMB LV_cachepool
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_cache_vol_with_new_origin
DESC: Create a cache LV, first creating a new origin LV,
DESC: then combining it with the existing cache pool named
DESC: by in arg pos 1 (variant, also use --cachepool).
# This is a ridiculously crazy command which nobody could
# understand. It should be be eliminated. It does two different
# things depending on whether LV in pos 1 is a cachepool LV
# or not. Both variations are unnecessary.
#
# 1. If LV is a cachepool, then it's an alternate form of
# an already crazy command above:
#
# # alternate form for lvcreate_cache_vol_with_new_origin
# lvcreate --cache --size SizeMB LV_cachepool
# OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE, --stripes Number, --stripesize SizeKB
# OP: PV ...
# ID: lvcreate_cache_vol_with_new_origin
# DESC: Create a cache LV, first creating a new origin LV,
# DESC: then combining it with the existing cache pool named
# DESC: in arg pos 1 (variant, infers --type cache,
# DESC: also use --cachepool).
#
# If LV is not a cachepool, then it's a disguised lvconvert:
#
# # FIXME: this should be done by lvconvert, and this command removed
# lvcreate --type cache --size SizeMB LV
# OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
# OP: PV ...
# ID: lvcreate_convert_to_cache_vol_with_cachepool
# DESC: Convert the specified LV to type cache after creating a new
# DESC: cache pool LV to use (use lvconvert).
#
# Note that stripes are accepted by the first and not by the
# second, but it's not possible to validate this until after
# the LV type is known.
#
# So, to define this syntax we have to combine both of
# those variants, each crazy on it's own, into one.
# def1: alternate form of lvcreate --type cache, or
# def2: FIXME: it should be done by lvconvert.
lvcreate --cache --size SizeMB LV
OO: OO_LVCREATE_CACHE, OO_LVCREATE, --stripes Number, --stripesize SizeKB
OP: PV ...
ID: lvcreate_cache_vol_with_new_origin_or_convert_to_cache_vol_with_cachepool
DESC: When LV is a cache pool, create a cache LV,
DESC: first creating a new origin LV, then combining it with
DESC: the existing cache pool named in arg pos 1
DESC: (variant, infers --type cache, also use --cachepool).
DESC: When LV is not a cache pool, convert the specified LV
DESC: to type cache after creating a new cache pool LV to use
DESC: (use lvconvert).
---
@@ -1167,21 +1409,36 @@ OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
--maxlogicalvolumes Number, --maxphysicalvolumes Number,
--metadatatype MetadataType, --vgmetadatacopies MetadataCopies
# FIXME: it would be nice to have separate definitions
# for the cases where the destination VG exists or is new,
# but when choosing the command definition, we don't yet
# know if the destination VG exists or not. So to do this
# we'd need a command option to specify if the VG is new.
#
# this won't work:
# vgsplit VG VG PV
# ID: vgsplit_by_pv_to_existing
#
# vgsplit VG VG_new PV ...
# ID: vgsplit_by_pv_to_new
#
# but this could:
# vgsplit VG VG PV
# ID: vgsplit_by_pv_to_existing
#
# vgsplit --create-new VG VG_new PV ...
# ID: vgsplit_by_pv_to_new
#
# Then the OO_VGSPLIT_NEW options could be
# included in the second case but not the first.
vgsplit VG VG PV ...
OO: OO_VGSPLIT
ID: vgsplit_by_pv_to_existing
OO: OO_VGSPLIT, OO_VGSPLIT_NEW
ID: vgsplit_by_pv
vgsplit --name LV VG VG
OO: OO_VGSPLIT
ID: vgsplit_by_lv_to_existing
vgsplit VG VG_new PV ...
OO: OO_VGSPLIT, OO_VGSPLIT_NEW
ID: vgsplit_by_pv_to_new
vgsplit --name LV VG VG_new
OO: OO_VGSPLIT, OO_VGSPLIT_NEW
ID: vgsplit_by_lv_to_new
ID: vgsplit_by_lv
---

View File

@@ -1911,12 +1911,8 @@ static void print_ambiguous(void)
continue;
if (cmd->ro_count != dup->ro_count)
continue;
if (cmd->oo_count != dup->oo_count)
continue;
if (cmd->rp_count != dup->rp_count)
continue;
if (cmd->op_count != dup->op_count)
continue;
for (ro = 0; ro < cmd->ro_count; ro++) {
if (!opt_arg_matches(&cmd->required_opt_args[ro],

View File

@@ -81,7 +81,8 @@ lvcreate -l1 -s -n inval $vg/$lv3
lvcreate -l4 -I4 -i2 -n stripe $vg
# Invalidate snapshot
not dd if=/dev/zero of="$DM_DEV_DIR/$vg/inval" bs=4K
invalid lvscan "$dev1"
# ignores unused positional arg dev1
lvscan "$dev1"
lvdisplay --maps
lvscan --all
@@ -108,13 +109,16 @@ vgmknodes --refresh
lvscan
lvmdiskscan
invalid pvscan "$dev1"
# ignores unused arg
pvscan "$dev1"
invalid pvscan -aay
invalid pvscan --major 254
invalid pvscan --minor 0
invalid pvscan --novolumegroup -e
invalid vgscan $vg
invalid lvscan $vg
# ignores unsed arg
vgscan $vg
# ignroes unused arg
lvscan $vg
if aux have_readline; then
cat <<EOF | lvm

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

@@ -1,6 +1,6 @@
/* Do not edit. This file is generated by scripts/create-commands */
/* using command definitions from scripts/command-lines.in */
#define COMMAND_COUNT 146
#define COMMAND_COUNT 153
enum {
no_CMD,
lvchange_properties_CMD,
@@ -19,11 +19,9 @@ enum {
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_to_mirrored_or_change_image_count_CMD,
lvconvert_raid_to_striped_CMD,
lvconvert_raid_or_mirror_to_linear_CMD,
lvconvert_split_mirror_images_to_new_CMD,
@@ -43,6 +41,7 @@ enum {
lvcreate_mirror_CMD,
lvcreate_raid_any_CMD,
lvcreate_cow_snapshot_CMD,
lvcreate_striped_cow_snapshot_CMD,
lvcreate_cow_snapshot_with_virtual_origin_CMD,
lvcreate_thinpool_CMD,
lvcreate_cachepool_CMD,
@@ -51,8 +50,8 @@ enum {
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,
lvcreate_cache_vol_with_new_origin_or_convert_to_cache_vol_with_cachepool_CMD,
lvdisplay_general_CMD,
lvextend_by_size_CMD,
lvextend_by_pv_CMD,
@@ -110,10 +109,8 @@ enum {
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,
vgsplit_by_pv_CMD,
vgsplit_by_lv_CMD,
devtypes_general_CMD,
fullreport_general_CMD,
lastlog_general_CMD,

File diff suppressed because it is too large Load Diff

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

@@ -750,6 +750,81 @@ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
return int_arg(cmd, av);
}
/*
* 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;
}
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;
}
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[]
@@ -761,6 +836,7 @@ 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;
/*
@@ -774,6 +850,7 @@ 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;
@@ -783,16 +860,36 @@ static void _set_valid_args_for_command_name(int ci)
for (i = 0; i < ARG_COUNT; i++) {
if (all_args[i]) {
command_names[ci].valid_args[num_args] = _cmdline.arg_props[i].arg_enum;
opt_enum = _cmdline.arg_props[i].arg_enum;
command_names[ci].valid_args[num_args] = opt_enum;
num_args++;
/* Automatically recognize --extents in addition to --size. */
if (_cmdline.arg_props[i].arg_enum == size_ARG) {
if (opt_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;
}
@@ -861,49 +958,25 @@ void lvm_register_commands(void)
_set_valid_args_for_command_name(i);
}
static int _opt_equivalent_is_set(struct cmd_context *cmd, int opt)
/*
* 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)
{
if ((opt == mirrorlog_ARG) && arg_is_set(cmd, corelog_ARG))
return 1;
int opt_syn = _opt_standard_to_synonym(cmd->name, opt_std);
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;
return opt_syn && arg_is_set(cmd, opt_syn);
}
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))
if (arg_is_set(cmd, opt_enum) || _opt_synonym_is_set(cmd, opt_enum))
goto check_val;
/*
@@ -918,9 +991,6 @@ 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;
/*
@@ -952,12 +1022,13 @@ 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. */
@@ -972,6 +1043,36 @@ 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;
}
@@ -1186,14 +1287,22 @@ 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_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 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 ro, rp;
int i, j;
int opt_enum, opt_i;
int accepted, count;
name = last_path_component(path);
@@ -1206,27 +1315,34 @@ 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_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 */
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));
/* if the command name alone is enough, then that's a match */
if (!commands[i].ro_count && !commands[i].rp_count)
match_count = 1;
match_required = 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_count++;
match_count_ro++;
match_required++;
match_ro++;
if (commands[i].required_opt_args[ro].opt == type_ARG)
match_type = 1;
} else {
/* cmd is missing a required opt arg */
/* log_warn("mismatch %d ro opt %d", i, commands[i].required_opt_args[ro].opt); */
mismatch_count++;
mismatch_required++;
}
}
@@ -1235,12 +1351,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_count_ro) {
if (match_ro) {
/* one or more of the required_opt_args is used */
mismatch_count = 0;
mismatch_required = 0;
} else {
/* not even one of the required_opt_args is used */
mismatch_count = 1;
mismatch_required = 1;
}
}
@@ -1249,124 +1365,128 @@ 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_count++;
match_count_rp++;
match_required++;
match_rp++;
} else {
/* cmd is missing a required pos arg */
/* log_warn("mismatch %d rp %d", i, commands[i].required_pos_args[rp].pos); */
mismatch_count++;
mismatch_required++;
}
}
/* if cmd is missing any required opt/pos args, it can't be this command. */
if (mismatch_count) {
if (mismatch_required) {
/* save "closest" command that doesn't match */
if (match_count_ro && (match_count_ro > closest_count_ro)) {
closest_i = i;
closest_count_ro = match_count_ro;
if ((match_type && !close_type) ||
((match_type == close_type) && (match_ro > close_ro))) {
close_i = i;
close_ro = match_ro;
close_type = match_type;
}
continue;
}
if (!match_count)
if (!match_required)
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_count_ro || match_count_rp))
match_count++;
if ((commands[i].ro_count || commands[i].rp_count) && (match_ro || match_rp))
match_required++;
/* log_warn("command %d has match_count %d match_ro %d match_rp %d",
i, match_count, match_count_ro, match_count_rp); */
/* 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;
}
}
/*
* 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_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); */
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); */
best_i = i;
best_count = match_count;
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));
}
}
if (!best_count) {
if (!best_required) {
/* 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_ro) {
if (close_ro) {
log_warn("Closest command usage is:");
_print_usage(_cmdline.commands[closest_i].usage, 1);
_print_usage(_cmdline.commands[close_i].usage, 1);
}
return NULL;
}
/*
* 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 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.
*/
/*
* 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.",
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
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]));
}
return NULL;
}
/*
@@ -1377,6 +1497,9 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
*
* Otherwise, warn about positional args that exist beyond the number of
* required + optional pos_args.
*
* FIXME: should an unused positional arg cause the command to fail
* like an unused option?
*/
count = commands[best_i].rp_count;
@@ -1399,7 +1522,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
}
}
out:
log_debug("command line id: %s (%d)", commands[best_i].command_line_id, best_i);
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
return &commands[best_i];
}
@@ -1455,6 +1578,8 @@ 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.");
@@ -2284,7 +2409,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
log_debug("Parsing: %s", cmd->cmd_line);
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
return_ECMD_FAILED;
return EINVALID_CMD_LINE;
set_cmd_name(cmd->name);

View File

@@ -2555,10 +2555,14 @@ 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 on LV %s with type %s.", display_lvname(lv), seg->segtype->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);
ret_max = ECMD_FAILED;
} else {
log_warn("Operation not permitted on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
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);
}
continue;
}

View File

@@ -126,8 +126,8 @@ val(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Num
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:
* FIXME: 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,