1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-24 21:44:22 +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
10 changed files with 4086 additions and 5279 deletions

View File

@@ -70,27 +70,15 @@
# 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 (not corelog)
# resizeable (resizable or allocation)
# mirrorlog core (corelog)
# resizeable (resizable)
# allocatable (allocation)
# resizeable (allocation)
# activate (available)
# rebuild (raidrebuild)
# syncaction (raidsyncaction)
@@ -98,11 +86,7 @@
# 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
#
@@ -202,20 +186,17 @@ OO: OO_LVCHANGE
ID: lvchange_properties
DESC: Change a general LV property.
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
lvchange --resync VG|LV|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_resync
DESC: Resyncronize a mirror or raid LV.
lvchange --syncaction String VG|LV_raid|Tag|Select ...
lvchange --syncaction String VG|LV|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_syncaction
DESC: Resynchronize or check a raid LV.
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
lvchange --rebuild PV VG|LV|Tag|Select ...
OO: OO_LVCHANGE
ID: lvchange_rebuild
DESC: Reconstruct data on specific PVs of a raid LV.
lvchange --activate Active VG|LV|Tag|Select ...
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip, OO_LVCHANGE_META, OO_LVCHANGE
@@ -223,29 +204,26 @@ ID: lvchange_activate
DESC: Activate or deactivate an LV.
lvchange --refresh VG|LV|Tag|Select ...
OO: --partial, OO_LVCHANGE
OO: OO_LVCHANGE
ID: lvchange_refresh
DESC: Reactivate an LV using the latest metadata.
lvchange --monitor Bool VG|LV|Tag|Select ...
OO: --poll Bool, OO_LVCHANGE
ID: lvchange_monitor
DESC: Start or stop monitoring an LV from dmeventd.
DESC: Monitor or unmonitor an LV.
lvchange --poll Bool VG|LV|Tag|Select ...
OO: --monitor Bool, OO_LVCHANGE
ID: lvchange_poll
DESC: Start or stop processing an LV conversion.
lvchange --persistent Bool VG|LV|Tag|Select ...
OO: --minor Number, --major Number, OO_LVCHANGE
ID: lvchange_persistent
DESC: Make the minor device number persistent for an LV.
---
OO_LVCONVERT_RAID: --mirrors SNumber, --stripes_long Number,
--stripesize SizeKB, --regionsize SizeMB, --interval Number
--stripesize SizeKB, --regionsize SizeMB
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
@@ -280,7 +258,7 @@ OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync,
# current LV type.
lvconvert --merge LV_linear_striped_raid_thin_snapshot|VG|Tag ...
OO: --background, --interval Number, OO_LVCONVERT
OO: --background, --interval Number
ID: lvconvert_merge
DESC: Merge LV that was previously split from a mirror.
DESC: Merge thin LV into its origin LV.
@@ -298,23 +276,16 @@ 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, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --thin, --originname LV_new, 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, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --type thin, --originname LV_new, 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).
@@ -340,23 +311,15 @@ 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: --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
OO: --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_linear_striped_raid_cache
OO: --stripes_long Number, --stripesize SizeKB,
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
lvconvert --thinpool LV
OO: OO_LVCONVERT_POOL, OO_LVCONVERT
ID: lvconvert_to_thinpool
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
@@ -382,28 +345,31 @@ DESC: Convert LV to type cache-pool (variant, use --type cache-pool).
---
# 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 the LV type cannot be used when
# choosing a matching command definition.
lvconvert --type mirror --mirrors SNumber LV_linear_striped_raid1_mirror
OO: --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
lvconvert --type mirror --mirrors SNumber LV_linear_striped
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror
DESC: Convert LV to type 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).
---
lvconvert --type mirror LV_raid1
OO: --mirrors SNumber, OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_to_mirror
DESC: Convert LV from type raid1 to type mirror.
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
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.
---
@@ -412,52 +378,28 @@ DESC: Convert LV from type raid1 to type mirror.
# help the second fixme...
#
# FIXME: there are two different operations here, and it would
# be nice to split them into two unambiguous command lines:
# be nice to split them into to unambiguous command lines:
#
# 1. lvconvert --type raid LV_linear_striped_mirror
# 1. lvconvert --type raid LV_linear_striped
# DESC: Convert LV to type raid.
#
# 2. lvconvert --type raid LV_raid
# DESC: Change LV raid type.
lvconvert --type raid LV_linear_striped_mirror_raid
lvconvert --type raid LV_linear_striped_raid
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_general_to_raid
DESC: Convert LV to type raid.
DESC: Change LV between raid types.
DESC: Change LV raid type.
---
# 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
lvconvert --mirrors SNumber LV_raid_mirror
OO: OO_LVCONVERT
OP: PV ...
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).
ID: lvconvert_change_mirror_images
DESC: Change the number of mirror images in the LV.
---
@@ -474,27 +416,15 @@ 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.
@@ -532,23 +462,22 @@ 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 mirror log used by a mirror LV.
DESC: Change the type of log used by LV.
---
lvconvert --splitcache LV_cachepool_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_keep_cachepool
DESC: Separate and keep the cache pool from a cache LV.
DESC: Separate and preserve a cache pool from a cache LV.
---
lvconvert --uncache LV_cache_thinpool
OO: OO_LVCONVERT
ID: lvconvert_split_and_delete_cachepool
DESC: Separate and delete the cache pool from a cache LV.
DESC: Separate and remove a cache pool from a cache LV.
---
@@ -563,16 +492,14 @@ DESC: Separate a COW snapshot from its origin LV.
# The purpose of this command is not entirely clear.
lvconvert LV_mirror
OO: OO_LVCONVERT
ID: lvconvert_poll_mirror
DESC: Poll mirror LV to collapse resync layers.
DESC: Poll LV to collapse resync layers.
---
# FIXME: add a new option defining this operation, e.g. --swapmetadata
lvconvert --poolmetadata LV LV_thinpool_cachepool
OO: OO_LVCONVERT
ID: lvconvert_swap_pool_metadata
DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
@@ -591,12 +518,7 @@ OO_LVCREATE_CACHE: --cachemode CacheMode, --cachepolicy String, --cachesettings
OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB
# 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 advisable.
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool, --mirrors 0
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool
OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
--regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB
@@ -617,27 +539,17 @@ 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. Same reasoning as above: it's confusing to
# advertise an option when the only value accepted for the option
# makes the option do nothing.
lvcreate --type linear --size SizeMB VG
OO: --mirrors 0, --stripes 1, OO_LVCREATE
OO: OO_LVCREATE
OP: PV ...
ID: lvcreate_linear
DESC: Create a linear LV.
# This is the one place we mention the optional --name
# because it's the most common case and may be confusing
# to people to not see the name parameter.
lvcreate --size SizeMB VG
OO: --type linear, --mirrors 0, --stripes 1, OO_LVCREATE
OO: --type linear, OO_LVCREATE
OP: PV ...
ID: lvcreate_linear
DESC: Create a linear LV (default --type linear).
DESC: Create a linear LV (default --type linear).
DESC: When --name is omitted, the name is generated.
---
@@ -657,24 +569,20 @@ DESC: Create a striped LV (infers --type striped).
---
lvcreate --type mirror --size SizeMB VG
OO: --mirrors SNumber, --mirrorlog MirrorLog, --regionsize SizeMB, --stripes Number, OO_LVCREATE
OO: --mirrors SNumber, --mirrorlog MirrorLog, --corelog, --regionsize SizeMB, OO_LVCREATE
OP: PV ...
ID: lvcreate_mirror
DESC: Create a mirror LV (also see --type raid1).
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, --stripes Number, OO_LVCREATE_RAID, OO_LVCREATE
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, --corelog, OO_LVCREATE_RAID, OO_LVCREATE
OP: PV ...
ID: lvcreate_mirror_or_raid1
ID: lvcreate_mirror
DESC: Create a raid1 or mirror LV (variant, infers --type raid1|mirror).
---
# FIXME: we should probably expand this from raid* to
# various specific raid levels, then narrow the range
# of options applicable to each.
lvcreate --type raid --size SizeMB VG
OO: OO_LVCREATE_RAID, OO_LVCREATE
OP: PV ...
@@ -683,28 +591,15 @@ 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?
#
# Or, perhaps we should not promote --type snapshot, and
# prefer --snapshot as the primary syntax, since the type
# is not really snapshot (which makes it different from
# all the other cases of using --type, where the resulting
# LV does have the specified type.)
lvcreate --type snapshot --size SizeMB LV
OO: --snapshot, --stripes Number, --stripesize SizeKB,
--chunksize SizeKB, OO_LVCREATE
OO: --snapshot, 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, --stripes Number, --stripesize SizeKB,
--chunksize SizeKB, OO_LVCREATE
OO: --type snapshot, OO_LVCREATE
OP: PV ...
ID: lvcreate_cow_snapshot
DESC: Create a COW snapshot LV from an origin LV
@@ -713,45 +608,26 @@ DESC: (infers --type snapshot).
---
lvcreate --type snapshot --size SizeMB --virtualsize SizeMB VG
OO: --snapshot, --chunksize SizeKB, OO_LVCREATE
OO: --snapshot, --virtualoriginsize SizeMB, 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: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
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,
--stripes Number, --stripesize SizeKB
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
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
@@ -767,32 +643,16 @@ 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 VG
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
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 the first arg
DESC: (variant, also see --thinpool for naming pool).
# alternate form of lvcreate --type thin
lvcreate --virtualsize SizeMB --thinpool LV_thinpool
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).
@@ -800,25 +660,17 @@ DESC: Create a thin LV in a thin pool (variant, infers --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 the first arg
DESC: (variant, infers --type thin, also see --thinpool for
DESC: naming pool.)
DESC: Create a thin LV in the thin pool named in arg pos 1
DESC: (variant, infers --type thin).
---
lvcreate --type thin LV_thin
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
OO: 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
# alternate form of lvcreate --type thin LV_thin
lvcreate --snapshot LV_thin
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
ID: lvcreate_thin_snapshot
@@ -839,151 +691,84 @@ 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,
--stripes Number, --stripesize SizeKB
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_and_thinpool
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 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,
--stripes Number, --stripesize SizeKB
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_and_thinpool
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 by the --thinpool arg
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,
--stripes Number, --stripesize SizeKB
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_and_thinpool
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 the first arg.
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,
--stripes Number, --stripesize SizeKB
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_and_thinpool
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 the first arg
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,
--stripes Number, --stripesize SizeKB
OO: OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_and_thinpool
DESC: Create a thin LV, first creating a thin pool for it,
DESC: where the new thin pool name is generated automatically.
ID: lvcreate_thin_vol_with_thinpool
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, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OO: --type thin, --type snapshot, --thin, --snapshot,
--virtualoriginsize SizeMB, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
OP: PV ...
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
DESC: Create a thin LV, first creating a thin pool for it
DESC: (infers --type thin).
DESC: Create a sparse snapshot of a virtual origin LV
DESC: (infers --type snapshot).
DESC: Chooses --type thin or --type snapshot according to
DESC: config setting sparse_segtype_default.
DESC: Infers --type thin or --type snapshot according to
DESC: confing setting sparse_segtype_default.
---
# 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
# FIXME: this should be done by lvconvert, and this command deprecated
lvcreate --type cache --size SizeMB --cachepool LV_cachepool VG
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
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: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
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 the --cachepool arg.
DESC: then combining it with the existing cache pool in arg pos 1.
# 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
lvcreate --size SizeMB --cachepool LV_cachepool
OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE
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 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: in the first arg (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 complicated 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 the first arg (variant, infers --type cache,
# DESC: also use --cachepool).
#
# 2. 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
# ridiculous command.
# def1: alternate form of lvcreate --type cache, or
# def2: 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 the first arg
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).
DESC: then combining it with the existing cache pool in arg pos 1.
DESC: (variant, infers --type cache).
---
@@ -1007,7 +792,6 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
--stripes Number, --stripesize SizeKB, --test, --poolmetadatasize SizeMB
OP: PV ...
ID: lvextend_by_size
DESC: Extend an LV by a specified size.
lvextend LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
@@ -1015,7 +799,6 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB,
--test
ID: lvextend_by_pv
DESC: Extend an LV by a specified PV.
lvextend --poolmetadatasize SizeMB LV_thinpool
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
@@ -1024,7 +807,6 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
--test
OP: PV ...
ID: lvextend_pool_metadata_by_size
DESC: Extend a pool metadata SubLV by a specified size.
lvextend --usepolicies LV_thinpool_snapshot
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
@@ -1032,7 +814,6 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
--reportformat String, --resizefs,
--test
ID: lvextend_by_policy
DESC: Extend an LV according to a predefined policy.
---
@@ -1089,7 +870,7 @@ OO: --alloc Alloc, --autobackup Bool, --force,
--test
OP: PV ...
ID: lvresize_pool_metadata_by_size
DESC: Resize a pool metadata SubLV by a specified size.
DESC: Resize the metadata SubLV of a pool LV.
---
@@ -1118,12 +899,10 @@ OO_PVCHANGE_META: --allocatable Bool, --addtag Tag, --deltag Tag,
pvchange OO_PVCHANGE_META --all
OO: OO_PVCHANGE
ID: pvchange_properties_all
DESC: Change properties of all PVs.
pvchange OO_PVCHANGE_META PV|Select ...
OO: --select String, OO_PVCHANGE
ID: pvchange_properties_some
DESC: Change properties of specified PVs.
---
@@ -1168,12 +947,10 @@ OO: --abort, --alloc Alloc, --atomic, --autobackup Bool, --background,
--interval Number, --name LV, --noudevsync, --reportformat String, --test
OP: PV ...
ID: pvmove_one
DESC: Move PV extents.
pvmove
OO: --abort, --background, --test
ID: pvmove_any
DESC: Continue or abort existing pvmove operations.
---
@@ -1194,14 +971,12 @@ pvscan
OO: --ignorelockingfailure, --reportformat String, --exported, --novolumegroup,
--short, --uuid
ID: pvscan_show
DESC: Display PV information.
pvscan --cache_long
OO: --ignorelockingfailure, --reportformat String, --background,
--activate Active, --major Number, --minor Number,
OP: PV|String ...
ID: pvscan_cache
DESC: Populate the lvmetad cache by scanning PVs.
---
@@ -1241,44 +1016,37 @@ vgchange OO_VGCHANGE_META
OO: OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_properties
DESC: Change a general VG property.
vgchange --monitor Bool
OO: --sysinit, --ignorelockingfailure, --poll Bool, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_monitor
DESC: Start or stop monitoring LVs from dmeventd.
vgchange --poll Bool
OO: --ignorelockingfailure, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_poll
DESC: Start or stop processing LV conversions.
vgchange --activate Active
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit,
--ignorelockingfailure, --monitor Bool, --poll Bool, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_activate
DESC: Activate or deactivate LVs.
vgchange --refresh
OO: --sysinit, --ignorelockingfailure, --monitor Bool, --poll Bool, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_refresh
DESC: Reactivate LVs using the latest metadata.
vgchange --lockstart
OO: --lockopt String, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_lockstart
DESC: Start the lockspace of a shared VG in lvmlockd.
vgchange --lockstop
OO: --lockopt String, OO_VGCHANGE_META, OO_VGCHANGE
OP: VG|Tag ...
ID: vgchange_lockstop
DESC: Stop the lockspace of a shared VG in lvmlockd.
---
@@ -1324,12 +1092,10 @@ OO_VGEXPORT: --reportformat String, --test
vgexport VG|Tag|Select ...
OO: --select String, OO_VGEXPORT
ID: vgexport_some
DESC: Export specified VGs.
vgexport --all
OO: OO_VGEXPORT
ID: vgexport_all
DESC: Export all VGs.
---
@@ -1348,12 +1114,10 @@ OO_VGIMPORT: --force, --reportformat String, --test
vgimport VG|Tag|Select ...
OO: --select String, OO_VGIMPORT
ID: vgimport_some
DESC: Import specified VGs.
vgimport --all
OO: OO_VGIMPORT
ID: vgimport_all
DESC: Import all VGs.
---
@@ -1381,17 +1145,14 @@ OO_VGREDUCE: --autobackup Bool, --force, --reportformat String, --test
vgreduce VG PV ...
OO: OO_VGREDUCE
ID: vgreduce_by_pv
DESC: Remove a PV from a VG.
vgreduce --all VG
OO: OO_VGREDUCE
ID: vgreduce_all
DESC: Remove all unused PVs from a VG.
vgreduce --removemissing VG
OO: --mirrorsonly, OO_VGREDUCE
ID: vgreduce_missing
DESC: Remove all missing PVs from a VG.
---
@@ -1404,12 +1165,10 @@ ID: vgremove_general
vgrename VG VG_new
OO: --autobackup Bool, --force, --reportformat String, --test
ID: vgrename_by_name
DESC: Rename a VG.
vgrename String VG_new
OO: --autobackup Bool, --force, --reportformat String, --test
ID: vgrename_by_uuid
DESC: Rename a VG by specifying the VG UUID.
---
@@ -1433,38 +1192,21 @@ 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, OO_VGSPLIT_NEW
ID: vgsplit_by_pv
DESC: Split a VG by specified PVs.
OO: OO_VGSPLIT
ID: vgsplit_by_pv_to_existing
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_lv
DESC: Split a VG by PVs in a specified LV.
ID: vgsplit_by_pv_to_new
vgsplit --name LV VG VG_new
OO: OO_VGSPLIT, OO_VGSPLIT_NEW
ID: vgsplit_by_lv_to_new
---

View File

@@ -108,8 +108,6 @@ static struct opt_name opt_names[ARG_COUNT + 1] = {
struct cmd_name {
const char *name;
const char *desc;
int variants;
int common_options[ARG_COUNT + 1];
};
/* create table of command names, e.g. vgcreate */
@@ -135,7 +133,7 @@ struct oo_line {
int cmd_count;
struct command cmd_array[MAX_CMDS];
struct command lvm_all; /* for printing common options for all lvm commands */
struct command common_options; /* for printing common usage */
#define MAX_OO_LINES 256
int oo_line_count;
@@ -501,19 +499,6 @@ static const char *cmd_name_desc(const char *name)
return NULL;
}
static struct cmd_name *find_command_name(const char *str)
{
int i;
for (i = 0; i < MAX_CMD_NAMES; i++) {
if (!cmd_names[i].name)
break;
if (!strcmp(cmd_names[i].name, str))
return &cmd_names[i];
}
return NULL;
}
static int is_opt_name(char *str)
{
if (!strncmp(str, "--", 2))
@@ -992,7 +977,7 @@ static void print_def(struct arg_def *def, int usage)
printf("%s", def->str);
else if (val_enum == constnum_VAL)
printf("%llu", (unsigned long long)def->num);
printf("ll%u", (unsigned long long)def->num);
else {
if (sep) printf("|");
@@ -1188,155 +1173,35 @@ void print_command_count(void)
printf("};\n");
}
static int is_lvm_all_opt(int opt)
static int is_common_opt(int opt)
{
int oo;
for (oo = 0; oo < lvm_all.oo_count; oo++) {
if (lvm_all.optional_opt_args[oo].opt == opt)
for (oo = 0; oo < common_options.oo_count; oo++) {
if (common_options.optional_opt_args[oo].opt == opt)
return 1;
}
return 0;
}
static void factor_common_options(void)
/*
* For certain commands (esp commands like lvcreate with many variants), common
* options should not be printed for every variation, but once for all. The
* list of commands this applies to is fixed for now but could be encoded in
* command-lines.in.
*
* The common options are defined in OO_USAGE_COMMON. Those options
* are skipped when creating the usage strings for each variation of
* these commands. Instead they are set in the usage_common string.
*/
void print_usage(struct command *cmd, int skip_required)
{
int cn, opt_enum, ci, oo, found;
struct command *cmd;
for (cn = 0; cn < MAX_CMD_NAMES; cn++) {
if (!cmd_names[cn].name)
break;
for (ci = 0; ci < cmd_count; ci++) {
cmd = &cmd_array[ci];
if (strcmp(cmd->name, cmd_names[cn].name))
continue;
cmd_names[cn].variants++;
}
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
for (ci = 0; ci < cmd_count; ci++) {
cmd = &cmd_array[ci];
if (strcmp(cmd->name, cmd_names[cn].name))
continue;
found = 0;
for (oo = 0; oo < cmd->oo_count; oo++) {
if (cmd->optional_opt_args[oo].opt == opt_enum) {
found = 1;
break;
}
}
if (!found)
goto next_opt;
}
/* all commands starting with this name use this option */
cmd_names[cn].common_options[opt_enum] = 1;
next_opt:
;
}
}
/*
for (cn = 0; cn < MAX_CMD_NAMES; cn++) {
if (!cmd_names[cn].name)
break;
printf("%s (%d)\n", cmd_names[cn].name, cmd_names[cn].variants);
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (cmd_names[cn].common_options[opt_enum])
printf(" %s\n", opt_names[opt_enum].long_opt);
}
}
*/
}
void print_usage_common(struct command *cmd)
{
struct cmd_name *cname;
int i, sep, ro, rp, oo, op, opt_enum;
if (!(cname = find_command_name(cmd->name)))
return;
sep = 0;
/*
* when there's more than one variant, options that
* are comon to all commands with a common name.
*/
if (cname->variants < 2)
goto all;
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (!cname->common_options[opt_enum])
continue;
if (!sep) {
printf("\n");
printf("\" [");
}
if (sep)
printf(",");
for (oo = 0; oo < cmd->oo_count; oo++) {
if (cmd->optional_opt_args[oo].opt != opt_enum)
continue;
printf(" %s", opt_names[opt_enum].long_opt);
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&cmd->optional_opt_args[oo].def, 1);
}
sep = 1;
break;
}
}
all:
/* options that are common to all lvm commands */
for (oo = 0; oo < lvm_all.oo_count; oo++) {
opt_enum = lvm_all.optional_opt_args[oo].opt;
if (!sep) {
printf("\n");
printf("\" [");
}
if (sep)
printf(",");
printf(" %s", opt_names[opt_enum].long_opt);
if (lvm_all.optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&lvm_all.optional_opt_args[oo].def, 1);
}
sep = 1;
}
printf(" ]\"");
printf(";\n");
}
void print_usage(struct command *cmd)
{
struct cmd_name *cname;
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
int i, sep, ro, rp, oo, op, opt_enum;
int i, sep, ro, rp, oo, op;
if (!(cname = find_command_name(cmd->name)))
return;
if (skip_required)
goto oo_count;
printf("\"%s", cmd->name);
@@ -1375,41 +1240,31 @@ void print_usage(struct command *cmd)
sep = 0;
if (cmd->oo_count) {
printf("\n");
printf("\" [");
for (oo = 0; oo < cmd->oo_count; oo++) {
opt_enum = cmd->optional_opt_args[oo].opt;
/*
* Skip common opts which are in the usage_common string.
* The common opts are those in lvm_all and in
* cname->common_options.
*/
if (is_lvm_all_opt(opt_enum))
/* skip common opts which are in the usage_common string */
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
continue;
if ((cname->variants > 1) && cname->common_options[opt_enum])
continue;
if (!sep) {
printf("\n");
printf("\" [");
}
if (sep)
printf(",");
printf(" %s", opt_names[opt_enum].long_opt);
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&cmd->optional_opt_args[oo].def, 1);
}
sep = 1;
}
if (sep)
printf(",");
printf(" COMMON_OPTIONS");
printf(" ]\"");
}
if (sep)
printf(" ]\"");
op_count:
if (!cmd->op_count)
goto done;
@@ -1538,12 +1393,12 @@ static void print_def_man(struct arg_def *def, int usage)
printf(" ...");
}
void print_cmd_man(struct command *cmd, int common)
void print_cmd_man(struct command *cmd, int skip_required)
{
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
int i, sep, ro, rp, oo, op;
if (common)
if (skip_required)
goto oo_count;
printf("\\fB%s\\fP", cmd->name);
@@ -1690,7 +1545,7 @@ void print_cmd_man(struct command *cmd, int common)
for (oo = 0; oo < cmd->oo_count; oo++) {
/* skip common opts which are in the usage_common string */
if ((cmd != &lvm_all) && is_lvm_all_opt(cmd->optional_opt_args[oo].opt))
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
continue;
if (!opt_names[cmd->optional_opt_args[oo].opt].short_opt)
@@ -1720,7 +1575,7 @@ void print_cmd_man(struct command *cmd, int common)
for (oo = 0; oo < cmd->oo_count; oo++) {
/* skip common opts which are in the usage_common string */
if ((cmd != &lvm_all) && is_lvm_all_opt(cmd->optional_opt_args[oo].opt))
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
continue;
if (opt_names[cmd->optional_opt_args[oo].opt].short_opt)
@@ -1826,7 +1681,7 @@ void print_command_man(void)
const char *desc;
int i, j, ro, rp, oo, op;
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
include_optional_opt_args(&common_options, "OO_USAGE_COMMON");
printf(".TH LVM_ALL 8\n");
@@ -1861,7 +1716,7 @@ void print_command_man(void)
if ((i == (cmd_count - 1)) || strcmp(cmd->name, cmd_array[i+1].name)) {
printf("Common options:\n");
printf(".\n");
print_cmd_man(&lvm_all, 1);
print_cmd_man(&common_options, 1);
}
printf("\n");
@@ -1874,7 +1729,7 @@ void print_command_struct(int only_usage)
struct command *cmd;
int i, j, ro, rp, oo, op;
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
include_optional_opt_args(&common_options, "OO_USAGE_COMMON");
printf("/* Do not edit. This file is generated by scripts/create-commands */\n");
printf("/* using command definitions from scripts/command-lines.in */\n");
@@ -1884,8 +1739,8 @@ void print_command_struct(int only_usage)
cmd = &cmd_array[i];
if (only_usage) {
print_usage(cmd);
print_usage_common(cmd);
print_usage(cmd, 0);
print_usage(&common_options, 1);
printf("\n");
continue;
}
@@ -1904,11 +1759,11 @@ void print_command_struct(int only_usage)
printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
printf("commands[%d].usage = ", i);
print_usage(cmd);
print_usage(cmd, 0);
if (cmd->oo_count) {
printf("commands[%d].usage_common = ", i);
print_usage_common(cmd);
print_usage(&common_options, 1);
} else {
printf("commands[%d].usage_common = \"NULL\";\n", i);
}
@@ -2056,8 +1911,12 @@ 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],
@@ -2077,8 +1936,8 @@ static void print_ambiguous(void)
}
printf("Ambiguous commands %d and %d:\n", i, j);
print_usage(cmd);
print_usage(dup);
print_usage(cmd, 0);
print_usage(dup, 0);
printf("\n");
dups[found].i = i;
@@ -2118,11 +1977,11 @@ static void print_help(int argc, char *argv[])
{
printf("%s --output struct|count|usage|expanded <filename>\n", argv[0]);
printf("\n");
printf("struct: print C structures for command-lines.h\n");
printf("count: print defines and enums for command-lines-count.h\n");
printf("ambiguous: print commands differing only by LV types\n");
printf("struct: print C structures.\n");
printf("usage: print usage format.\n");
printf("expanded: print expanded input format.\n");
printf("count: print #define COMMAND_COUNT <Number>\n");
printf("ambiguous: print commands differing only by LV types\n");
}
int main(int argc, char *argv[])
@@ -2288,14 +2147,10 @@ int main(int argc, char *argv[])
fclose(file);
factor_common_options();
if (!outputformat)
print_command_struct(1);
else if (!strcmp(outputformat, "struct")) {
else if (!strcmp(outputformat, "struct"))
print_command_struct(0);
print_ambiguous();
}
else if (!strcmp(outputformat, "count"))
print_command_count();
else if (!strcmp(outputformat, "usage"))

View File

@@ -81,8 +81,7 @@ 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
# ignores unused positional arg dev1
lvscan "$dev1"
invalid lvscan "$dev1"
lvdisplay --maps
lvscan --all
@@ -109,16 +108,13 @@ vgmknodes --refresh
lvscan
lvmdiskscan
# ignores unused arg
pvscan "$dev1"
invalid pvscan "$dev1"
invalid pvscan -aay
invalid pvscan --major 254
invalid pvscan --minor 0
invalid pvscan --novolumegroup -e
# ignores unsed arg
vgscan $vg
# ignroes unused arg
lvscan $vg
invalid vgscan $vg
invalid 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 151
#define COMMAND_COUNT 147
enum {
no_CMD,
lvchange_properties_CMD,
@@ -19,8 +19,11 @@ 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_to_mirrored_or_change_image_count_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,
@@ -38,7 +41,6 @@ enum {
lvcreate_linear_CMD,
lvcreate_striped_CMD,
lvcreate_mirror_CMD,
lvcreate_mirror_or_raid1_CMD,
lvcreate_raid_any_CMD,
lvcreate_cow_snapshot_CMD,
lvcreate_cow_snapshot_with_virtual_origin_CMD,
@@ -47,10 +49,10 @@ enum {
lvcreate_thin_vol_CMD,
lvcreate_thin_snapshot_CMD,
lvcreate_thin_snapshot_of_external_CMD,
lvcreate_thin_vol_and_thinpool_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,
@@ -108,8 +110,10 @@ enum {
vgrename_by_uuid_CMD,
vgs_general_CMD,
vgscan_general_CMD,
vgsplit_by_pv_CMD,
vgsplit_by_lv_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,

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,81 +750,6 @@ 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[]
@@ -836,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;
/*
@@ -850,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;
@@ -860,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;
}
@@ -958,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;
/*
@@ -991,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;
/*
@@ -1022,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. */
@@ -1043,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;
}
@@ -1287,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);
@@ -1315,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++;
}
}
@@ -1351,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;
}
}
@@ -1365,128 +1249,124 @@ 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;
}
/*
@@ -1497,9 +1377,6 @@ 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;
@@ -1578,8 +1455,6 @@ 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.");

View File

@@ -2555,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;
}

View File

@@ -116,7 +116,8 @@ 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(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Number")
@@ -125,8 +126,8 @@ val(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Num
val(VAL_COUNT, NULL, NULL, NULL)
/*
* 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:
* 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,