1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-16 23:33:16 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
7f02163489 commands: new method for defining commands
. Define a prototype for every lvm command.
. Match every user command with one definition.
. 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, --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
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
FLAGS: SECONDARY_SYNTAX

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

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

The prototype syntax used for help/man output includes
required --option and positional args on the first line,
and optional --option and positional args enclosed in [ ]
on subsequent lines.

  command_name <required_opt_args> <required_pos_args>
          [ <optional_opt_args> ]
          [ <optional_pos_args> ]

$ lvresize --help
  lvresize - Resize a logical volume

  Resize an LV by a specified size.
  lvresize --size Number[m|unit] LV
        [ --resizefs,
          --poolmetadatasize Number[m|unit],
          COMMON_OPTIONS ]
        [ PV ... ]

  Resize a pool metadata SubLV by a specified size.
  lvresize --poolmetadatasize Number[m|unit] LV_thinpool
        [ COMMON_OPTIONS ]
        [ PV ... ]

  Common options:
        [ --alloc contiguous|cling|cling_by_tags|normal|anywhere|inherit,
          --nosync,
          --reportformat String,
          --autobackup y|n,
          --stripes Number,
          --stripesize Number[k|unit],
          --nofsck,
          --commandprofile String,
          --config String,
          --debug,
          --driverloaded y|n,
          --help,
          --profile String,
          --quiet,
          --verbose,
          --version,
          --yes,
          --test,
          --force,
          --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

Command definitions that are not to be advertised/suggested
have the flag SECONDARY_SYNTAX.  These commands will not be
printed in the normal help output.

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 per-command-name
implementation functions.

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-27 15:57:27 -05:00
17 changed files with 963 additions and 9274 deletions

View File

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

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

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

View File

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

View File

@@ -31,8 +31,8 @@ arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
arg(config_ARG, '\0', "config", string_VAL, 0, 0)
arg(configreport_ARG, '\0', "configreport", string_VAL, ARG_GROUPABLE, 1)
arg(configtype_ARG, '\0', "typeconfig", string_VAL, 0, 0)
arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1)
arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0)
arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
@@ -81,26 +81,26 @@ arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
arg(polloperation_ARG, '\0', "polloperation", string_VAL, 0, 0)
arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0)
arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", number_VAL, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", string_VAL, ARG_GROUPABLE, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0)
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_VAL, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0)
arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_VAL, ARG_GROUPABLE, 0)
arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0)
arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
arg(repair_ARG, '\0', "repair", 0, 0, 0)
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
arg(reportformat_ARG, '\0', "reportformat", string_VAL, 0, 0)
arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0)
arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
arg(resync_ARG, '\0', "resync", 0, 0, 0)
@@ -116,7 +116,7 @@ arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
arg(syncaction_ARG, '\0', "syncaction", string_VAL, 0, 0) /* FIXME Use custom VAL */
arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0)
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
@@ -133,14 +133,14 @@ arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
arg(validate_ARG, '\0', "validate", 0, 0, 0)
arg(version_ARG, '\0', "version", 0, 0, 0)
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_VAL, 0, 0)
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
arg(writemostly_ARG, '\0', "writemostly", string_VAL, ARG_GROUPABLE, 0)
arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0)
/* Allow some variations */
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)

View File

