mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
config: use config checks and add support for creating trees from config definition (config_def_create_tree fn)
Configuration checking is initiated during config load/processing (_process_config fn) which is part of the command context creation/refresh. This patch also defines 5 types of trees that could be created from the configuration definition (config_settings.h), the cfg_def_tree_t: - CFG_DEF_TREE_CURRENT that denotes a tree of all the configuration nodes that are explicitly defined in lvm.conf/--config - CFG_DEF_TREE_MISSING that denotes a tree of all missing configuration nodes for which default valus are used since they're not explicitly used in lvm.conf/--config - CFG_DEF_TREE_DEFAULT that denotes a tree of all possible configuration nodes with default values assigned, no matter what the actual lvm.conf/--config is - CFG_DEF_TREE_NEW that denotes a tree of all new configuration nodes that appeared in given version - CFG_DEF_TREE_COMPLETE that denotes a tree of the whole configuration tree that is used in LVM2 (a combination of CFG_DEF_TREE_CURRENT + CFG_DEF_TREE_MISSING). This is not implemented yet, it will be added later... The function that creates the definition tree of given type: struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec); Where the "spec" specifies the tree type to be created: struct config_def_tree_spec { cfg_def_tree_t type; /* tree type */ uint16_t version; /* tree at this LVM2 version */ int ignoreadvanced; /* do not include advanced configs */ int ignoreunsupported; /* do not include unsupported configs */ }; This tree can be passed to already existing functions that write the tree on output (like we already do with cmd->cft). There is a new lvm.conf section called "config" with two new options: - config/checks which enables/disables checking (enabled by default) - config/abort_on_errors which enables/disables aborts on any type of mismatch found in the config (disabled by default)
This commit is contained in:
parent
e38aaddb5e
commit
245b85692e
@ -10,6 +10,20 @@
|
|||||||
# N.B. Take care that each setting only appears once if uncommenting
|
# N.B. Take care that each setting only appears once if uncommenting
|
||||||
# example settings in this file.
|
# example settings in this file.
|
||||||
|
|
||||||
|
# This section allows you to set the way the configuration settings are handled.
|
||||||
|
config {
|
||||||
|
|
||||||
|
# If enabled, any LVM2 configuration mismatch is reported.
|
||||||
|
# This implies checking that the configuration key is understood
|
||||||
|
# by LVM2 and that the value of the key is of a proper type.
|
||||||
|
# If disabled, any configuration mismatch is ignored and default
|
||||||
|
# value is used instead without any warning (a message about the
|
||||||
|
# configuration key not being found is issued in verbose mode only).
|
||||||
|
checks = 1
|
||||||
|
|
||||||
|
# If enabled, any configuration mismatch aborts the LVM2 process.
|
||||||
|
abort_on_errors = 0
|
||||||
|
}
|
||||||
|
|
||||||
# This section allows you to configure which block devices should
|
# This section allows you to configure which block devices should
|
||||||
# be used by the LVM system.
|
# be used by the LVM system.
|
||||||
@ -359,7 +373,6 @@ shell {
|
|||||||
|
|
||||||
# Miscellaneous global LVM2 settings
|
# Miscellaneous global LVM2 settings
|
||||||
global {
|
global {
|
||||||
|
|
||||||
# The file creation mask for any files and directories created.
|
# The file creation mask for any files and directories created.
|
||||||
# Interpreted as octal if the first digit is zero.
|
# Interpreted as octal if the first digit is zero.
|
||||||
umask = 077
|
umask = 077
|
||||||
|
@ -290,6 +290,11 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
const char *lvmetad_socket;
|
const char *lvmetad_socket;
|
||||||
int udev_disabled = 0;
|
int udev_disabled = 0;
|
||||||
|
|
||||||
|
if (!config_def_check(cmd, 0, 0, 0) && find_config_tree_bool(cmd, config_abort_on_errors_CFG)) {
|
||||||
|
log_error("LVM configuration invalid.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* umask */
|
/* umask */
|
||||||
cmd->default_settings.umask = find_config_tree_int(cmd, global_umask_CFG);
|
cmd->default_settings.umask = find_config_tree_int(cmd, global_umask_CFG);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
struct config_file {
|
struct config_file {
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
@ -851,3 +852,237 @@ int config_write(struct dm_config_tree *cft, const char *file,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
||||||
|
cfg_def_item_t *def)
|
||||||
|
{
|
||||||
|
char *enc_value, *token, *p, *r;
|
||||||
|
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
|
||||||
|
|
||||||
|
if (!def->default_value.v_CFG_TYPE_STRING) {
|
||||||
|
if (!(array = dm_config_create_value(cft))) {
|
||||||
|
log_error("Failed to create default empty array for %s.", def->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
array->type = DM_CFG_EMPTY_ARRAY;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
|
||||||
|
log_error("_get_def_array_values: dm_strdup failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Proper value always starts with '#'. */
|
||||||
|
if (token[0] != '#')
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
while (token) {
|
||||||
|
/* Move to type identifier. Error on no char. */
|
||||||
|
token++;
|
||||||
|
if (!token[0])
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
/* Move to the actual value and decode any "##" into "#". */
|
||||||
|
p = token + 1;
|
||||||
|
while ((p = strchr(p, '#')) && p[1] == '#') {
|
||||||
|
memmove(p, p + 1, strlen(p));
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
/* Separate the value out of the whole string. */
|
||||||
|
if (p)
|
||||||
|
p[0] = '\0';
|
||||||
|
|
||||||
|
if (!(v = dm_config_create_value(cft))) {
|
||||||
|
log_error("Failed to create default config array value for %s.", def->name);
|
||||||
|
dm_free(enc_value);
|
||||||
|
}
|
||||||
|
if (oldv)
|
||||||
|
oldv->next = v;
|
||||||
|
if (!array)
|
||||||
|
array = v;
|
||||||
|
|
||||||
|
switch (toupper(token[0])) {
|
||||||
|
case 'I':
|
||||||
|
case 'B':
|
||||||
|
v->v.i = strtoll(token + 1, &r, 10);
|
||||||
|
if (*r)
|
||||||
|
goto bad;
|
||||||
|
v->type = DM_CFG_INT;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
v->v.f = strtod(token + 1, &r);
|
||||||
|
if (*r)
|
||||||
|
goto bad;
|
||||||
|
v->type = DM_CFG_FLOAT;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (!(r = dm_pool_alloc(cft->mem, strlen(token + 1)))) {
|
||||||
|
dm_free(enc_value);
|
||||||
|
log_error("Failed to duplicate token for default "
|
||||||
|
"array value of %s.", def->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(r, token + 1, strlen(token + 1));
|
||||||
|
v->v.str = r;
|
||||||
|
v->type = DM_CFG_STRING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldv = v;
|
||||||
|
token = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_free(enc_value);
|
||||||
|
return array;
|
||||||
|
bad:
|
||||||
|
log_error(INTERNAL_ERROR "Default array value malformed for \"%s\", "
|
||||||
|
"value: \"%s\", token: \"%s\".", def->name,
|
||||||
|
def->default_value.v_CFG_TYPE_STRING, token);
|
||||||
|
dm_free(enc_value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||||
|
struct config_def_tree_spec *spec,
|
||||||
|
struct dm_config_node *parent,
|
||||||
|
struct dm_config_node *relay,
|
||||||
|
cfg_def_item_t *def)
|
||||||
|
{
|
||||||
|
struct dm_config_node *cn;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
if (!(cn = dm_config_create_node(cft, def->name))) {
|
||||||
|
log_error("Failed to create default config setting node.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(def->type & CFG_TYPE_SECTION) && (!(cn->v = dm_config_create_value(cft)))) {
|
||||||
|
log_error("Failed to create default config setting node value.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(def->type & CFG_TYPE_ARRAY)) {
|
||||||
|
switch (def->type) {
|
||||||
|
case CFG_TYPE_SECTION:
|
||||||
|
cn->v = NULL;
|
||||||
|
break;
|
||||||
|
case CFG_TYPE_BOOL:
|
||||||
|
cn->v->type = DM_CFG_INT;
|
||||||
|
cn->v->v.i = cfg_def_get_default_value(def, CFG_TYPE_BOOL);
|
||||||
|
break;
|
||||||
|
case CFG_TYPE_INT:
|
||||||
|
cn->v->type = DM_CFG_INT;
|
||||||
|
cn->v->v.i = cfg_def_get_default_value(def, CFG_TYPE_INT);
|
||||||
|
break;
|
||||||
|
case CFG_TYPE_FLOAT:
|
||||||
|
cn->v->type = DM_CFG_FLOAT;
|
||||||
|
cn->v->v.f = cfg_def_get_default_value(def, CFG_TYPE_FLOAT);
|
||||||
|
break;
|
||||||
|
case CFG_TYPE_STRING:
|
||||||
|
cn->v->type = DM_CFG_STRING;
|
||||||
|
if (!(str = cfg_def_get_default_value(def, CFG_TYPE_STRING)))
|
||||||
|
str = "";
|
||||||
|
cn->v->v.str = str;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error(INTERNAL_ERROR "_add_def_node: unknown type");
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
cn->v = _get_def_array_values(cft, def);
|
||||||
|
|
||||||
|
cn->child = NULL;
|
||||||
|
if (parent) {
|
||||||
|
cn->parent = parent;
|
||||||
|
if (!parent->child)
|
||||||
|
parent->child = cn;
|
||||||
|
} else
|
||||||
|
cn->parent = cn;
|
||||||
|
|
||||||
|
if (relay)
|
||||||
|
relay->sib = cn;
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_id, cfg_def_item_t *def)
|
||||||
|
{
|
||||||
|
if (def->parent != section_id)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
switch (spec->type) {
|
||||||
|
case CFG_DEF_TREE_MISSING:
|
||||||
|
if ((def->flags & CFG_USED) ||
|
||||||
|
(def->flags & CFG_NAME_VARIABLE) ||
|
||||||
|
(def->since_version > spec->version))
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case CFG_DEF_TREE_NEW:
|
||||||
|
if (def->since_version != spec->version)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (def->since_version > spec->version)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dm_config_node *_add_def_section_subtree(struct dm_config_tree *cft,
|
||||||
|
struct config_def_tree_spec *spec,
|
||||||
|
struct dm_config_node *parent,
|
||||||
|
struct dm_config_node *relay,
|
||||||
|
int section_id)
|
||||||
|
{
|
||||||
|
struct dm_config_node *cn = NULL, *relay_sub = NULL, *tmp;
|
||||||
|
cfg_def_item_t *def;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
for (id = 0; id < CFG_COUNT; id++) {
|
||||||
|
def = cfg_def_get_item_p(id);
|
||||||
|
if (_should_skip_def_node(spec, section_id, def))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!cn && !(cn = _add_def_node(cft, spec, parent, relay, cfg_def_get_item_p(section_id))))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
if ((tmp = def->type == CFG_TYPE_SECTION ? _add_def_section_subtree(cft, spec, cn, relay_sub, id)
|
||||||
|
: _add_def_node(cft, spec, cn, relay_sub, def)))
|
||||||
|
relay_sub = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
bad:
|
||||||
|
log_error("Failed to create default config section node.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||||
|
{
|
||||||
|
struct dm_config_tree *cft;
|
||||||
|
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
if (!(cft = dm_config_create())) {
|
||||||
|
log_error("Failed to create default config tree.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id = root_CFG_SECTION + 1; id < CFG_COUNT; id++) {
|
||||||
|
if (cfg_def_get_item_p(id)->parent != root_CFG_SECTION)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((tmp = _add_def_section_subtree(cft, spec, root, relay, id))) {
|
||||||
|
relay = tmp;
|
||||||
|
if (!root)
|
||||||
|
root = relay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cft->root = root;
|
||||||
|
return cft;
|
||||||
|
}
|
||||||
|
@ -76,6 +76,23 @@ typedef struct cfg_def_item {
|
|||||||
const char *comment; /* brief comment */
|
const char *comment; /* brief comment */
|
||||||
} cfg_def_item_t;
|
} cfg_def_item_t;
|
||||||
|
|
||||||
|
/* configuration definition tree types */
|
||||||
|
typedef enum {
|
||||||
|
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
|
||||||
|
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
|
||||||
|
CFG_DEF_TREE_COMPLETE, /* CURRENT + MISSING, the tree actually used within execution, not implemented yet */
|
||||||
|
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
|
||||||
|
CFG_DEF_TREE_NEW /* tree of all new nodes that appeared in given version */
|
||||||
|
} cfg_def_tree_t;
|
||||||
|
|
||||||
|
/* configuration definition tree specification */
|
||||||
|
struct config_def_tree_spec {
|
||||||
|
cfg_def_tree_t type; /* tree type */
|
||||||
|
uint16_t version; /* tree at this LVM2 version */
|
||||||
|
int ignoreadvanced; /* do not include advanced configs */
|
||||||
|
int ignoreunsupported; /* do not include unsupported configs */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register ID for each possible item in the configuration tree.
|
* Register ID for each possible item in the configuration tree.
|
||||||
*/
|
*/
|
||||||
@ -103,8 +120,8 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
|||||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||||
int config_file_read(struct dm_config_tree *cft);
|
int config_file_read(struct dm_config_tree *cft);
|
||||||
int config_write(struct dm_config_tree *cft, const char *file,
|
int config_write(struct dm_config_tree *cft, const char *file, int argc, char **argv);
|
||||||
int argc, char **argv);
|
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec);
|
||||||
void config_file_destroy(struct dm_config_tree *cft);
|
void config_file_destroy(struct dm_config_tree *cft);
|
||||||
|
|
||||||
time_t config_file_timestamp(struct dm_config_tree *cft);
|
time_t config_file_timestamp(struct dm_config_tree *cft);
|
||||||
|
@ -67,7 +67,7 @@ cfg_section(dmeventd_CFG_SECTION, "dmeventd", root_CFG_SECTION, 0, vsn(1, 2, 3),
|
|||||||
cfg_section(tags_CFG_SECTION, "tags", root_CFG_SECTION, 0, vsn(1, 0, 18), NULL)
|
cfg_section(tags_CFG_SECTION, "tags", root_CFG_SECTION, 0, vsn(1, 0, 18), NULL)
|
||||||
|
|
||||||
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), "Configuration tree check on each LVM command execution.")
|
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), "Configuration tree check on each LVM command execution.")
|
||||||
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,2,99), "Abort LVM command execution if configuration is invalid.")
|
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), "Abort LVM command execution if configuration is invalid.")
|
||||||
|
|
||||||
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL)
|
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL)
|
||||||
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, 0, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL)
|
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, 0, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user