mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-03 08:23:48 +03:00
Compare commits
1 Commits
dev-dct-cm
...
dev-dct-cm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1581f36ef3 |
@@ -94,13 +94,6 @@ struct cmd_context {
|
||||
struct arg_values *opt_arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
|
||||
/*
|
||||
* Position args remaining after command name
|
||||
* and --options are removed from original argc/argv.
|
||||
*/
|
||||
int position_argc;
|
||||
char **position_argv;
|
||||
|
||||
/*
|
||||
* Format handlers.
|
||||
*/
|
||||
|
||||
@@ -319,6 +319,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
||||
{
|
||||
int top_level = 0;
|
||||
unsigned snap_count;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/* non-top-level LVs */
|
||||
if (lv_is_thin_pool_metadata(lv)) {
|
||||
@@ -352,7 +353,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
|
||||
goto_bad;
|
||||
}
|
||||
if (lv_is_thin_snapshot(lv))
|
||||
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
||||
if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
|
||||
goto_bad;
|
||||
|
||||
@@ -1066,16 +1066,9 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l
|
||||
* Useful functions for managing snapshots.
|
||||
*/
|
||||
int lv_is_origin(const struct logical_volume *lv);
|
||||
#define lv_is_thick_origin lv_is_origin
|
||||
|
||||
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
|
||||
int lv_is_thin_snapshot(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv);
|
||||
#define lv_is_thick_snapshot lv_is_cow
|
||||
|
||||
int lv_is_cache_origin(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv);
|
||||
int lv_is_merging_cow(const struct logical_volume *cow);
|
||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
||||
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
|
||||
|
||||
@@ -748,19 +748,6 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count)
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_is_thin_snapshot(const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (!lv_is_thin_volume(lv))
|
||||
return 0;
|
||||
|
||||
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Explict check of new thin pool for usability
|
||||
*
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
* Put all long args that don't have a corresponding short option first.
|
||||
*/
|
||||
/* *INDENT-OFF* */
|
||||
arg(ARG_UNUSED, '-', "", 0, 0, 0) /* place holder for unused 0 value */
|
||||
|
||||
arg(abort_ARG, '\0', "abort", 0, 0, 0)
|
||||
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
|
||||
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
|
||||
|
||||
@@ -115,32 +115,6 @@
|
||||
# included in the text as indicators of new lines when printing
|
||||
# the descriptions for help/man output.
|
||||
#
|
||||
# RULE: rules that a given command must follow, i.e. required (and)
|
||||
# or invalid (not) combinations of options, LV types or LV properties.
|
||||
#
|
||||
# RULE: A and|not B
|
||||
#
|
||||
# Conditions in A are applied to a given command+LV.
|
||||
# If the conditions in A are true, then the requirements
|
||||
# in B are applied. If the conditions in B are true|false
|
||||
# according to and|not, then the command fails or continues.
|
||||
#
|
||||
# RULE: A and B
|
||||
# if the conditions in A apply, then
|
||||
# if the conditions in B are not true, the command fails.
|
||||
#
|
||||
# RULE: A not B
|
||||
# if the conditions in B apply, then
|
||||
# if the conditions in B are true, the command fails.
|
||||
#
|
||||
# RULE: --opt|LV_type|lv_is_prop|all and|not --opt|LV_type|lv_is_prop
|
||||
# RULE: --opt1 not --opt2
|
||||
# RULE: --opt1 and --opt2
|
||||
# RULE: --opt1 LV_type1 lv_is_prop1 and --opt2
|
||||
# RULE: --opt1 LV_type1 and lv_is_prop1
|
||||
# RULE: LV_type1 and lv_is_prop1
|
||||
#
|
||||
#
|
||||
# Note that one the most difficult aspect of these definitions is
|
||||
# the variants of --thin / --type thin / --type thin-pool,
|
||||
# --cache / --type cache / --type cache-pool.
|
||||
@@ -149,6 +123,42 @@
|
||||
# to be tested individually to see what it means.
|
||||
#
|
||||
|
||||
#
|
||||
# Another capability we might want to add here is a way to express
|
||||
# rules, per definition, of what arg combinations are allowed or
|
||||
# required, e.g.
|
||||
#
|
||||
# if --foo is set, then --bar cannot be set could be encoded as:
|
||||
# RULE_OPT_INVALID_OPT: --foo --bar
|
||||
#
|
||||
# if --foo is set, then --bar is required could be encoded as:
|
||||
# RULE_OPT_REQUIRES_OPT: --foo --bar
|
||||
#
|
||||
# if --foo is set, then positional arg 1 is required
|
||||
# (the type of value in that arg is specified by the command def):
|
||||
# RULE_OPT_REQUIRES_POS: --foo 1
|
||||
#
|
||||
#
|
||||
# The rules could also specify validation for positional LV args:
|
||||
#
|
||||
# if --foo is set, then specified lv checks must pass:
|
||||
# RULE_OPT_REQUIRES_LV_CHECK: --foo lv_is_merging_origin
|
||||
#
|
||||
# if --foo is set, then specified lv checks must not pass:
|
||||
# RULE_OPT_INVALID_LV_CHECK: --foo lv_is_merging_origin
|
||||
#
|
||||
# command def requires specified lv checks must pass:
|
||||
# RULE_OPT_REQUIRES_LV_CHECK: * lv_is_merging_origin
|
||||
#
|
||||
# command def requires specified lv checks must not pass:
|
||||
# RULE_OPT_INVALID_LV_CHECK: * lv_is_merging_origin
|
||||
#
|
||||
#
|
||||
# To implement would require a rule structure, and an array of
|
||||
# rule structures would be added to struct command, to be filled
|
||||
# in like the args arrays are.
|
||||
#
|
||||
|
||||
#
|
||||
# For efficiency, sets of options can be defined and reused
|
||||
# in multiple command definitions.
|
||||
@@ -211,9 +221,9 @@ OO_CONFIG: --atversion String, --typeconfig ConfigType, --file String, --ignorea
|
||||
|
||||
# None of these can function as a required option for lvchange.
|
||||
|
||||
OO_LVCHANGE: --autobackup Bool, --force, --ignoremonitoring,
|
||||
--ignoreskippedcluster, --noudevsync, --reportformat ReportFmt,
|
||||
--select String
|
||||
OO_LVCHANGE: --autobackup Bool, --force, --ignorelockingfailure,
|
||||
--ignoremonitoring, --ignoreskippedcluster, --noudevsync,
|
||||
--reportformat ReportFmt, --sysinit, --select String
|
||||
|
||||
# Any of these can function as a required option for lvchange.
|
||||
# profile is also part of OO_ALL, but is repeated in OO_LVCHANGE_META
|
||||
@@ -226,59 +236,30 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--errorwhenfull Bool, --discards Discards, --zero Bool,
|
||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
|
||||
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||
--writebehind Number, --writemostly WriteMostlyPV, --persistent n
|
||||
--writebehind Number, --writemostly WriteMostlyPV
|
||||
|
||||
lvchange OO_LVCHANGE_META VG|LV|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_properties
|
||||
DESC: Change a general LV property.
|
||||
RULE: all not lv_is_pvmove lv_is_mirror_log lv_is_mirror_image
|
||||
RULE: all and lv_is_vg_writable
|
||||
RULE: --contiguous not --alloc
|
||||
RULE: --profile not --detachprofile
|
||||
RULE: --metadataprofile not --detachprofile
|
||||
RULE: --minrecoveryrate and LV_raid
|
||||
RULE: --maxrecoveryrate and LV_raid
|
||||
RULE: --writebehind and LV_raid1
|
||||
RULE: --writemostly and LV_raid1
|
||||
RULE: --cachemode and LV_cache LV_cachepool
|
||||
RULE: --cachepolicy and LV_cache LV_cachepool
|
||||
RULE: --cachesettings and LV_cache LV_cachepool
|
||||
RULE: --errorwhenfull and LV_thinpool
|
||||
RULE: --discards and LV_thinpool
|
||||
RULE: --zero and LV_thinpool
|
||||
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
|
||||
RULE: --alloc not lv_is_thick_origin
|
||||
RULE: --contiguous not lv_is_thick_origin
|
||||
RULE: --metadataprofile not lv_is_thick_origin
|
||||
RULE: --permission not lv_is_thick_origin
|
||||
RULE: --persistent not lv_is_thick_origin
|
||||
RULE: --profile not lv_is_thick_origin
|
||||
RULE: --readahead not lv_is_thick_origin
|
||||
|
||||
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_resync
|
||||
DESC: Resyncronize a mirror or raid LV.
|
||||
RULE: all not lv_is_pvmove lv_is_locked
|
||||
RULE: all not LV_raid0
|
||||
|
||||
lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_syncaction
|
||||
DESC: Resynchronize or check a raid LV.
|
||||
RULE: all not LV_raid0
|
||||
|
||||
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_rebuild
|
||||
DESC: Reconstruct data on specific PVs of a raid LV.
|
||||
RULE: all not LV_raid0
|
||||
|
||||
# try removing the META change options from here?
|
||||
lvchange --activate Active VG|LV|Tag|Select ...
|
||||
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip,
|
||||
--ignorelockingfailure, --sysinit, OO_LVCHANGE_META, OO_LVCHANGE
|
||||
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip, OO_LVCHANGE_META, OO_LVCHANGE
|
||||
ID: lvchange_activate
|
||||
DESC: Activate or deactivate an LV.
|
||||
|
||||
@@ -291,18 +272,16 @@ lvchange --monitor Bool VG|LV|Tag|Select ...
|
||||
OO: --poll Bool, OO_LVCHANGE
|
||||
ID: lvchange_monitor
|
||||
DESC: Start or stop monitoring an LV from dmeventd.
|
||||
RULE: all not lv_is_pvmove
|
||||
|
||||
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 y --minor Number LV
|
||||
OO: --major Number, OO_LVCHANGE
|
||||
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.
|
||||
RULE: all not LV_thinpool LV_cachepool
|
||||
|
||||
---
|
||||
|
||||
@@ -324,7 +303,6 @@ OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to linear.
|
||||
RULE: all not lv_is_locked lv_is_pvmove
|
||||
|
||||
lvconvert --type striped LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
@@ -503,7 +481,6 @@ ID: lvconvert_merge
|
||||
DESC: Merge LV that was previously split from a mirror.
|
||||
DESC: Merge thin LV into its origin LV.
|
||||
DESC: Merge COW snapshot LV into its origin.
|
||||
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||
|
||||
---
|
||||
|
||||
|
||||
110
tools/command.h
110
tools/command.h
@@ -54,6 +54,27 @@ struct command_name {
|
||||
#define ARG_DEF_FLAG_NEW 1 << 0
|
||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
|
||||
|
||||
/* arg_def lv_types */
|
||||
enum {
|
||||
ARG_DEF_LV_ANY = 0,
|
||||
ARG_DEF_LV_LINEAR = 1 << 0,
|
||||
ARG_DEF_LV_STRIPED = 1 << 1,
|
||||
ARG_DEF_LV_SNAPSHOT = 1 << 2,
|
||||
ARG_DEF_LV_MIRROR = 1 << 3,
|
||||
ARG_DEF_LV_RAID = 1 << 4,
|
||||
ARG_DEF_LV_RAID0 = 1 << 5,
|
||||
ARG_DEF_LV_RAID1 = 1 << 6,
|
||||
ARG_DEF_LV_RAID4 = 1 << 7,
|
||||
ARG_DEF_LV_RAID5 = 1 << 8,
|
||||
ARG_DEF_LV_RAID6 = 1 << 9,
|
||||
ARG_DEF_LV_RAID10 = 1 << 10,
|
||||
ARG_DEF_LV_THIN = 1 << 11,
|
||||
ARG_DEF_LV_THINPOOL = 1 << 12,
|
||||
ARG_DEF_LV_CACHE = 1 << 13,
|
||||
ARG_DEF_LV_CACHEPOOL = 1 << 14,
|
||||
ARG_DEF_LV_LAST = 1 << 15,
|
||||
};
|
||||
|
||||
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
|
||||
{
|
||||
return (val_bits & (1 << val_enum)) ? 1 : 0;
|
||||
@@ -64,33 +85,13 @@ static inline uint64_t val_enum_to_bit(int val_enum)
|
||||
return (1ULL << val_enum);
|
||||
}
|
||||
|
||||
static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum)
|
||||
{
|
||||
return (lvp_bits & (1 << lvp_enum)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint64_t lvp_enum_to_bit(int lvp_enum)
|
||||
{
|
||||
return (1ULL << lvp_enum);
|
||||
}
|
||||
|
||||
static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum)
|
||||
{
|
||||
return (lvt_bits & (1 << lvt_enum)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint64_t lvt_enum_to_bit(int lvt_enum)
|
||||
{
|
||||
return (1ULL << lvt_enum);
|
||||
}
|
||||
|
||||
/* Description a value that follows an option or exists in a position. */
|
||||
|
||||
struct arg_def {
|
||||
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
|
||||
uint64_t lvt_bits; /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */
|
||||
uint64_t num; /* a literal number for conststr_VAL */
|
||||
const char *str; /* a literal string for constnum_VAL */
|
||||
uint32_t lv_types; /* ARG_DEF_LV_, for lv_VAL, can be multiple */
|
||||
uint32_t flags; /* ARG_DEF_FLAG_ */
|
||||
};
|
||||
|
||||
@@ -108,33 +109,6 @@ struct pos_arg {
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Commands using a given command definition must follow a set
|
||||
* of rules. If a given command+LV match the conditions in
|
||||
* opt/lvt_bits/lvp_bits, then the conditions in check_...
|
||||
* are applied.
|
||||
*
|
||||
* Rules that include only options can be verified before the VG
|
||||
* is read. Otherwise, the rules are verified in process_each
|
||||
* after the VG is read.
|
||||
*/
|
||||
|
||||
#define RULE_INVALID 1
|
||||
#define RULE_REQUIRE 2
|
||||
|
||||
struct cmd_rule {
|
||||
int opt; /* apply rule when this option is set (foo_ARG) */
|
||||
uint64_t lvt_bits; /* apply rule when LV has one of these types (lvt_enum_to_bit) */
|
||||
uint64_t lvp_bits; /* apply rule when LV has all these properties (lvp_enum_to_bit) */
|
||||
|
||||
uint32_t rule; /* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
|
||||
|
||||
int check_opt; /* this option must [not] be set */
|
||||
uint64_t check_lvt_bits; /* LV must [not] have this type */
|
||||
uint64_t check_lvp_bits; /* LV must [not] have these properties */
|
||||
};
|
||||
|
||||
/*
|
||||
* CMD_RO_ARGS needs to accomodate a list of options,
|
||||
* of which one is required after which the rest are
|
||||
@@ -144,7 +118,6 @@ struct cmd_rule {
|
||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||
#define CMD_RP_ARGS 8 /* required positional args */
|
||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||
#define CMD_MAX_RULES 32 /* max number of rules per command def */
|
||||
|
||||
/*
|
||||
* one or more from required_opt_args is required,
|
||||
@@ -185,8 +158,6 @@ struct command {
|
||||
/* optional positional args */
|
||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||
|
||||
struct cmd_rule rules[CMD_MAX_RULES];
|
||||
|
||||
int ro_count;
|
||||
int oo_count;
|
||||
int rp_count;
|
||||
@@ -195,7 +166,42 @@ struct command {
|
||||
/* used for processing current position */
|
||||
int pos_count;
|
||||
|
||||
int rule_count;
|
||||
/* struct cmd_rule rules[CMD_RULES]; */
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
/*
|
||||
* if rule.opt is set, then rule.type specifies if rule.check values
|
||||
* are required or invalid.
|
||||
*
|
||||
* if (arg_is_set(rule.opt) &&
|
||||
* (rule.type & RULE_OPT_INVALID_OPT) && arg_is_set(rule.check.opt)) {
|
||||
* log_error("option %s and option %s cannot be used together");
|
||||
* }
|
||||
*
|
||||
* if (arg_is_set(rule.opt) &&
|
||||
* (rule.type & RULE_OPT_REQUIRES_LV_CHECK) && !lv_check(lv, rule.check.bits, &fail_bits)) {
|
||||
* log_error("LV %s must be %s", lv, lv_check_to_str(fail_bits));
|
||||
* }
|
||||
*
|
||||
* if (arg_is_set(rule.opt) &&
|
||||
* (rule.type & RULE_OPT_INVALID_LV_CHECK) && lv_check(lv, rule.check.bits, &fail_bits)) {
|
||||
* log_error("LV %s must not be %s", lv, lv_check_to_str(fail_bits));
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
struct cmd_rule {
|
||||
int opt; /* foo_ARG, or INT_MAX for command def in general */
|
||||
int type; /* RULE_ specifies how to require/prohibit check value */
|
||||
|
||||
union {
|
||||
int opt;
|
||||
int pos;
|
||||
uint64_t bits;
|
||||
} check;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -57,42 +57,28 @@ int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg
|
||||
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 in tools.h and args.h */
|
||||
/* also see arg_props */
|
||||
struct opt_name {
|
||||
const char *name; /* "foo_ARG" */
|
||||
int opt_enum; /* foo_ARG */
|
||||
const char short_opt; /* -f */
|
||||
const char *name;
|
||||
int opt_enum; /* enum from args.h */
|
||||
const char short_opt;
|
||||
char _padding[7];
|
||||
const char *long_opt; /* --foo */
|
||||
int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
|
||||
const char *long_opt;
|
||||
int val_enum; /* enum from vals.h */
|
||||
uint32_t unused1;
|
||||
uint32_t unused2;
|
||||
};
|
||||
|
||||
/* also see val_props in tools.h and vals.h */
|
||||
/* also see val_props */
|
||||
struct val_name {
|
||||
const char *enum_name; /* "foo_VAL" */
|
||||
int val_enum; /* foo_VAL */
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av); /* foo_arg() */
|
||||
const char *name; /* FooVal */
|
||||
const char *enum_name;
|
||||
int val_enum; /* enum from vals.h */
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av); /* unused here */
|
||||
const char *name;
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
/* also see lv_props in tools.h and lv_props.h */
|
||||
struct lvp_name {
|
||||
const char *enum_name; /* "is_foo_LVP" */
|
||||
int lvp_enum; /* is_foo_LVP */
|
||||
const char *name; /* "lv_is_foo" */
|
||||
};
|
||||
|
||||
/* also see lv_types in tools.h and lv_types.h */
|
||||
struct lvt_name {
|
||||
const char *enum_name; /* "foo_LVT" */
|
||||
int lvt_enum; /* foo_LVT */
|
||||
const char *name; /* "foo" */
|
||||
};
|
||||
|
||||
/* create foo_VAL enums for option and position values */
|
||||
/* create foo_VAL enums */
|
||||
|
||||
enum {
|
||||
#define val(a, b, c, d) a ,
|
||||
@@ -100,7 +86,7 @@ enum {
|
||||
#undef val
|
||||
};
|
||||
|
||||
/* create foo_ARG enums for --option's */
|
||||
/* create foo_ARG enums */
|
||||
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
@@ -108,22 +94,6 @@ enum {
|
||||
#undef arg
|
||||
};
|
||||
|
||||
/* create foo_LVP enums for LV properties */
|
||||
|
||||
enum {
|
||||
#define lvp(a, b, c) a,
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/* create foo_LVT enums for LV types */
|
||||
|
||||
enum {
|
||||
#define lvt(a, b, c) a,
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
/* create table of value names, e.g. String, and corresponding enum from vals.h */
|
||||
|
||||
static struct val_name val_names[VAL_COUNT + 1] = {
|
||||
@@ -140,22 +110,6 @@ static struct opt_name opt_names[ARG_COUNT + 1] = {
|
||||
#undef arg
|
||||
};
|
||||
|
||||
/* create table of lv property names, e.g. lv_is_foo, and corresponding enum from lv_props.h */
|
||||
|
||||
static struct lvp_name lvp_names[LVP_COUNT + 1] = {
|
||||
#define lvp(a, b, c) { # a, a, b },
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/* create table of lv type names, e.g. linear and corresponding enum from lv_types.h */
|
||||
|
||||
static struct lvt_name lvt_names[LVT_COUNT + 1] = {
|
||||
#define lvt(a, b, c) { # a, a, b },
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#define MAX_CMD_NAMES 128
|
||||
@@ -309,7 +263,7 @@ static int opt_str_to_num(char *str)
|
||||
|
||||
static char *val_bits_to_str(uint64_t val_bits)
|
||||
{
|
||||
static char buf[1024];
|
||||
static char buf[128];
|
||||
int i;
|
||||
int or = 0;
|
||||
|
||||
@@ -329,130 +283,212 @@ static char *val_bits_to_str(uint64_t val_bits)
|
||||
}
|
||||
|
||||
/*
|
||||
* When bits for foo_LVP and bar_LVP are both set in bits, print:
|
||||
* lvp_enum_to_bit(foo_LVP) | lvp_enum_to_bit(bar_LVP)
|
||||
* The _<lvtype> and _new suffixes are only used by the command definitions and
|
||||
* are not exposed to lvm at large, which uses only the ARG_DEF values.
|
||||
*/
|
||||
|
||||
static char *lvp_bits_to_str(uint64_t bits)
|
||||
static uint32_t lv_str_to_types(char *str)
|
||||
{
|
||||
static char lvp_buf[1024];
|
||||
int i;
|
||||
int or = 0;
|
||||
|
||||
memset(lvp_buf, 0, sizeof(lvp_buf));
|
||||
|
||||
for (i = 0; i < LVP_COUNT; i++) {
|
||||
if (bits & lvp_enum_to_bit(i)) {
|
||||
if (or) strcat(lvp_buf, " | ");
|
||||
strcat(lvp_buf, "lvp_enum_to_bit(");
|
||||
strcat(lvp_buf, lvp_names[i].enum_name);
|
||||
strcat(lvp_buf, ")");
|
||||
or = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return lvp_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* When bits for foo_LVT and bar_LVT are both set in bits, print:
|
||||
* lvt_enum_to_bit(foo_LVT) | lvt_enum_to_bit(bar_LVT)
|
||||
*/
|
||||
|
||||
static char *lvt_bits_to_str(uint64_t bits)
|
||||
{
|
||||
static char lvt_buf[1024];
|
||||
int i;
|
||||
int or = 0;
|
||||
|
||||
memset(lvt_buf, 0, sizeof(lvt_buf));
|
||||
|
||||
for (i = 1; i < LVT_COUNT; i++) {
|
||||
if (bits & lvt_enum_to_bit(i)) {
|
||||
if (or) strcat(lvt_buf, " | ");
|
||||
strcat(lvt_buf, "lvt_enum_to_bit(");
|
||||
strcat(lvt_buf, lvt_names[i].enum_name);
|
||||
strcat(lvt_buf, ")");
|
||||
or = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return lvt_buf;
|
||||
}
|
||||
|
||||
/* "lv_is_prop" to is_prop_LVP */
|
||||
|
||||
static int lvp_name_to_enum(char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < LVP_COUNT; i++) {
|
||||
if (!strcmp(str, lvp_names[i].name))
|
||||
return lvp_names[i].lvp_enum;
|
||||
}
|
||||
printf("unknown lv property %s\n", str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* type_LVT to "type" */
|
||||
|
||||
static const char *lvt_enum_to_name(int lvt_enum)
|
||||
{
|
||||
return lvt_names[lvt_enum].name;
|
||||
}
|
||||
|
||||
/* "type" to type_LVT */
|
||||
|
||||
static int lvt_name_to_enum(char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < LVT_COUNT; i++) {
|
||||
if (!strcmp(str, lvt_names[i].name))
|
||||
return lvt_names[i].lvt_enum;
|
||||
}
|
||||
printf("unknown lv type %s\n", str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* LV_<type> to <type>_LVT */
|
||||
|
||||
int lv_to_enum(char *name)
|
||||
{
|
||||
return lvt_name_to_enum(name + 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* LV_<type1>_<type2> to lvt_bits
|
||||
*
|
||||
* type1 to lvt_enum
|
||||
* lvt_bits |= lvt_enum_to_bit(lvt_enum)
|
||||
* type2 to lvt_enum
|
||||
* lvt_bits |= lvt_enum_to_bit(lvt_enum)
|
||||
*/
|
||||
|
||||
uint64_t lv_to_bits(char *name)
|
||||
{
|
||||
char buf[64];
|
||||
char copy[128] = { 0 };
|
||||
char *argv[MAX_LINE_ARGC];
|
||||
uint64_t lvt_bits = 0;
|
||||
int lvt_enum;
|
||||
int argc;
|
||||
char *name;
|
||||
uint32_t types = 0;
|
||||
int i;
|
||||
|
||||
strcpy(buf, name);
|
||||
strncpy(copy, str, 128);
|
||||
|
||||
split_line(buf, &argc, argv, '_');
|
||||
split_line(copy, &argc, argv, '_');
|
||||
|
||||
/* 0 is "LV" */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "new"))
|
||||
continue;
|
||||
lvt_enum = lvt_name_to_enum(argv[i]);
|
||||
lvt_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
for (i = 0; i < argc; i++) {
|
||||
name = argv[i];
|
||||
|
||||
if (!strcmp(name, "linear"))
|
||||
types |= ARG_DEF_LV_LINEAR;
|
||||
|
||||
if (!strcmp(name, "striped"))
|
||||
types |= ARG_DEF_LV_STRIPED;
|
||||
|
||||
if (!strcmp(name, "snapshot"))
|
||||
types |= ARG_DEF_LV_SNAPSHOT;
|
||||
|
||||
if (!strcmp(name, "mirror"))
|
||||
types |= ARG_DEF_LV_MIRROR;
|
||||
|
||||
if (!strcmp(name, "thin"))
|
||||
types |= ARG_DEF_LV_THIN;
|
||||
|
||||
if (!strcmp(name, "thinpool"))
|
||||
types |= ARG_DEF_LV_THINPOOL;
|
||||
|
||||
if (!strcmp(name, "cache"))
|
||||
types |= ARG_DEF_LV_CACHE;
|
||||
|
||||
if (!strcmp(name, "cachepool"))
|
||||
types |= ARG_DEF_LV_CACHEPOOL;
|
||||
|
||||
if (!strcmp(name, "raid0"))
|
||||
types |= ARG_DEF_LV_RAID0;
|
||||
|
||||
if (!strcmp(name, "raid1"))
|
||||
types |= ARG_DEF_LV_RAID1;
|
||||
|
||||
if (!strcmp(name, "raid4"))
|
||||
types |= ARG_DEF_LV_RAID4;
|
||||
|
||||
if (!strcmp(name, "raid5"))
|
||||
types |= ARG_DEF_LV_RAID5;
|
||||
|
||||
if (!strcmp(name, "raid6"))
|
||||
types |= ARG_DEF_LV_RAID6;
|
||||
|
||||
if (!strcmp(name, "raid10"))
|
||||
types |= ARG_DEF_LV_RAID10;
|
||||
|
||||
if (!strcmp(name, "raid"))
|
||||
types |= ARG_DEF_LV_RAID;
|
||||
}
|
||||
|
||||
return lvt_bits;
|
||||
return types;
|
||||
}
|
||||
|
||||
static const char *lv_num_to_str(int num)
|
||||
{
|
||||
switch (num) {
|
||||
case ARG_DEF_LV_LINEAR:
|
||||
return "linear";
|
||||
case ARG_DEF_LV_STRIPED:
|
||||
return "striped";
|
||||
case ARG_DEF_LV_SNAPSHOT:
|
||||
return "snapshot";
|
||||
case ARG_DEF_LV_MIRROR:
|
||||
return "mirror";
|
||||
case ARG_DEF_LV_RAID:
|
||||
return "raid";
|
||||
case ARG_DEF_LV_RAID0:
|
||||
return "raid0";
|
||||
case ARG_DEF_LV_RAID1:
|
||||
return "raid1";
|
||||
case ARG_DEF_LV_RAID4:
|
||||
return "raid4";
|
||||
case ARG_DEF_LV_RAID5:
|
||||
return "raid5";
|
||||
case ARG_DEF_LV_RAID6:
|
||||
return "raid6";
|
||||
case ARG_DEF_LV_RAID10:
|
||||
return "raid10";
|
||||
case ARG_DEF_LV_THIN:
|
||||
return "thin";
|
||||
case ARG_DEF_LV_THINPOOL:
|
||||
return "thinpool";
|
||||
case ARG_DEF_LV_CACHE:
|
||||
return "cache";
|
||||
case ARG_DEF_LV_CACHEPOOL:
|
||||
return "cachepool";
|
||||
default:
|
||||
printf("lv_num_to_str: unknown LV num: %d\n", num);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static char *lv_types_to_flags(int lv_types)
|
||||
{
|
||||
static char buf_lv_types[128];
|
||||
int or = 0;
|
||||
|
||||
memset(buf_lv_types, 0, sizeof(buf_lv_types));
|
||||
|
||||
if (lv_types & ARG_DEF_LV_LINEAR) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_LINEAR");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_STRIPED) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_STRIPED");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_SNAPSHOT) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_SNAPSHOT");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_MIRROR) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_MIRROR");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID0) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID0");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID1) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID1");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID4) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID4");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID5) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID5");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID6) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID6");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_RAID10) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_RAID10");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_THIN) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_THIN");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_THINPOOL) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_THINPOOL");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_CACHE) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_CACHE");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
if (lv_types & ARG_DEF_LV_CACHEPOOL) {
|
||||
if (or) strcat(buf_lv_types, " | ");
|
||||
strcat(buf_lv_types, "ARG_DEF_LV_CACHEPOOL");
|
||||
or = 1;
|
||||
}
|
||||
|
||||
return buf_lv_types;
|
||||
}
|
||||
|
||||
static const char *is_command_name(char *str)
|
||||
@@ -531,7 +567,7 @@ static int is_pos_name(char *str)
|
||||
|
||||
static int is_oo_definition(char *str)
|
||||
{
|
||||
if (!strncmp(str, "OO_", 3) && strstr(str, ":"))
|
||||
if (!strncmp(str, "OO_", 3))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -564,13 +600,6 @@ static int is_flags_line(char *str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_rule_line(char *str)
|
||||
{
|
||||
if (!strncmp(str, "RULE:", 5))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_id_line(char *str)
|
||||
{
|
||||
if (!strncmp(str, "ID:", 3))
|
||||
@@ -606,7 +635,7 @@ static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
|
||||
def->val_bits |= val_enum_to_bit(val_enum);
|
||||
|
||||
if ((val_enum == lv_VAL) && strstr(name, "_"))
|
||||
def->lvt_bits = lv_to_bits(name);
|
||||
def->lv_types = lv_str_to_types(name);
|
||||
|
||||
if (strstr(name, "_new"))
|
||||
def->flags |= ARG_DEF_FLAG_NEW;
|
||||
@@ -658,7 +687,7 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
|
||||
|
||||
if (val_enum == lv_VAL) {
|
||||
if (strstr(name, "_"))
|
||||
def->lvt_bits = lv_to_bits(name);
|
||||
def->lv_types = lv_str_to_types(name);
|
||||
}
|
||||
|
||||
if ((val_enum == vg_VAL) || (val_enum == lv_VAL) || (val_enum == pv_VAL)) {
|
||||
@@ -976,7 +1005,6 @@ static void add_required_line(struct command *cmd, int argc, char *argv[])
|
||||
static void print_def(struct arg_def *def, int usage)
|
||||
{
|
||||
int val_enum;
|
||||
int lvt_enum;
|
||||
int sep = 0;
|
||||
int i;
|
||||
|
||||
@@ -1000,10 +1028,10 @@ static void print_def(struct arg_def *def, int usage)
|
||||
sep = 1;
|
||||
}
|
||||
|
||||
if (val_enum == lv_VAL && def->lvt_bits) {
|
||||
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
|
||||
printf("_%s", lvt_enum_to_name(lvt_enum));
|
||||
if (val_enum == lv_VAL && def->lv_types) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (def->lv_types & (1 << i))
|
||||
printf("_%s", lv_num_to_str(1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,79 +1190,6 @@ static void add_flags(struct command *cmd, char *line)
|
||||
cmd->cmd_flags |= CMD_FLAG_SECONDARY_SYNTAX;
|
||||
}
|
||||
|
||||
static void add_rule(struct command *cmd, char *line)
|
||||
{
|
||||
struct cmd_rule *rule;
|
||||
char *line_argv[MAX_LINE_ARGC];
|
||||
char *arg;
|
||||
int line_argc;
|
||||
int i, lvt_enum, lvp_enum;
|
||||
int check = 0;
|
||||
|
||||
if (cmd->rule_count == CMD_MAX_RULES) {
|
||||
printf("too many rules for cmd\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rule = &cmd->rules[cmd->rule_count++];
|
||||
|
||||
split_line(line, &line_argc, line_argv, ' ');
|
||||
|
||||
for (i = 0; i < line_argc; i++) {
|
||||
arg = line_argv[i];
|
||||
|
||||
if (!strcmp(arg, "not")) {
|
||||
rule->rule = RULE_INVALID;
|
||||
check = 1;
|
||||
}
|
||||
|
||||
else if (!strcmp(arg, "and")) {
|
||||
rule->rule = RULE_REQUIRE;
|
||||
check = 1;
|
||||
}
|
||||
|
||||
else if (!strncmp(arg, "all", 3)) {
|
||||
/* opt/lvt_bits/lvp_bits all remain 0 to mean all */
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (!strncmp(arg, "--", 2)) {
|
||||
if (check)
|
||||
rule->check_opt = opt_str_to_num(arg);
|
||||
else
|
||||
rule->opt = opt_str_to_num(arg);
|
||||
}
|
||||
|
||||
else if (!strncmp(arg, "LV_", 3)) {
|
||||
lvt_enum = lv_to_enum(arg);
|
||||
|
||||
if (check)
|
||||
rule->check_lvt_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
else
|
||||
rule->lvt_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
}
|
||||
|
||||
else if (!strncmp(arg, "lv_is_", 6)) {
|
||||
lvp_enum = lvp_name_to_enum(arg);
|
||||
|
||||
if (check)
|
||||
rule->check_lvp_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
else
|
||||
rule->lvp_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *rule_to_define_str(int rule_type)
|
||||
{
|
||||
switch (rule_type) {
|
||||
case RULE_INVALID:
|
||||
return "RULE_INVALID";
|
||||
case RULE_REQUIRE:
|
||||
return "RULE_REQUIRE";
|
||||
}
|
||||
}
|
||||
|
||||
static char *cmd_flags_to_str(uint32_t flags)
|
||||
{
|
||||
static char buf_cmd_flags[32];
|
||||
@@ -1612,7 +1567,6 @@ static void print_val_man(const char *str)
|
||||
static void print_def_man(struct arg_def *def, int usage)
|
||||
{
|
||||
int val_enum;
|
||||
int lvt_enum;
|
||||
int sep = 0;
|
||||
int i;
|
||||
|
||||
@@ -1645,11 +1599,11 @@ static void print_def_man(struct arg_def *def, int usage)
|
||||
sep = 1;
|
||||
}
|
||||
|
||||
if (val_enum == lv_VAL && def->lvt_bits) {
|
||||
if (val_enum == lv_VAL && def->lv_types) {
|
||||
printf("\\fI");
|
||||
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (lvt_bit_is_set(def->lvt_bits, lvt_enum))
|
||||
printf("_%s", lvt_enum_to_name(lvt_enum));
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (def->lv_types & (1 << i))
|
||||
printf("_%s", lv_num_to_str(1 << i));
|
||||
}
|
||||
printf("\\fP");
|
||||
}
|
||||
@@ -1975,7 +1929,7 @@ void print_man_usage(struct command *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
printf(" ]\n");
|
||||
printf("]\n");
|
||||
printf(".RE\n");
|
||||
|
||||
done:
|
||||
@@ -2361,7 +2315,7 @@ void print_man_command(void)
|
||||
void print_command_struct(int only_usage)
|
||||
{
|
||||
struct command *cmd;
|
||||
int i, j, ro, rp, oo, op, ru;
|
||||
int i, j, ro, rp, oo, op;
|
||||
|
||||
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
|
||||
|
||||
@@ -2387,7 +2341,6 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count);
|
||||
printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
|
||||
printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
|
||||
printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
|
||||
|
||||
if (cmd->cmd_flags)
|
||||
printf("commands[%d].cmd_flags = %s;\n", i, cmd_flags_to_str(cmd->cmd_flags));
|
||||
@@ -2416,9 +2369,9 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].required_opt_args[%d].def.val_bits = %s;\n",
|
||||
i, ro, val_bits_to_str(cmd->required_opt_args[ro].def.val_bits));
|
||||
|
||||
if (cmd->required_opt_args[ro].def.lvt_bits)
|
||||
printf("commands[%d].required_opt_args[%d].def.lvt_bits = %s;\n",
|
||||
i, ro, lvt_bits_to_str(cmd->required_opt_args[ro].def.lvt_bits));
|
||||
if (cmd->required_opt_args[ro].def.lv_types)
|
||||
printf("commands[%d].required_opt_args[%d].def.lv_types = %s;\n",
|
||||
i, ro, lv_types_to_flags(cmd->required_opt_args[ro].def.lv_types));
|
||||
|
||||
if (cmd->required_opt_args[ro].def.flags)
|
||||
printf("commands[%d].required_opt_args[%d].def.flags = %s;\n",
|
||||
@@ -2445,9 +2398,9 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].required_pos_args[%d].def.val_bits = %s;\n",
|
||||
i, rp, val_bits_to_str(cmd->required_pos_args[rp].def.val_bits));
|
||||
|
||||
if (cmd->required_pos_args[rp].def.lvt_bits)
|
||||
printf("commands[%d].required_pos_args[%d].def.lvt_bits = %s;\n",
|
||||
i, rp, lvt_bits_to_str(cmd->required_pos_args[rp].def.lvt_bits));
|
||||
if (cmd->required_pos_args[rp].def.lv_types)
|
||||
printf("commands[%d].required_pos_args[%d].def.lv_types = %s;\n",
|
||||
i, rp, lv_types_to_flags(cmd->required_pos_args[rp].def.lv_types));
|
||||
|
||||
if (cmd->required_pos_args[rp].def.flags)
|
||||
printf("commands[%d].required_pos_args[%d].def.flags = %s;\n",
|
||||
@@ -2474,9 +2427,9 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].optional_opt_args[%d].def.val_bits = %s;\n",
|
||||
i, oo, val_bits_to_str(cmd->optional_opt_args[oo].def.val_bits));
|
||||
|
||||
if (cmd->optional_opt_args[oo].def.lvt_bits)
|
||||
printf("commands[%d].optional_opt_args[%d].def.lvt_bits = %s;\n",
|
||||
i, oo, lvt_bits_to_str(cmd->optional_opt_args[oo].def.lvt_bits));
|
||||
if (cmd->optional_opt_args[oo].def.lv_types)
|
||||
printf("commands[%d].optional_opt_args[%d].def.lv_types = %s;\n",
|
||||
i, oo, lv_types_to_flags(cmd->optional_opt_args[oo].def.lv_types));
|
||||
|
||||
if (cmd->optional_opt_args[oo].def.flags)
|
||||
printf("commands[%d].optional_opt_args[%d].def.flags = %s;\n",
|
||||
@@ -2503,9 +2456,9 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].optional_pos_args[%d].def.val_bits = %s;\n",
|
||||
i, op, val_bits_to_str(cmd->optional_pos_args[op].def.val_bits));
|
||||
|
||||
if (cmd->optional_pos_args[op].def.lvt_bits)
|
||||
printf("commands[%d].optional_pos_args[%d].def.lvt_bits = %s;\n",
|
||||
i, op, lvt_bits_to_str(cmd->optional_pos_args[op].def.lvt_bits));
|
||||
if (cmd->optional_pos_args[op].def.lv_types)
|
||||
printf("commands[%d].optional_pos_args[%d].def.lv_types = %s;\n",
|
||||
i, op, lv_types_to_flags(cmd->optional_pos_args[op].def.lv_types));
|
||||
|
||||
if (cmd->optional_pos_args[op].def.flags)
|
||||
printf("commands[%d].optional_pos_args[%d].def.flags = %s;\n",
|
||||
@@ -2521,31 +2474,6 @@ void print_command_struct(int only_usage)
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->rule_count) {
|
||||
for (ru = 0; ru < cmd->rule_count; ru++) {
|
||||
printf("commands[%d].rules[%d].opt = %s;\n", i, ru,
|
||||
cmd->rules[ru].opt ? opt_to_enum_str(cmd->rules[ru].opt) : "0");
|
||||
|
||||
printf("commands[%d].rules[%d].lvt_bits = %s;\n", i, ru,
|
||||
cmd->rules[ru].lvt_bits ? lvt_bits_to_str(cmd->rules[ru].lvt_bits) : "0");
|
||||
|
||||
printf("commands[%d].rules[%d].lvp_bits = %s;\n", i, ru,
|
||||
cmd->rules[ru].lvp_bits ? lvp_bits_to_str(cmd->rules[ru].lvp_bits) : "0");
|
||||
|
||||
printf("commands[%d].rules[%d].rule = %s;\n", i, ru,
|
||||
rule_to_define_str(cmd->rules[ru].rule));
|
||||
|
||||
printf("commands[%d].rules[%d].check_opt = %s;\n", i, ru,
|
||||
cmd->rules[ru].check_opt ? opt_to_enum_str(cmd->rules[ru].check_opt) : "0");
|
||||
|
||||
printf("commands[%d].rules[%d].check_lvt_bits = %s;\n", i, ru,
|
||||
cmd->rules[ru].check_lvt_bits ? lvt_bits_to_str(cmd->rules[ru].check_lvt_bits) : "0");
|
||||
|
||||
printf("commands[%d].rules[%d].check_lvp_bits = %s;\n", i, ru,
|
||||
cmd->rules[ru].check_lvp_bits ? lvp_bits_to_str(cmd->rules[ru].check_lvp_bits) : "0");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
@@ -2772,11 +2700,6 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_rule_line(line_argv[0])) {
|
||||
add_rule(cmd, line_orig);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_id_line(line_argv[0])) {
|
||||
cmd->command_line_id = strdup(line_argv[1]);
|
||||
continue;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
/*
|
||||
* NULL in the last arg can be replaced with actual
|
||||
* calls to the lv_is_prop() function when those
|
||||
* become functions (are #define now), take uniform
|
||||
* args (e.g. some take cmd others don't), and are
|
||||
* exposed in tools.h
|
||||
*
|
||||
* Until then, the lv_is_prop() functions are
|
||||
* called indirectly through _lv_is_prop().
|
||||
*/
|
||||
|
||||
lvp(LVP_NONE, "", NULL) /* enum value 0 means none */
|
||||
lvp(is_locked_LVP, "lv_is_locked", NULL)
|
||||
lvp(is_partial_LVP, "lv_is_partial", NULL)
|
||||
lvp(is_virtual_LVP, "lv_is_virtual", NULL)
|
||||
lvp(is_merging_LVP, "lv_is_merging", NULL)
|
||||
lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL)
|
||||
lvp(is_converting_LVP, "lv_is_converting", NULL)
|
||||
lvp(is_external_origin_LVP, "lv_is_external_origin", NULL)
|
||||
lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL)
|
||||
lvp(is_not_synced_LVP, "lv_is_not_synced", NULL)
|
||||
lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL)
|
||||
lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL)
|
||||
lvp(is_pvmove_LVP, "lv_is_pvmove", NULL)
|
||||
lvp(is_removed_LVP, "lv_is_removed", NULL)
|
||||
lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL)
|
||||
|
||||
/* kinds of sub LV */
|
||||
lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL)
|
||||
lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL)
|
||||
lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL)
|
||||
lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL)
|
||||
lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL)
|
||||
lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL)
|
||||
lvp(is_raid_image_LVP, "lv_is_raid_image", NULL)
|
||||
lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL)
|
||||
|
||||
/*
|
||||
* is_thick_origin should be used instead of is_origin
|
||||
* is_thick_snapshot is generally used as LV_snapshot from lv_types.h
|
||||
*/
|
||||
lvp(is_origin_LVP, "lv_is_origin", NULL)
|
||||
lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL)
|
||||
lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL)
|
||||
lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL)
|
||||
lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL)
|
||||
|
||||
lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL)
|
||||
lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL)
|
||||
lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
|
||||
lvp(is_visible_LVP, "lv_is_visible", NULL)
|
||||
lvp(is_historical_LVP, "lv_is_historical", NULL)
|
||||
lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
|
||||
lvp(LVP_COUNT, "", NULL)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
|
||||
/*
|
||||
* LV types used in command definitions. The type strings are used
|
||||
* as LV suffixes, e.g. LV_type or LV_type1_type2.
|
||||
*
|
||||
* The final NULL arg can be replaced with lv_is_type() functions
|
||||
* if the current lv_is_type #defines become functions and are
|
||||
* moved to tools.h
|
||||
*
|
||||
* Until then, the lv_is_type() functions are called indirectly
|
||||
* through _lv_is_type().
|
||||
*/
|
||||
|
||||
lvt(LVT_NONE, "", NULL)
|
||||
lvt(linear_LVT, "linear", NULL)
|
||||
lvt(striped_LVT, "striped", NULL)
|
||||
lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */
|
||||
lvt(thin_LVT, "thin", NULL)
|
||||
lvt(thinpool_LVT, "thinpool", NULL)
|
||||
lvt(cache_LVT, "cache", NULL)
|
||||
lvt(cachepool_LVT, "cachepool", NULL)
|
||||
lvt(mirror_LVT, "mirror", NULL)
|
||||
lvt(raid_LVT, "raid", NULL)
|
||||
lvt(raid0_LVT, "raid0", NULL)
|
||||
lvt(raid1_LVT, "raid1", NULL)
|
||||
lvt(raid4_LVT, "raid4", NULL)
|
||||
lvt(raid5_LVT, "raid5", NULL)
|
||||
lvt(raid6_LVT, "raid6", NULL)
|
||||
lvt(raid10_LVT, "raid10", NULL)
|
||||
lvt(LVT_COUNT, "", NULL)
|
||||
|
||||
283
tools/lvchange.c
283
tools/lvchange.c
@@ -1436,3 +1436,286 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
update ? READ_FOR_UPDATE : 0, NULL,
|
||||
&_lvchange_single);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check if the status of the LV allows running lvchange.
|
||||
*
|
||||
* FIXME: check for invalid VG/LV properties in a way that is not prone
|
||||
* to missing some. Currently, there are some checks here, some in the
|
||||
* functions above, some in process_each, and some may be missing.
|
||||
*/
|
||||
static int _lvchange_status_is_valid(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
if (!(lv->vg->status & LVM_WRITE)) {
|
||||
log_error("Operation not permitted on LV %s: writable VG required.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_pvmove(lv)) {
|
||||
log_error("Operation not permitted on LV %s: used for pvmove.",
|
||||
display_lvname(lv));
|
||||
if (arg_is_set(cmd, activate_ARG))
|
||||
log_error("Use 'pvmove --abort' to abandon a pvmove");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_log(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is mirror log.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_image(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is mirror image.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv) && !lv_is_thin_volume(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is under snapshot.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_properties_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
int doit = 0, docmds = 0;
|
||||
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
|
||||
log_error("Operation not permitted on LV %s: persistent device numbers are not supported with pools.",
|
||||
display_lvname(lv));
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a persistent lv lock already exists from activation
|
||||
* (with the needed mode or higher), this will be a no-op.
|
||||
* Otherwise, the lv lock will be taken as non-persistent
|
||||
* and released when this command exits.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < cmd->command->ro_count; i++) {
|
||||
opt_enum = cmd->command->required_opt_args[i].opt;
|
||||
|
||||
if (!arg_is_set(cmd, opt_enum))
|
||||
continue;
|
||||
|
||||
if (!archive(lv->vg))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
docmds++;
|
||||
|
||||
switch (opt_enum) {
|
||||
case permission_ARG:
|
||||
doit += _lvchange_permission(cmd, lv);
|
||||
break;
|
||||
|
||||
case alloc_ARG:
|
||||
case contiguous_ARG:
|
||||
doit += _lvchange_alloc(cmd, lv);
|
||||
break;
|
||||
|
||||
case errorwhenfull_ARG:
|
||||
doit += _lvchange_errorwhenfull(cmd, lv);
|
||||
break;
|
||||
|
||||
case readahead_ARG:
|
||||
doit += _lvchange_readahead(cmd, lv);
|
||||
break;
|
||||
|
||||
case persistent_ARG:
|
||||
doit += _lvchange_persistent(cmd, lv);
|
||||
break;
|
||||
|
||||
case discards_ARG:
|
||||
case zero_ARG:
|
||||
doit += _lvchange_pool_update(cmd, lv);
|
||||
break;
|
||||
|
||||
case addtag_ARG:
|
||||
case deltag_ARG:
|
||||
doit += _lvchange_tag(cmd, lv, opt_enum);
|
||||
break;
|
||||
|
||||
case writemostly_ARG:
|
||||
case writebehind_ARG:
|
||||
doit += _lvchange_writemostly(lv);
|
||||
break;
|
||||
|
||||
case minrecoveryrate_ARG:
|
||||
case maxrecoveryrate_ARG:
|
||||
doit += _lvchange_recovery_rate(lv);
|
||||
break;
|
||||
|
||||
case profile_ARG:
|
||||
case metadataprofile_ARG:
|
||||
case detachprofile_ARG:
|
||||
doit += _lvchange_profile(lv);
|
||||
break;
|
||||
|
||||
case setactivationskip_ARG:
|
||||
doit += _lvchange_activation_skip(lv);
|
||||
break;
|
||||
|
||||
case cachemode_ARG:
|
||||
case cachepolicy_ARG:
|
||||
case cachesettings_ARG:
|
||||
doit += _lvchange_cache(cmd, lv);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
||||
arg_long_option_name(i));
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
|
||||
|
||||
if (doit != docmds)
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
int ret;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle, _lvchange_properties_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvchange_activate_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct logical_volume *origin;
|
||||
char snaps_msg[128];
|
||||
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
/* FIXME: untangle the proper logic for cow / sparse / virtual origin */
|
||||
|
||||
/* If LV is sparse, activate origin instead */
|
||||
if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
|
||||
lv = origin;
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
origin = origin_from_cow(lv);
|
||||
if (origin->origin_count < 2)
|
||||
snaps_msg[0] = '\0';
|
||||
else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
|
||||
" and %u other snapshot(s)",
|
||||
origin->origin_count - 1) < 0) {
|
||||
log_error("Failed to prepare message.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!arg_is_set(cmd, yes_ARG) &&
|
||||
(yes_no_prompt("Change of snapshot %s will also change its "
|
||||
"origin %s%s. Proceed? [y/n]: ",
|
||||
display_lvname(lv), display_lvname(origin),
|
||||
snaps_msg) == 'n')) {
|
||||
log_error("Logical volume %s not changed.", display_lvname(lv));
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If --sysinit -aay is used and at the same time lvmetad is used,
|
||||
* we want to rely on autoactivation to take place. Also, we
|
||||
* need to take special care here as lvmetad service does
|
||||
* not neet to be running at this moment yet - it could be
|
||||
* just too early during system initialization time.
|
||||
*/
|
||||
if (arg_is_set(cmd, sysinit_ARG) && (arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY)) {
|
||||
if (lvmetad_used()) {
|
||||
log_warn("WARNING: lvmetad is active, skipping direct activation during sysinit.");
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_lvchange_activate(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
|
||||
/*
|
||||
* Include foreign VGs that contain active LVs.
|
||||
* That shouldn't happen in general, but if it does by some
|
||||
* mistake, then we want to allow those LVs to be deactivated.
|
||||
*/
|
||||
cmd->include_active_foreign_vgs = 1;
|
||||
|
||||
/* Allow deactivating if locks fail. */
|
||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_activate_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvchange_refresh_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
|
||||
|
||||
if (!_lv_refresh(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
int ret;
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -79,25 +79,6 @@ struct command_name command_names[MAX_COMMAND_NAMES] = {
|
||||
#undef xx
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of LV properties
|
||||
*/
|
||||
static struct lv_props _lv_props[LVP_COUNT + 1] = {
|
||||
#define lvp(a, b, c) {a, b, c},
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of LV types
|
||||
*/
|
||||
static struct lv_types _lv_types[LVT_COUNT + 1] = {
|
||||
#define lvt(a, b, c) {a, b, c},
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Table of valid command lines
|
||||
*/
|
||||
@@ -1098,20 +1079,6 @@ void lvm_register_commands(void)
|
||||
_set_valid_args_for_command_name(i);
|
||||
}
|
||||
|
||||
struct lv_props *get_lv_prop(int lvp_enum)
|
||||
{
|
||||
if (!lvp_enum)
|
||||
return NULL;
|
||||
return &_lv_props[lvp_enum];
|
||||
}
|
||||
|
||||
struct lv_types *get_lv_type(int lvt_enum)
|
||||
{
|
||||
if (!lvt_enum)
|
||||
return NULL;
|
||||
return &_lv_types[lvt_enum];
|
||||
}
|
||||
|
||||
/*
|
||||
* Also see merge_synonym(). The command definitions
|
||||
* are written using just one variation of the option
|
||||
@@ -1437,7 +1404,7 @@ static void _print_description(int ci)
|
||||
* set to match.
|
||||
*
|
||||
* required_pos_args[0].types & select_VAL means
|
||||
* argv[] in that pos can be NULL if arg_is_set(select_ARG)
|
||||
* 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 */
|
||||
@@ -1457,7 +1424,6 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
||||
int i, j;
|
||||
int opt_enum, opt_i;
|
||||
int accepted, count;
|
||||
int check_is_set;
|
||||
|
||||
name = last_path_component(path);
|
||||
|
||||
@@ -1678,52 +1644,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Check any rules related to option combinations.
|
||||
* Other rules are checked after VG is read.
|
||||
*/
|
||||
|
||||
for (i = 0; i < commands[best_i].rule_count; i++) {
|
||||
struct cmd_rule *rule;
|
||||
rule = &commands[best_i].rules[i];
|
||||
|
||||
/*
|
||||
* The rule wants to check an option (check_opt), and the
|
||||
* qualification for applying the rule can't include knowing a
|
||||
* specific LV type (lvt_bits) or LV property (lvp_bits).
|
||||
*/
|
||||
|
||||
if (rule->check_opt && !rule->lvt_bits && !rule->lvp_bits) {
|
||||
/*
|
||||
* When no opt is specified for applying the rule, then
|
||||
* the rule is always applied, otherwise the rule is
|
||||
* applied when the specific option is set.
|
||||
*/
|
||||
if (rule->opt && !arg_is_set(cmd, rule->opt))
|
||||
continue;
|
||||
|
||||
check_is_set = arg_is_set(cmd, rule->check_opt);
|
||||
|
||||
if (check_is_set && (rule->rule == RULE_INVALID)) {
|
||||
log_error("Invalid option combination for command (%s %d): %s and %s",
|
||||
commands[best_i].command_line_id, best_i,
|
||||
arg_long_option_name(rule->opt),
|
||||
arg_long_option_name(rule->check_opt));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!check_is_set && (rule->rule == RULE_REQUIRE)) {
|
||||
log_error("Invalid option usage for command (%s %d): %s requires %s",
|
||||
commands[best_i].command_line_id, best_i,
|
||||
arg_long_option_name(rule->opt),
|
||||
arg_long_option_name(rule->check_opt));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
|
||||
|
||||
return &commands[best_i];
|
||||
@@ -1782,7 +1703,7 @@ static int _usage(const char *name, int help_count)
|
||||
log_print(" be omitted if the --select option is used.");
|
||||
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 numeric suffix.");
|
||||
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),");
|
||||
@@ -2621,12 +2542,6 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
|
||||
return EINVALID_CMD_LINE;
|
||||
|
||||
/*
|
||||
* Remaining position args after command name and --options are removed.
|
||||
*/
|
||||
cmd->position_argc = argc;
|
||||
cmd->position_argv = argv;
|
||||
|
||||
set_cmd_name(cmd->name);
|
||||
|
||||
if (arg_is_set(cmd, backgroundfork_ARG)) {
|
||||
|
||||
548
tools/toollib.c
548
tools/toollib.c
@@ -2326,464 +2326,6 @@ static struct lv_segment _historical_lv_segment = {
|
||||
.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
|
||||
};
|
||||
|
||||
static void lvp_bits_to_str(uint64_t bits, char *buf, int len)
|
||||
{
|
||||
struct lv_props *prop;
|
||||
int lvp_enum;
|
||||
int pos = 0;
|
||||
int ret;
|
||||
|
||||
for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||
if (!(prop = get_lv_prop(lvp_enum)))
|
||||
continue;
|
||||
|
||||
if (lvp_bit_is_set(bits, lvp_enum)) {
|
||||
ret = snprintf(buf + pos, len - pos, "%s ", prop->name);
|
||||
if (ret >= len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
static void lvt_bits_to_str(uint64_t bits, char *buf, int len)
|
||||
{
|
||||
struct lv_types *type;
|
||||
int lvt_enum;
|
||||
int pos = 0;
|
||||
int ret;
|
||||
|
||||
for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (!(type = get_lv_type(lvt_enum)))
|
||||
continue;
|
||||
|
||||
if (lvt_bit_is_set(bits, lvt_enum)) {
|
||||
ret = snprintf(buf + pos, len - pos, "%s ", type->name);
|
||||
if (ret >= len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the lv_prop function pointer used for lv_is_foo() #defines.
|
||||
* Alternatively, lv_is_foo() could all be turned into functions.
|
||||
*/
|
||||
|
||||
static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum)
|
||||
{
|
||||
switch (lvp_enum) {
|
||||
case is_locked_LVP:
|
||||
return lv_is_locked(lv);
|
||||
case is_partial_LVP:
|
||||
return lv_is_partial(lv);
|
||||
case is_virtual_LVP:
|
||||
return lv_is_virtual(lv);
|
||||
case is_merging_LVP:
|
||||
return lv_is_merging(lv);
|
||||
case is_merging_origin_LVP:
|
||||
return lv_is_merging_origin(lv);
|
||||
case is_converting_LVP:
|
||||
return lv_is_converting(lv);
|
||||
case is_external_origin_LVP:
|
||||
return lv_is_external_origin(lv);
|
||||
case is_virtual_origin_LVP:
|
||||
return lv_is_virtual_origin(lv);
|
||||
case is_not_synced_LVP:
|
||||
return lv_is_not_synced(lv);
|
||||
case is_pending_delete_LVP:
|
||||
return lv_is_pending_delete(lv);
|
||||
case is_error_when_full_LVP:
|
||||
return lv_is_error_when_full(lv);
|
||||
case is_pvmove_LVP:
|
||||
return lv_is_pvmove(lv);
|
||||
case is_removed_LVP:
|
||||
return lv_is_removed(lv);
|
||||
case is_vg_writable_LVP:
|
||||
return (lv->vg->status & LVM_WRITE) ? 1 : 0;
|
||||
case is_thinpool_data_LVP:
|
||||
return lv_is_thin_pool_data(lv);
|
||||
case is_thinpool_metadata_LVP:
|
||||
return lv_is_thin_pool_metadata(lv);
|
||||
case is_cachepool_data_LVP:
|
||||
return lv_is_cache_pool_data(lv);
|
||||
case is_cachepool_metadata_LVP:
|
||||
return lv_is_cache_pool_metadata(lv);
|
||||
case is_mirror_image_LVP:
|
||||
return lv_is_mirror_image(lv);
|
||||
case is_mirror_log_LVP:
|
||||
return lv_is_mirror_log(lv);
|
||||
case is_raid_image_LVP:
|
||||
return lv_is_raid_image(lv);
|
||||
case is_raid_metadata_LVP:
|
||||
return lv_is_raid_metadata(lv);
|
||||
case is_origin_LVP: /* use lv_is_thick_origin */
|
||||
return lv_is_origin(lv);
|
||||
case is_thick_origin_LVP:
|
||||
return lv_is_thick_origin(lv);
|
||||
case is_thick_snapshot_LVP:
|
||||
return lv_is_thick_snapshot(lv);
|
||||
case is_thin_origin_LVP:
|
||||
return lv_is_thin_origin(lv, NULL);
|
||||
case is_thin_snapshot_LVP:
|
||||
return lv_is_thin_snapshot(lv);
|
||||
case is_cache_origin_LVP:
|
||||
return lv_is_cache_origin(lv);
|
||||
case is_merging_cow_LVP:
|
||||
return lv_is_merging_cow(lv);
|
||||
case is_cow_covering_origin_LVP:
|
||||
return lv_is_cow_covering_origin(lv);
|
||||
case is_visible_LVP:
|
||||
return lv_is_visible(lv);
|
||||
case is_historical_LVP:
|
||||
return lv_is_historical(lv);
|
||||
case is_raid_with_tracking_LVP:
|
||||
return lv_is_raid_with_tracking(lv);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an LV matches a given LV type enum.
|
||||
*/
|
||||
|
||||
static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
switch (lvt_enum) {
|
||||
case striped_LVT:
|
||||
return seg_is_striped(seg);
|
||||
case linear_LVT:
|
||||
return seg_is_linear(seg);
|
||||
case snapshot_LVT:
|
||||
return lv_is_cow(lv);
|
||||
case thin_LVT:
|
||||
return lv_is_thin_volume(lv);
|
||||
case thinpool_LVT:
|
||||
return lv_is_thin_pool(lv);
|
||||
case cache_LVT:
|
||||
return lv_is_cache(lv);
|
||||
case cachepool_LVT:
|
||||
return lv_is_cache_pool(lv);
|
||||
case mirror_LVT:
|
||||
return lv_is_mirror(lv);
|
||||
case raid_LVT:
|
||||
return lv_is_raid(lv);
|
||||
case raid0_LVT:
|
||||
return seg_is_raid0(seg);
|
||||
case raid1_LVT:
|
||||
return seg_is_raid1(seg);
|
||||
case raid4_LVT:
|
||||
return seg_is_raid4(seg);
|
||||
#if 0
|
||||
case raid5_LVT:
|
||||
return seg_is_raid5(seg);
|
||||
case raid6_LVT:
|
||||
return seg_is_raid6(seg);
|
||||
#endif
|
||||
case raid10_LVT:
|
||||
return seg_is_raid10(seg);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_lvt_enum(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (seg_is_striped(seg))
|
||||
return striped_LVT;
|
||||
if (seg_is_linear(seg))
|
||||
return linear_LVT;
|
||||
if (lv_is_cow(lv))
|
||||
return snapshot_LVT;
|
||||
if (lv_is_thin_volume(lv))
|
||||
return thin_LVT;
|
||||
if (lv_is_thin_pool(lv))
|
||||
return thinpool_LVT;
|
||||
if (lv_is_cache(lv))
|
||||
return cache_LVT;
|
||||
if (lv_is_cache_pool(lv))
|
||||
return cachepool_LVT;
|
||||
if (lv_is_mirror(lv))
|
||||
return mirror_LVT;
|
||||
if (lv_is_raid(lv))
|
||||
return raid_LVT;
|
||||
if (seg_is_raid0(seg))
|
||||
return raid0_LVT;
|
||||
if (seg_is_raid1(seg))
|
||||
return raid1_LVT;
|
||||
if (seg_is_raid4(seg))
|
||||
return raid4_LVT;
|
||||
#if 0
|
||||
if (seg_is_raid5(seg))
|
||||
return raid5_LVT;
|
||||
if (seg_is_raid6(seg))
|
||||
return raid6_LVT;
|
||||
#endif
|
||||
if (seg_is_raid10(seg))
|
||||
return raid10_LVT;
|
||||
|
||||
log_error(INTERNAL_ERROR "unknown lv type for %s", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call lv_is_<type> for each <type>_LVT bit set in lvt_bits.
|
||||
* If lv matches one of the specified lv types, then return 1.
|
||||
*/
|
||||
|
||||
static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits,
|
||||
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||
{
|
||||
struct lv_types *type;
|
||||
int lvt_enum;
|
||||
int found_a_match = 0;
|
||||
int match;
|
||||
|
||||
if (match_bits)
|
||||
*match_bits = 0;
|
||||
if (unmatch_bits)
|
||||
*unmatch_bits = 0;
|
||||
|
||||
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (!lvt_bit_is_set(lvt_bits, lvt_enum))
|
||||
continue;
|
||||
|
||||
if (!(type = get_lv_type(lvt_enum)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All types are currently handled by _lv_is_type()
|
||||
* because lv_is_type() are #defines and not exposed
|
||||
* in tools.h
|
||||
*/
|
||||
|
||||
if (!type->fn)
|
||||
match = _lv_is_type(cmd, lv, lvt_enum);
|
||||
else
|
||||
match = type->fn(cmd, lv);
|
||||
|
||||
if (match)
|
||||
found_a_match = 1;
|
||||
|
||||
if (match_bits && match)
|
||||
*match_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
|
||||
if (unmatch_bits && !match)
|
||||
*unmatch_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
}
|
||||
|
||||
return found_a_match;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits.
|
||||
* If lv matches all of the specified lv properties, then return 1.
|
||||
*/
|
||||
|
||||
static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits,
|
||||
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||
{
|
||||
struct lv_props *prop;
|
||||
int lvp_enum;
|
||||
int found_a_mismatch = 0;
|
||||
int match;
|
||||
|
||||
if (match_bits)
|
||||
*match_bits = 0;
|
||||
if (unmatch_bits)
|
||||
*unmatch_bits = 0;
|
||||
|
||||
for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||
if (!lvp_bit_is_set(lvp_bits, lvp_enum))
|
||||
continue;
|
||||
|
||||
if (!(prop = get_lv_prop(lvp_enum)))
|
||||
continue;
|
||||
|
||||
if (!prop->fn)
|
||||
match = _lv_is_prop(cmd, lv, lvp_enum);
|
||||
else
|
||||
match = prop->fn(cmd, lv);
|
||||
|
||||
if (!match)
|
||||
found_a_mismatch = 1;
|
||||
|
||||
if (match_bits && match)
|
||||
*match_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
|
||||
if (unmatch_bits && !match)
|
||||
*unmatch_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
}
|
||||
|
||||
return !found_a_mismatch;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the command definition specifies one required positional
|
||||
* LV (possibly repeatable), and specifies accepted LV types,
|
||||
* then verify that the LV being processed matches one of those
|
||||
* types.
|
||||
*
|
||||
* process_each_lv() can only be used for commands that have
|
||||
* one positional LV arg (optionally repeating, where each is
|
||||
* processed independently.) It cannot work for commands that
|
||||
* have different required LVs in designated positions, like
|
||||
* 'lvrename LV1 LV2', where each LV is not processed
|
||||
* independently. That means that this LV type check only
|
||||
* needs to check the lv_type of the first positional arg.
|
||||
*/
|
||||
|
||||
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if ((cmd->command->rp_count == 1) &&
|
||||
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
||||
cmd->command->required_pos_args[0].def.lvt_bits) {
|
||||
ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[0].def.lvt_bits, NULL, NULL);
|
||||
if (!ret) {
|
||||
int lvt_enum = _get_lvt_enum(lv);
|
||||
struct lv_types *type = get_lv_type(lvt_enum);
|
||||
log_warn("Operation on LV %s which has invalid type %s.",
|
||||
display_lvname(lv), type ? type->name : "unknown");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if LV passes each rule specified in command definition. */
|
||||
|
||||
static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
char buf[64];
|
||||
struct cmd_rule *rule;
|
||||
struct lv_types *lvtype = NULL;
|
||||
uint64_t lv_props_match_bits, lv_props_unmatch_bits;
|
||||
uint64_t lv_types_match_bits, lv_types_unmatch_bits;
|
||||
int lvt_enum;
|
||||
int opt_is_set;
|
||||
int ret = 1;
|
||||
int i;
|
||||
|
||||
lvt_enum = _get_lvt_enum(lv);
|
||||
if (lvt_enum)
|
||||
lvtype = get_lv_type(lvt_enum);
|
||||
|
||||
|
||||
for (i = 0; i < cmd->command->rule_count; i++) {
|
||||
rule = &cmd->command->rules[i];
|
||||
|
||||
/*
|
||||
* For the rule to apply, any option, LV type or LV property
|
||||
* that is specified before the not|and rule needs to match the
|
||||
* command/LV. If multiple LV types are specifed, one needs to
|
||||
* match for the rule to apply. If multiple LV properties are
|
||||
* specified, all need to match for the rule to apply.
|
||||
*
|
||||
* If all qualifications are zero (!opt && !lvt_bits && !lvp_bits),
|
||||
* then there are no qualifications and the rule always applies.
|
||||
*/
|
||||
|
||||
if (rule->opt && !arg_is_set(cmd, rule->opt))
|
||||
continue;
|
||||
|
||||
/* If LV matches one type in lvt_bits, this returns 1. */
|
||||
if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL))
|
||||
continue;
|
||||
|
||||
/* If LV matches all properties in lvp_bits, this returns 1. */
|
||||
if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check the option, LV types, LV properties specified after
|
||||
* the not|and rule.
|
||||
*/
|
||||
|
||||
if (rule->check_opt)
|
||||
opt_is_set = arg_is_set(cmd, rule->check_opt);
|
||||
|
||||
if (rule->check_lvt_bits)
|
||||
_lv_types_match(cmd, lv, rule->check_lvt_bits, &lv_types_match_bits, &lv_types_unmatch_bits);
|
||||
|
||||
if (rule->check_lvp_bits)
|
||||
_lv_props_match(cmd, lv, rule->check_lvp_bits, &lv_props_match_bits, &lv_props_unmatch_bits);
|
||||
|
||||
/*
|
||||
* Evaluate if the check results pass based on the rule.
|
||||
* The options are checked again here because the previous
|
||||
* option validation (during command matching) does not cover
|
||||
* cases where the option is combined with qualifying LV types
|
||||
* or properties.
|
||||
*/
|
||||
|
||||
if (rule->check_opt && (rule->rule == RULE_INVALID) && opt_is_set) {
|
||||
log_warn("Command option %s invalid with option %s",
|
||||
arg_long_option_name(rule->opt), arg_long_option_name(rule->check_opt));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (rule->check_opt && (rule->rule == RULE_REQUIRE) && !opt_is_set) {
|
||||
log_warn("Command option %s requires option %s",
|
||||
arg_long_option_name(rule->opt), arg_long_option_name(rule->check_opt));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV matches any of the invalid LV types. */
|
||||
|
||||
if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) {
|
||||
log_warn("Command on LV %s with invalid type: %s",
|
||||
display_lvname(lv), lvtype ? lvtype->name : "unknown");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV does not match any of the required LV types. */
|
||||
|
||||
if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s with type %s does not match required type: %s",
|
||||
display_lvname(lv), lvtype ? lvtype->name : "unknown", buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV matches any of the invalid LV properties. */
|
||||
|
||||
if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s with invalid properties: %s",
|
||||
display_lvname(lv), buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV does not match any of the required LV properties. */
|
||||
|
||||
if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s requires properties: %s",
|
||||
display_lvname(lv), buf);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_list *arg_lvnames, const struct dm_list *tags_in,
|
||||
int stop_on_error,
|
||||
@@ -2808,6 +2350,9 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_list found_arg_lvnames;
|
||||
struct glv_list *glvl, *tglvl;
|
||||
int do_report_ret_code = 1;
|
||||
uint32_t lv_types;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
|
||||
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
|
||||
|
||||
@@ -2959,42 +2504,65 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The command definition may include restrictions on the
|
||||
* types and properties of LVs that can be processed.
|
||||
* If the command definition specifies one required positional
|
||||
* LV (possibly repeatable), and specifies accepted LV types,
|
||||
* then verify that the LV being processed matches one of those
|
||||
* types.
|
||||
*
|
||||
* process_each_lv() can only be used for commands that have
|
||||
* one positional LV arg (optionally repeating, where each is
|
||||
* processed independently.) It cannot work for commands that
|
||||
* have different required LVs in designated positions, like
|
||||
* 'lvrename LV1 LV2', where each LV is not processed
|
||||
* independently. That means that this LV type check only
|
||||
* needs to check the lv_type of the first positional arg.
|
||||
*
|
||||
* There is one command that violates this rule by stealing
|
||||
* the first positional LV arg before calling process_each_lv:
|
||||
* lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
||||
* This code cannot validate that case. process_each_lv() sees
|
||||
* a single LV name arg, but it's in pos 2. Could we work around
|
||||
* this by looking at the final positional arg rather than always
|
||||
* looking at pos 1?
|
||||
*
|
||||
* This only validates types for required LV positional args
|
||||
* (currently there are no command specifications that include
|
||||
* specific LV types in optional positional args.)
|
||||
*/
|
||||
|
||||
if (!_check_lv_types(cmd, lvl->lv)) {
|
||||
/* FIXME: include this result in report log? */
|
||||
/* FIXME: avoid duplicating message for each level */
|
||||
if ((cmd->command->rp_count == 1) &&
|
||||
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
||||
cmd->command->required_pos_args[0].def.lv_types) {
|
||||
|
||||
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
lv_types = cmd->command->required_pos_args[0].def.lv_types;
|
||||
lv = lvl->lv;
|
||||
seg = first_seg(lv);
|
||||
|
||||
if ((lv_is_cow(lv) && !(lv_types & ARG_DEF_LV_SNAPSHOT)) ||
|
||||
(lv_is_thin_volume(lv) && !(lv_types & ARG_DEF_LV_THIN)) ||
|
||||
(lv_is_thin_pool(lv) && !(lv_types & ARG_DEF_LV_THINPOOL)) ||
|
||||
(lv_is_cache(lv) && !(lv_types & ARG_DEF_LV_CACHE)) ||
|
||||
(lv_is_cache_pool(lv) && !(lv_types & ARG_DEF_LV_CACHEPOOL)) ||
|
||||
(lv_is_mirror(lv) && !(lv_types & ARG_DEF_LV_MIRROR)) ||
|
||||
(lv_is_raid(lv) && !(lv_types & (ARG_DEF_LV_RAID | ARG_DEF_LV_RAID0 | ARG_DEF_LV_RAID1 | ARG_DEF_LV_RAID4 | ARG_DEF_LV_RAID5 | ARG_DEF_LV_RAID6 | ARG_DEF_LV_RAID10))) ||
|
||||
(segtype_is_striped(seg->segtype) && !(lv_types & ARG_DEF_LV_STRIPED)) ||
|
||||
(segtype_is_linear(seg->segtype) && !(lv_types & ARG_DEF_LV_LINEAR))) {
|
||||
/*
|
||||
* If a named LV arg cannot be processed it's an error, otherwise
|
||||
* the LV is skipped and doesn't cause the command to fail.
|
||||
*/
|
||||
if (str_list_match_item(&found_arg_lvnames, lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s with type %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lv), seg->segtype->name);
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s with type %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lv), seg->segtype->name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_check_lv_rules(cmd, lvl->lv)) {
|
||||
/* FIXME: include this result in report log? */
|
||||
/* FIXME: avoid duplicating message for each level */
|
||||
|
||||
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
|
||||
/* define the enums for the values accepted by command line --options, foo_VAL */
|
||||
/* define the enums for the values accepted by command line --options */
|
||||
enum {
|
||||
#define val(a, b, c, d) a ,
|
||||
#include "vals.h"
|
||||
#undef val
|
||||
};
|
||||
|
||||
/* define the enums for the command line --options, foo_ARG */
|
||||
/* define the enums for the command line --options */
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#include "args.h"
|
||||
@@ -69,20 +69,6 @@ enum {
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
/* define enums for LV properties, foo_LVP */
|
||||
enum {
|
||||
#define lvp(a, b, c) a ,
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/* define enums for LV types, foo_LVT */
|
||||
enum {
|
||||
#define lvt(a, b, c) a ,
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
||||
@@ -125,21 +111,6 @@ struct val_props {
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
/* a global table of possible LV properties */
|
||||
struct lv_props {
|
||||
int lvp_enum; /* is_foo_LVP from lv_props.h */
|
||||
const char *name; /* "lv_is_foo" used in command-lines.in */
|
||||
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||
};
|
||||
|
||||
/* a global table of possible LV types */
|
||||
/* (as exposed externally in command line interface, not exactly as internal segtype is used) */
|
||||
struct lv_types {
|
||||
int lvt_enum; /* is_foo_LVT from lv_types.h */
|
||||
const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */
|
||||
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||
};
|
||||
|
||||
#define CACHE_VGMETADATA 0x00000001
|
||||
#define PERMITTED_READ_ONLY 0x00000002
|
||||
/* Process all VGs if none specified on the command line. */
|
||||
@@ -238,7 +209,4 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
struct lv_props *get_lv_prop(int lvp_enum);
|
||||
struct lv_types *get_lv_type(int lvt_enum);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user