@@ -1,129 +0,0 @@
/* Do not edit. This file is generated by scripts/create-commands */
/* using command definitions from scripts/command-lines.in */
#define COMMAND_COUNT 151
enum {
no_CMD,
lvchange_properties_CMD,
lvchange_resync_CMD,
lvchange_syncaction_CMD,
lvchange_rebuild_CMD,
lvchange_activate_CMD,
lvchange_refresh_CMD,
lvchange_monitor_CMD,
lvchange_poll_CMD,
lvchange_persistent_CMD,
lvconvert_merge_CMD,
lvconvert_combine_split_snapshot_CMD,
lvconvert_to_thin_with_external_CMD,
lvconvert_to_cache_vol_CMD,
lvconvert_to_thinpool_CMD,
lvconvert_to_cachepool_CMD,
lvconvert_to_mirror_CMD,
lvconvert_general_to_raid_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,
lvconvert_split_mirror_images_and_track_CMD,
lvconvert_repair_pvs_or_thinpool_CMD,
lvconvert_replace_pv_CMD,
lvconvert_change_mirrorlog_CMD,
lvconvert_split_and_keep_cachepool_CMD,
lvconvert_split_and_delete_cachepool_CMD,
lvconvert_split_cow_snapshot_CMD,
lvconvert_poll_mirror_CMD,
lvconvert_swap_pool_metadata_CMD,
lvcreate_error_vol_CMD,
lvcreate_zero_vol_CMD,
lvcreate_linear_CMD,
lvcreate_striped_CMD,
lvcreate_mirror_CMD,
lvcreate_mirror_or_raid1_CMD,
lvcreate_raid_any_CMD,
lvcreate_cow_snapshot_CMD,
lvcreate_cow_snapshot_with_virtual_origin_CMD,
lvcreate_thinpool_CMD,
lvcreate_cachepool_CMD,
lvcreate_thin_vol_CMD,
lvcreate_thin_snapshot_CMD,
lvcreate_thin_snapshot_of_external_CMD,
lvcreate_thin_vol_and_thinpool_CMD,
lvcreate_thin_vol_with_thinpool_or_sparse_snapshot_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,
lvextend_pool_metadata_by_size_CMD,
lvextend_by_policy_CMD,
lvmconfig_general_CMD,
lvreduce_general_CMD,
lvremove_general_CMD,
lvrename_vg_lv_lv_CMD,
lvrename_lv_lv_CMD,
lvresize_by_size_CMD,
lvresize_by_pv_CMD,
lvresize_pool_metadata_by_size_CMD,
lvs_general_CMD,
lvscan_general_CMD,
pvchange_properties_all_CMD,
pvchange_properties_some_CMD,
pvresize_general_CMD,
pvck_general_CMD,
pvcreate_general_CMD,
pvdisplay_general_CMD,
pvmove_one_CMD,
pvmove_any_CMD,
pvremove_general_CMD,
pvs_general_CMD,
pvscan_show_CMD,
pvscan_cache_CMD,
vgcfgbackup_general_CMD,
vgcfgrestore_by_vg_CMD,
vgcfgrestore_by_file_CMD,
vgchange_properties_CMD,
vgchange_monitor_CMD,
vgchange_poll_CMD,
vgchange_activate_CMD,
vgchange_refresh_CMD,
vgchange_lockstart_CMD,
vgchange_lockstop_CMD,
vgck_general_CMD,
vgconvert_general_CMD,
vgcreate_general_CMD,
vgdisplay_general_CMD,
vgexport_some_CMD,
vgexport_all_CMD,
vgextend_general_CMD,
vgimport_some_CMD,
vgimport_all_CMD,
vgimportclone_general_CMD,
vgmerge_general_CMD,
vgmknodes_general_CMD,
vgreduce_by_pv_CMD,
vgreduce_all_CMD,
vgreduce_missing_CMD,
vgremove_general_CMD,
vgrename_by_name_CMD,
vgrename_by_uuid_CMD,
vgs_general_CMD,
vgscan_general_CMD,
vgsplit_by_pv_CMD,
vgsplit_by_lv_CMD,
devtypes_general_CMD,
fullreport_general_CMD,
lastlog_general_CMD,
lvpoll_general_CMD,
formats_general_CMD,
help_general_CMD,
version_general_CMD,
pvdata_general_CMD,
segtypes_general_CMD,
systemid_general_CMD,
tags_general_CMD,
lvmchange_general_CMD,
lvmdiskscan_general_CMD,
lvmsadc_general_CMD,
lvmsar_general_CMD,
COMMAND_ID_COUNT,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -47,7 +47,15 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int alloc_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int locktype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int readahead_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
/* also see arg_props */
struct opt_name {
@@ -108,6 +116,8 @@ 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 */
@@ -133,12 +143,15 @@ struct oo_line {
int cmd_count;
struct command cmd_array[MAX_CMDS];
struct command common_options; /* for printing common usage */
struct command lvm_all; /* for printing common options for all lvm commands */
#define MAX_OO_LINES 256
int oo_line_count;
struct oo_line oo_lines[MAX_OO_LINES];
static int include_man_secondary = 1;
static int include_man_primary = 1;
static char *man_command_name = NULL;
static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]);
@@ -243,7 +256,7 @@ static int opt_str_to_num(char *str)
exit(1);
}
static char *val_bits_to_str(int val_bits)
static char *val_bits_to_str(uint64_t val_bits)
{
static char buf[128];
int i;
@@ -499,6 +512,19 @@ 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))
@@ -562,6 +588,13 @@ static int is_desc_line(char *str)
return 0;
}
static int is_flags_line(char *str)
{
if (!strncmp(str, "FLAGS:", 6))
return 1;
return 0;
}
static int is_id_line(char *str)
{
if (!strncmp(str, "ID:", 3))
@@ -1132,14 +1165,46 @@ static char *flags_to_str(int flags)
memset(buf_flags, 0, sizeof(buf_flags));
if (flags & ARG_DEF_FLAG_MAY_REPEAT)
if (flags & ARG_DEF_FLAG_MAY_REPEAT) {
if (buf_flags[0])
strcat(buf_flags, " | ");
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
if (flags & ARG_DEF_FLAG_NEW)
}
if (flags & ARG_DEF_FLAG_NEW) {
if (buf_flags[0])
strcat(buf_flags, " | ");
strcat(buf_flags, "ARG_DEF_FLAG_NEW");
}
return buf_flags;
}
static void add_flags(struct command *cmd, char *line)
{
if (strstr(line, "SECONDARY_SYNTAX"))
cmd->cmd_flags |= CMD_FLAG_SECONDARY_SYNTAX;
}
static char *cmd_flags_to_str(uint32_t flags)
{
static char buf_cmd_flags[32];
memset(buf_cmd_flags, 0, sizeof(buf_cmd_flags));
if (flags & CMD_FLAG_SECONDARY_SYNTAX) {
if (buf_cmd_flags[0])
strcat(buf_cmd_flags, " | ");
strcat(buf_cmd_flags, "CMD_FLAG_SECONDARY_SYNTAX");
}
if (flags & CMD_FLAG_ONE_REQUIRED_OPT) {
if (buf_cmd_flags[0])
strcat(buf_cmd_flags, " | ");
strcat(buf_cmd_flags, "CMD_FLAG_ONE_REQUIRED_OPT");
}
return buf_cmd_flags;
}
void print_command_count(void)
{
struct command *cmd;
@@ -1173,35 +1238,156 @@ void print_command_count(void)
printf("};\n");
}
static int is_common_opt(int opt)
static int is_lvm_all_opt(int opt)
{
int oo;
for (oo = 0; oo < common_options.oo_count; oo++) {
if (common_options.optional_opt_args[oo].opt == opt)
for (oo = 0; oo < lvm_all.oo_count; oo++) {
if (lvm_all.optional_opt_args[oo].opt == opt)
return 1;
}
return 0;
}
/*
* 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)
static void factor_common_options(void)
{
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
int i, sep, ro, rp, oo, op;
int cn, opt_enum, ci, oo, found;
struct command *cmd;
if (skip_required)
goto oo_count;
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 common 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 (is_lvm_all_opt(opt_enum))
continue;
if (!sep) {
printf("\n");
printf("\" [");
} else {
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("\" [");
} else {
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;
if (!(cname = find_command_name(cmd->name)))
return;
printf("\"%s", cmd->name);
@@ -1240,30 +1426,40 @@ void print_usage(struct command *cmd, int skip_required)
sep = 0;
if (cmd->oo_count) {
printf("\n");
printf("\" [");
for (oo = 0; oo < cmd->oo_count; oo++) {
/* skip common opts which are in the usage_common string */
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
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))
continue;
if (!sep) {
printf("\n");
printf("\" [");
}
if ((cname->variants > 1) && cname->common_options[opt_enum])
continue;
if (sep)
printf(",");
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
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;
}
}
if (sep)
if (sep)
printf(",");
printf(" COMMON_OPTIONS");
printf(" ]\"");
}
op_count:
if (!cmd->op_count)
@@ -1352,7 +1548,7 @@ static void print_def_man(struct arg_def *def, int usage)
else if (val_enum == constnum_VAL) {
printf("\\fB");
printf("ll%u", (unsigned long long)def->num);
printf("%llu", (unsigned long long)def->num);
printf("\\fP");
}
@@ -1393,13 +1589,56 @@ static void print_def_man(struct arg_def *def, int usage)
printf(" ...");
}
void print_cmd_man(struct command *cmd, int skip_required)
static char *man_long_opt_name(struct command *cmd, int opt_enum)
{
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
int i, sep, ro, rp, oo, op;
static char long_opt_name[64];
if (skip_required)
goto oo_count;
memset(&long_opt_name, 0, sizeof(long_opt_name));
switch (opt_enum) {
case syncaction_ARG:
strncpy(long_opt_name, "--[raid]syncaction", 63);
break;
case writemostly_ARG:
strncpy(long_opt_name, "--[raid]writemostly", 63);
break;
case minrecoveryrate_ARG:
strncpy(long_opt_name, "--[raid]minrecoveryrate", 63);
break;
case maxrecoveryrate_ARG:
strncpy(long_opt_name, "--[raid]maxrecoveryrate", 63);
break;
case writebehind_ARG:
strncpy(long_opt_name, "--[raid]writebehind", 63);
break;
case vgmetadatacopies_ARG:
if (!strncmp(cmd->name, "vg", 2))
strncpy(long_opt_name, "--[vg]metadatacopies", 63);
else
strncpy(long_opt_name, "--vgmetadatacopies", 63);
break;
case pvmetadatacopies_ARG:
if (!strncmp(cmd->name, "pv", 2))
strncpy(long_opt_name, "--[pv]metadatacopies", 63);
else
strncpy(long_opt_name, "--pvmetadatacopies", 63);
break;
default:
strncpy(long_opt_name, opt_names[opt_enum].long_opt, 63);
break;
}
return long_opt_name;
}
void print_man_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;
if (!(cname = find_command_name(cmd->name)))
return;
printf("\\fB%s\\fP", cmd->name);
@@ -1424,8 +1663,11 @@ void print_cmd_man(struct command *cmd, int skip_required)
sep = 0;
/* print required options with a short opt */
for (ro = 0; ro < cmd->ro_count; ro++) {
if (!opt_names[cmd->required_opt_args[ro].opt].short_opt)
opt_enum = cmd->required_opt_args[ro].opt;
if (!opt_names[opt_enum].short_opt)
continue;
if (sep) {
@@ -1434,13 +1676,13 @@ void print_cmd_man(struct command *cmd, int skip_required)
printf(" ");
}
if (opt_names[cmd->required_opt_args[ro].opt].short_opt) {
if (opt_names[opt_enum].short_opt) {
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[cmd->required_opt_args[ro].opt].short_opt,
opt_names[cmd->required_opt_args[ro].opt].long_opt);
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd, opt_enum));
} else {
printf(" ");
printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt);
printf(" \\fB%s\\fP", man_long_opt_name(cmd, opt_enum));
}
if (cmd->required_opt_args[ro].def.val_bits) {
@@ -1451,8 +1693,11 @@ void print_cmd_man(struct command *cmd, int skip_required)
sep = 1;
}
/* print required options without a short opt */
for (ro = 0; ro < cmd->ro_count; ro++) {
if (opt_names[cmd->required_opt_args[ro].opt].short_opt)
opt_enum = cmd->required_opt_args[ro].opt;
if (opt_names[opt_enum].short_opt)
continue;
if (sep) {
@@ -1462,7 +1707,7 @@ void print_cmd_man(struct command *cmd, int skip_required)
}
printf(" ");
printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt);
printf(" \\fB%s\\fP", man_long_opt_name(cmd, opt_enum));
if (cmd->required_opt_args[ro].def.val_bits) {
printf(" ");
@@ -1476,6 +1721,7 @@ void print_cmd_man(struct command *cmd, int skip_required)
printf(".RE\n");
}
/* print required positional args on a new line after the onereq set */
if (cmd->rp_count) {
printf(".RS 4\n");
for (rp = 0; rp < cmd->rp_count; rp++) {
@@ -1498,15 +1744,17 @@ void print_cmd_man(struct command *cmd, int skip_required)
/*
* all are required options, print as:
* -a|--a, -b|--b
* -a|--aaa <val> -b|--bbb <val>
*/
if (cmd->ro_count) {
for (ro = 0; ro < cmd->ro_count; ro++) {
if (opt_names[cmd->required_opt_args[ro].opt].short_opt) {
opt_enum = cmd->required_opt_args[ro].opt;
if (opt_names[opt_enum].short_opt) {
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[cmd->required_opt_args[ro].opt].short_opt,
opt_names[cmd->required_opt_args[ro].opt].long_opt);
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd, opt_enum));
} else {
printf(" \\fB%s\\fP", opt_names[cmd->required_opt_args[ro].opt].long_opt);
}
@@ -1518,6 +1766,7 @@ void print_cmd_man(struct command *cmd, int skip_required)
}
}
/* print required positional args on the same line as the required options */
if (cmd->rp_count) {
for (rp = 0; rp < cmd->rp_count; rp++) {
if (cmd->required_pos_args[rp].def.val_bits) {
@@ -1539,22 +1788,29 @@ void print_cmd_man(struct command *cmd, int skip_required)
sep = 0;
printf(".br\n");
if (cmd->oo_count) {
printf(".RS 4\n");
printf("[");
/* print optional options with short opts */
for (oo = 0; oo < cmd->oo_count; oo++) {
/* skip common opts which are in the usage_common string */
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
opt_enum = cmd->optional_opt_args[oo].opt;
if (!opt_names[opt_enum].short_opt)
continue;
if (!opt_names[cmd->optional_opt_args[oo].opt].short_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))
continue;
if (!sep) {
printf(".RS 4\n");
printf("[");
}
if ((cname->variants > 1) && cname->common_options[opt_enum])
continue;
if (sep) {
printf(",");
@@ -1563,8 +1819,8 @@ void print_cmd_man(struct command *cmd, int skip_required)
}
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[cmd->optional_opt_args[oo].opt].short_opt,
opt_names[cmd->optional_opt_args[oo].opt].long_opt);
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd, opt_enum));
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
@@ -1573,18 +1829,25 @@ void print_cmd_man(struct command *cmd, int skip_required)
sep = 1;
}
/* print optional options without short opts */
for (oo = 0; oo < cmd->oo_count; oo++) {
/* skip common opts which are in the usage_common string */
if ((cmd != &common_options) && is_common_opt(cmd->optional_opt_args[oo].opt))
opt_enum = cmd->optional_opt_args[oo].opt;
if (opt_names[opt_enum].short_opt)
continue;
if (opt_names[cmd->optional_opt_args[oo].opt].short_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))
continue;
if (!sep) {
printf(".RS 4\n");
printf("[");
}
if ((cname->variants > 1) && cname->common_options[opt_enum])
continue;
if (sep) {
printf(",");
@@ -1595,7 +1858,7 @@ void print_cmd_man(struct command *cmd, int skip_required)
/* space alignment without short opt */
printf(" ");
printf(" \\fB%s\\fP", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
printf(" \\fB%s\\fP", man_long_opt_name(cmd, opt_enum));
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
@@ -1603,9 +1866,15 @@ void print_cmd_man(struct command *cmd, int skip_required)
}
sep = 1;
}
}
if (sep) {
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
/* space alignment without short opt */
printf(" ");
}
printf(" COMMON_OPTIONS");
printf(" ]\n");
printf(".RE\n");
printf(".br\n");
@@ -1634,6 +1903,150 @@ void print_cmd_man(struct command *cmd, int skip_required)
printf("\n");
}
void print_man_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;
printf(".RS 4\n");
printf("[");
/*
* when there's more than one variant, options that
* are common to all commands with a common name.
*/
if (cname->variants < 2)
goto all;
/* print those with short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (!cname->common_options[opt_enum])
continue;
if (!opt_names[opt_enum].short_opt)
continue;
if (is_lvm_all_opt(opt_enum))
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
for (oo = 0; oo < cmd->oo_count; oo++) {
if (cmd->optional_opt_args[oo].opt != opt_enum)
continue;
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd, opt_enum));
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def_man(&cmd->optional_opt_args[oo].def, 1);
}
sep = 1;
break;
}
}
/* print those without short opts */
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
if (!cname->common_options[opt_enum])
continue;
if (opt_names[opt_enum].short_opt)
continue;
if (is_lvm_all_opt(opt_enum))
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
for (oo = 0; oo < cmd->oo_count; oo++) {
if (cmd->optional_opt_args[oo].opt != opt_enum)
continue;
/* space alignment without short opt */
printf(" ");
printf(" \\fB%s\\fP", man_long_opt_name(cmd, opt_enum));
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def_man(&cmd->optional_opt_args[oo].def, 1);
}
sep = 1;
break;
}
}
all:
/* options that are common to all lvm commands */
/* those with short opts */
for (oo = 0; oo < lvm_all.oo_count; oo++) {
opt_enum = lvm_all.optional_opt_args[oo].opt;
if (!opt_names[opt_enum].short_opt)
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
printf(" \\fB-%c\\fP|\\fB%s\\fP",
opt_names[opt_enum].short_opt,
man_long_opt_name(cmd, opt_enum));
if (lvm_all.optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&lvm_all.optional_opt_args[oo].def, 1);
}
sep = 1;
}
/* those without short opts */
for (oo = 0; oo < lvm_all.oo_count; oo++) {
opt_enum = lvm_all.optional_opt_args[oo].opt;
if (opt_names[opt_enum].short_opt)
continue;
if (sep) {
printf(",");
printf("\n.br\n");
printf(" ");
}
/* space alignment without short opt */
printf(" ");
printf(" \\fB%s\\fP", man_long_opt_name(cmd, opt_enum));
if (lvm_all.optional_opt_args[oo].def.val_bits) {
printf(" ");
print_def(&lvm_all.optional_opt_args[oo].def, 1);
}
sep = 1;
}
printf(" ]\n");
}
#define DESC_LINE 256
void print_desc_man(const char *desc)
@@ -1674,26 +2087,55 @@ void print_desc_man(const char *desc)
}
}
void print_command_man(void)
static char *upper_command_name(char *str)
{
struct command *cmd;
const char *last_cmd_name = NULL;
static char str_upper[32];
int i = 0;
while (*str) {
str_upper[i++] = toupper(*str);
str++;
}
str_upper[i] = '\0';
return str_upper;
}
void print_man_command(void)
{
struct command *cmd, *prev_cmd = NULL;
const char *desc;
int i, j, ro, rp, oo, op;
include_optional_opt_args(&common_options, "OO_USAGE_COMMON");
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
printf(".TH LVM_ALL 8\n");
printf(".TH %s 8 \"LVM TOOLS #VERSION#\" \"Sistina Software UK\"\n",
man_command_name ? upper_command_name(man_command_name) : "LVM_COMMANDS");
for (i = 0; i < cmd_count; i++) {
cmd = &cmd_array[i];
if (!last_cmd_name || strcmp(last_cmd_name, cmd->name)) {
if (prev_cmd && strcmp(prev_cmd->name, cmd->name)) {
printf("Common options:\n");
printf(".\n");
print_man_usage_common(prev_cmd);
prev_cmd = NULL;
}
if ((cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_secondary)
continue;
if (!(cmd->cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && !include_man_primary)
continue;
if (man_command_name && strcmp(man_command_name, cmd->name))
continue;
if (!prev_cmd || strcmp(prev_cmd->name, cmd->name)) {
printf(".SH NAME\n");
printf(".\n");
if ((desc = cmd_name_desc(cmd->name)))
printf("%s - %s\n", cmd->name, desc);
printf("%s \\- %s\n", cmd->name, desc);
else
printf("%s\n", cmd->name);
printf(".br\n");
@@ -1703,7 +2145,7 @@ void print_command_man(void)
printf(".br\n");
printf(".P\n");
printf(".\n");
last_cmd_name = cmd->name;
prev_cmd = cmd;
}
if (cmd->desc) {
@@ -1711,12 +2153,12 @@ void print_command_man(void)
printf(".P\n");
}
print_cmd_man(cmd, 0);
print_man_usage(cmd);
if ((i == (cmd_count - 1)) || strcmp(cmd->name, cmd_array[i+1].name)) {
if (i == (cmd_count - 1)) {
printf("Common options:\n");
printf(".\n");
print_cmd_man(&common_options, 1);
print_man_usage_common(cmd);
}
printf("\n");
@@ -1729,7 +2171,7 @@ void print_command_struct(int only_usage)
struct command *cmd;
int i, j, ro, rp, oo, op;
include_optional_opt_args(&common_options, "OO_USAGE_COMMON");
include_optional_opt_args(&lvm_all, "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");
@@ -1739,8 +2181,8 @@ void print_command_struct(int only_usage)
cmd = &cmd_array[i];
if (only_usage) {
print_usage(cmd, 0);
print_usage(&common_options, 1);
print_usage(cmd);
print_usage_common(cmd);
printf("\n");
continue;
}
@@ -1754,16 +2196,18 @@ void print_command_struct(int only_usage)
printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
if (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT)
printf("commands[%d].cmd_flags = CMD_FLAG_ONE_REQUIRED_OPT;\n", i);
if (cmd->cmd_flags)
printf("commands[%d].cmd_flags = %s;\n", i, cmd_flags_to_str(cmd->cmd_flags));
else
printf("commands[%d].cmd_flags = 0;\n", i, cmd_flags_to_str(cmd->cmd_flags));
printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
printf("commands[%d].usage = ", i);
print_usage(cmd, 0);
print_usage(cmd);
if (cmd->oo_count) {
printf("commands[%d].usage_common = ", i);
print_usage(&common_options, 1);
print_usage_common(cmd);
} else {
printf("commands[%d].usage_common = \"NULL\";\n", i);
}
@@ -1932,8 +2376,8 @@ static void print_ambiguous(void)
}
printf("Ambiguous commands %d and %d:\n", i, j);
print_usage(cmd, 0);
print_usage(dup, 0);
print_usage(cmd);
print_usage(dup);
printf("\n");
dups[found].i = i;
@@ -1973,11 +2417,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.\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("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[])
@@ -2010,6 +2454,9 @@ int main(int argc, char *argv[])
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"output", required_argument, 0, 'o' },
{"man-primary", required_argument, 0, 'p' },
{"man-secondary", required_argument, 0, 's' },
{"man-command", required_argument, 0, 'c' },
{0, 0, 0, 0 }
};
@@ -2017,7 +2464,7 @@ int main(int argc, char *argv[])
int c;
int option_index = 0;
c = getopt_long(argc, argv, "ho:",
c = getopt_long(argc, argv, "ho:p:s:c:",
long_options, &option_index);
if (c == -1)
break;
@@ -2031,6 +2478,15 @@ int main(int argc, char *argv[])
case 'o':
outputformat = strdup(optarg);
break;
case 'p':
include_man_primary = atoi(optarg);
break;
case 's':
include_man_secondary = atoi(optarg);
break;
case 'c':
man_command_name = strdup(optarg);
break;
}
}
@@ -2082,15 +2538,22 @@ int main(int argc, char *argv[])
if (is_desc_line(line_argv[0])) {
char *desc = strdup(line_orig);
if (cmd->desc) {
cmd->desc = realloc((char *)cmd->desc, strlen(cmd->desc) + strlen(desc) + 2);
strcat((char *)cmd->desc, " ");
strcat((char *)cmd->desc, desc);
int newlen = strlen(cmd->desc) + strlen(desc) + 2;
char *newdesc = malloc(newlen);
memset(newdesc, 0, newlen);
snprintf(newdesc, newlen, "%s %s", cmd->desc, desc);
cmd->desc = newdesc;
free(desc);
} else
cmd->desc = desc;
continue;
}
if (is_flags_line(line_argv[0])) {
add_flags(cmd, line_orig);
continue;
}
if (is_id_line(line_argv[0])) {
cmd->command_line_id = strdup(line_argv[1]);
continue;
@@ -2143,10 +2606,14 @@ 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"))
@@ -2156,8 +2623,10 @@ int main(int argc, char *argv[])
else if (!strcmp(outputformat, "ambiguous"))
print_ambiguous();
else if (!strcmp(outputformat, "man"))
print_command_man();
print_man_command();
else
print_help(argc, argv);
return 0;
}

View File

@@ -733,23 +733,105 @@ int readahead_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_va
/*
* Non-zero, positive integer, "all", or "unmanaged"
*/
int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
int vgmetadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strncmp(cmd->name, "vg", 2)) {
if (!strcasecmp(av->value, "all")) {
av->ui_value = VGMETADATACOPIES_ALL;
return 1;
}
if (!strcasecmp(av->value, "all")) {
av->ui_value = VGMETADATACOPIES_ALL;
return 1;
}
if (!strcasecmp(av->value, "unmanaged")) {
av->ui_value = VGMETADATACOPIES_UNMANAGED;
return 1;
}
if (!strcasecmp(av->value, "unmanaged")) {
av->ui_value = VGMETADATACOPIES_UNMANAGED;
return 1;
}
return int_arg(cmd, av);
}
int pvmetadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
int num;
if (!int_arg(cmd, av))
return 0;
num = av->i_value;
if ((num != 0) && (num != 1) && (num != 2))
return 0;
return 1;
}
int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strncmp(cmd->name, "pv", 2))
return pvmetadatacopies_arg(cmd, av);
if (!strncmp(cmd->name, "vg", 2))
return vgmetadatacopies_arg(cmd, av);
return 0;
}
int polloperation_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "pvmove") ||
!strcmp(av->value, "convert") ||
!strcmp(av->value, "merge") ||
!strcmp(av->value, "merge_thin"))
return 1;
return 0;
}
int writemostly_arg(struct cmd_context *cmd, struct arg_values *av)
{
/* Could we verify that a PV arg looks like /dev/foo ? */
return 1;
}
int syncaction_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "check") ||
!strcmp(av->value, "repair"))
return 1;
return 0;
}
int reportformat_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "basic") ||
!strcmp(av->value, "json"))
return 1;
return 0;
}
int configreport_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "log") ||
!strcmp(av->value, "vg") ||
!strcmp(av->value, "lv") ||
!strcmp(av->value, "pv") ||
!strcmp(av->value, "pvseg") ||
!strcmp(av->value, "seg"))
return 1;
return 0;
}
int configtype_arg(struct cmd_context *cmd, struct arg_values *av)
{
if (!strcmp(av->value, "current") ||
!strcmp(av->value, "default") ||
!strcmp(av->value, "diff") ||
!strcmp(av->value, "full") ||
!strcmp(av->value, "list") ||
!strcmp(av->value, "missing") ||
!strcmp(av->value, "new") ||
!strcmp(av->value, "profilable") ||
!strcmp(av->value, "profilable-command") ||
!strcmp(av->value, "profilable-metadata"))
return 1;
return 0;
}
/*
* FIXME: there's been a confusing mixup among:
* resizeable, resizable, allocatable, allocation.
@@ -790,6 +872,14 @@ static int _opt_standard_to_synonym(const char *cmd_name, int opt)
return raidwritebehind_ARG;
case virtualsize_ARG:
return virtualoriginsize_ARG;
case pvmetadatacopies_ARG:
if (!strncmp(cmd_name, "pv", 2))
return metadatacopies_ARG;
return 0;
case vgmetadatacopies_ARG:
if (!strncmp(cmd_name, "vg", 2))
return metadatacopies_ARG;
return 0;
}
return 0;
}
@@ -819,6 +909,12 @@ static int _opt_synonym_to_standard(const char *cmd_name, int opt)
return writebehind_ARG;
case virtualoriginsize_ARG:
return virtualsize_ARG;
case metadatacopies_ARG:
if (!strncmp(cmd_name, "pv", 2))
return pvmetadatacopies_ARG;
if (!strncmp(cmd_name, "vg", 2))
return vgmetadatacopies_ARG;
return 0;
}
return 0;
}
@@ -1237,17 +1333,14 @@ static void _print_description(int ci)
int bi = 0;
for (di = 0; di < strlen(desc); di++) {
if (desc[di] == '\0')
break;
if (desc[di] == '\n')
continue;
if (!strncmp(&desc[di], "DESC:", 5)) {
if (bi) {
buf[bi] = '\0';
log_print("%s", buf);
memset(buf, 0, sizeof(buf));
bi = 0;
}
/* skip DESC: */
di += 5;
continue;
}
@@ -1261,8 +1354,10 @@ static void _print_description(int ci)
break;
}
if (bi)
if (bi) {
buf[bi] = '\0';
log_print("%s", buf);
}
}
/*
@@ -1490,16 +1585,14 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
}
/*
* Warn about positional args that are set but are not used by the command.
* If the user provided a positional arg that is not accepted by
* the mached command, then fail.
*
* If the last required_pos_arg or the last optional_pos_arg may repeat,
* then there won't be unused positional args.
*
* Otherwise, warn about positional args that exist beyond the number of
* required + optional pos_args.
*
* FIXME: should an unused positional arg cause the command to fail
* like an unused option?
* FIXME: same question as above, should there be a config setting
* to just warn/ignore about unused positional args?
*/
count = commands[best_i].rp_count;
@@ -1515,10 +1608,15 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
break;
if (count >= (commands[best_i].rp_count + commands[best_i].op_count)) {
log_warn("Ignoring positional argument which is not used by this command: %s.", argv[count]);
/* clear so it can't be used when processing. */
log_error("Invalid positional argument for command (%s %d): %s.",
commands[best_i].command_line_id, best_i, argv[count]);
/* FIXME: to warn/ignore, clear so it can't be used when processing. */
/*
argv[count] = NULL;
(*argc)--;
*/
return NULL;
}
}
out:
@@ -1549,6 +1647,9 @@ static int _usage(const char *name, int help_count)
if (strcmp(_cmdline.commands[i].name, name))
continue;
if ((_cmdline.commands[i].cmd_flags & CMD_FLAG_SECONDARY_SYNTAX) && (help_count < 3))
continue;
if (strlen(_cmdline.commands[i].desc))
_print_description(i);
@@ -1585,6 +1686,11 @@ static int _usage(const char *name, int help_count)
log_print(". The _new suffix indicates the VG or LV must not yet exist.");
log_print(". LV followed by _<type> indicates that an LV of the given type");
log_print(" is required. (raid represents any raid<N> type.)");
log_print(". The default output unit is specified by letter, followed by |unit");
log_print(" which represents other possible units: hHbBsSkKmMgGtTpPeE.");
log_print(". Output units are 1024 SI base, regardless of unit capitalization.");
log_print(". Use --help --help --help to print secondary command syntax");
log_print(" formats that are recognized, e.g. for compatibility.");
log_print(". See man pages for short option equivalents of long option names,");
log_print(" and for more detailed descriptions of variable parameters.");
}

View File

@@ -801,10 +801,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
return 0;
}
if (arg_is_set(cmd, metadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else if (arg_is_set(cmd, vgmetadatacopies_ARG))
if (arg_is_set(cmd, vgmetadatacopies_ARG))
vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG,
DEFAULT_VGMETADATACOPIES);
else
@@ -4004,11 +4001,6 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
if (pp->pva.pvmetadatacopies < 0)
pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
if (pp->pva.pvmetadatacopies > 2) {
log_error("Metadatacopies may only be 0, 1 or 2");
return 0;
}
pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
return 1;

View File

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

View File

@@ -57,11 +57,13 @@
* words is not defined or stored in a consistent way,
* but is just whatever the parsing function happens to look
* for, so adding a new accepted value for the val type is
* often just making the parsing function recognize a new
* word. This new word should then also be added to the
* usage string for the val type here. It would be nice
* if the accepted values could be defined in a more
* consistent way, perhaps in struct val_props.
* generally making the parsing function recognize a new
* word, and making the implementation code also recognize
* that word to do something different. This new word should
* then also be added to the usage string for the val type here.
* It would be nice if the accepted values could be defined in a
* more consistent way, and perhaps in a single place, perhaps in
* struct val_props.
*
* The usage text for an option is not always the full
* set of words accepted for an option, but may be a
@@ -92,9 +94,9 @@
* should avoid suggesting the upper case letters.
*/
val(none_VAL, NULL, "None", "") /* unused, for enum value 0 */
val(conststr_VAL, NULL, "ConstString", "") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "") /* used only for command defs */
val(none_VAL, NULL, "None", "ERR") /* unused, for enum value 0 */
val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
val(bool_VAL, yes_no_arg, "Bool", "y|n")
val(number_VAL, int_arg, "Number", NULL)
val(string_VAL, string_arg, "String", NULL)
@@ -116,21 +118,19 @@ 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")
/* 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(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
val(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Number")
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin")
val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]")
val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
/* this should always be last */
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:
*
* configreport_ARG, configtype_ARG, polloperation_ARG, raidrebuild_ARG,
* raidsyncaction_ARG, raidwritemostly_ARG, reportformat_ARG, syncaction_ARG,
* cachepolicy_ARG, cachesettings_ARG, writemostly_ARG
*/

View File

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

View File

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

View File

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