mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-23 02:05:07 +03:00
Support tagged config files.
This commit is contained in:
parent
46cdd53323
commit
c3941941ce
@ -1,3 +1,9 @@
|
||||
Version 2.00.16 -
|
||||
=============================
|
||||
Support for tagged config files.
|
||||
Don't abort operations if selinux present but disabled.
|
||||
Fix typo in configure which left HAVE_LIBDL unset.
|
||||
|
||||
Version 2.00.15 - 19 Apr 2004
|
||||
=============================
|
||||
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
||||
|
@ -173,13 +173,13 @@ int activation(void)
|
||||
static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct config_node *cn;
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
char *str;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
|
||||
/* If no hosts tags defined, activate */
|
||||
/* If no host tags defined, activate */
|
||||
if (list_empty(&cmd->tags))
|
||||
return 1;
|
||||
|
||||
|
@ -116,8 +116,7 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
find_config_int(cmd->cft->root, "global/test", 0);
|
||||
|
||||
/* Settings for logging to file */
|
||||
if (find_config_int(cmd->cft->root, "log/overwrite",
|
||||
DEFAULT_OVERWRITE))
|
||||
if (find_config_int(cmd->cft->root, "log/overwrite", DEFAULT_OVERWRITE))
|
||||
append = 0;
|
||||
|
||||
log_file = find_config_str(cmd->cft->root, "log/file", 0);
|
||||
@ -198,51 +197,260 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find and read config file */
|
||||
static int _init_config(struct cmd_context *cmd)
|
||||
static int _set_tag(struct cmd_context *cmd, const char *tag)
|
||||
{
|
||||
struct stat info;
|
||||
char config_file[PATH_MAX] = "";
|
||||
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
|
||||
|
||||
if (!(cmd->cft = create_config_tree())) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
if (!*cmd->sys_dir)
|
||||
return 1;
|
||||
|
||||
if (lvm_snprintf(config_file, sizeof(config_file),
|
||||
"%s/lvm.conf", cmd->sys_dir) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR was too long");
|
||||
destroy_config_tree(cmd->cft);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is there a config file? */
|
||||
if (stat(config_file, &info) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return 1;
|
||||
log_sys_error("stat", config_file);
|
||||
destroy_config_tree(cmd->cft);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_config_file(cmd->cft, config_file)) {
|
||||
log_error("Failed to load config file %s", config_file);
|
||||
destroy_config_tree(cmd->cft);
|
||||
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
|
||||
log_error("_set_tag: str_list_add %s failed", tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_dev_cache(struct cmd_context *cmd)
|
||||
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
|
||||
int *passes)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
*passes = 1;
|
||||
|
||||
for (cn = hn; cn; cn = cn->sib) {
|
||||
if (!cn->v)
|
||||
continue;
|
||||
if (!strcmp(cn->key, "host_list")) {
|
||||
*passes = 0;
|
||||
if (cn->v->type == CFG_EMPTY_ARRAY)
|
||||
continue;
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid hostname string "
|
||||
"for tag %s", cn->key);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cv->v.str, cmd->hostname)) {
|
||||
*passes = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!strcmp(cn->key, "host_filter")) {
|
||||
log_error("host_filter not supported yet");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
|
||||
{
|
||||
const struct config_node *tn, *cn;
|
||||
const char *tag;
|
||||
int passes;
|
||||
|
||||
if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
|
||||
return 1;
|
||||
|
||||
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
|
||||
if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
|
||||
DEFAULT_HOSTTAGS)) {
|
||||
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||
if (!_set_tag(cmd, cmd->hostname)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
cmd->hosttags = 1;
|
||||
}
|
||||
|
||||
for (cn = tn->child; cn; cn = cn->sib) {
|
||||
if (cn->v)
|
||||
continue;
|
||||
tag = cn->key;
|
||||
if (*tag == '@')
|
||||
tag++;
|
||||
if (!validate_name(tag)) {
|
||||
log_error("Invalid tag in config file: %s", cn->key);
|
||||
return 0;
|
||||
}
|
||||
if (cn->child) {
|
||||
passes = 0;
|
||||
if (!_check_host_filters(cmd, cn->child, &passes)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!passes)
|
||||
continue;
|
||||
}
|
||||
if (!_set_tag(cmd, tag)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
{
|
||||
char config_file[PATH_MAX] = "";
|
||||
const char *filler = "";
|
||||
struct stat info;
|
||||
struct config_tree_list *cfl;
|
||||
|
||||
if (*tag)
|
||||
filler = "_";
|
||||
|
||||
if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||
cmd->sys_dir, filler, tag) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR or tag was too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cfl = pool_alloc(cmd->libmem, sizeof(*cfl)))) {
|
||||
log_error("config_tree_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cfl->cft = create_config_tree(config_file))) {
|
||||
log_error("config_tree allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is there a config file? */
|
||||
if (stat(config_file, &info) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
list_add(&cmd->config_files, &cfl->list);
|
||||
goto out;
|
||||
}
|
||||
log_sys_error("stat", config_file);
|
||||
destroy_config_tree(cfl->cft);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Loading config file: %s", config_file);
|
||||
if (!read_config_file(cfl->cft)) {
|
||||
log_error("Failed to load config file %s", config_file);
|
||||
destroy_config_tree(cfl->cft);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_add(&cmd->config_files, &cfl->list);
|
||||
|
||||
out:
|
||||
if (*tag)
|
||||
_init_tags(cmd, cfl->cft);
|
||||
else
|
||||
/* Use temporary copy of lvm.conf while loading other files */
|
||||
cmd->cft = cfl->cft;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find and read first config file */
|
||||
static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
{
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
if (!*cmd->sys_dir) {
|
||||
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_load_config_file(cmd, "")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read any additional config files */
|
||||
static int _init_tag_configs(struct cmd_context *cmd)
|
||||
{
|
||||
struct str_list *sl;
|
||||
|
||||
/* Tag list may grow while inside this loop */
|
||||
list_iterate_items(sl, &cmd->tags) {
|
||||
if (!_load_config_file(cmd, sl->str)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _merge_config_files(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_tree_list *cfl;
|
||||
|
||||
/* Replace temporary duplicate copy of lvm.conf */
|
||||
if (cmd->cft->root) {
|
||||
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate_items(cfl, &cmd->config_files) {
|
||||
/* Merge all config trees into cmd->cft using merge/tag rules */
|
||||
if (!merge_config_tree(cmd, cmd->cft, cfl->cft)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_tags(struct cmd_context *cmd)
|
||||
{
|
||||
struct list *slh, *slht;
|
||||
|
||||
list_iterate_safe(slh, slht, &cmd->tags) {
|
||||
list_del(slh);
|
||||
}
|
||||
}
|
||||
|
||||
int config_files_changed(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_tree_list *cfl;
|
||||
|
||||
list_iterate_items(cfl, &cmd->config_files) {
|
||||
if (config_file_changed(cfl->cft))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _destroy_tag_configs(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_tree_list *cfl;
|
||||
|
||||
if (cmd->cft && cmd->cft->root) {
|
||||
destroy_config_tree(cmd->cft);
|
||||
cmd->cft = NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(cfl, &cmd->config_files) {
|
||||
destroy_config_tree(cfl->cft);
|
||||
}
|
||||
|
||||
list_init(&cmd->config_files);
|
||||
}
|
||||
|
||||
static int _init_dev_cache(struct cmd_context *cmd)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
stack;
|
||||
return 0;
|
||||
@ -281,7 +489,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
{
|
||||
unsigned nr_filt = 0;
|
||||
struct config_node *cn;
|
||||
const struct config_node *cn;
|
||||
struct dev_filter *filters[MAX_FILTERS];
|
||||
|
||||
memset(filters, 0, sizeof(filters));
|
||||
@ -351,8 +559,8 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_cache =
|
||||
find_config_str(cmd->cft->root, "devices/cache", cache_file);
|
||||
dev_cache = find_config_str(cmd->cft->root, "devices/cache",
|
||||
cache_file);
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||
log_error("Failed to create persistent device filter");
|
||||
return 0;
|
||||
@ -384,7 +592,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
struct list *fmth;
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
struct config_node *cn;
|
||||
const struct config_node *cn;
|
||||
#endif
|
||||
|
||||
label_init();
|
||||
@ -476,105 +684,6 @@ static int _init_hostname(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _set_tag(struct cmd_context *cmd, const char *tag)
|
||||
{
|
||||
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
|
||||
|
||||
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
|
||||
log_error("_init_tags: str_list_add %s failed", tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
|
||||
int *passes)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
*passes = 1;
|
||||
|
||||
for (cn = hn; cn; cn = cn->sib) {
|
||||
if (!cn->v)
|
||||
continue;
|
||||
if (!strcmp(cn->key, "host_list")) {
|
||||
*passes = 0;
|
||||
if (cn->v->type == CFG_EMPTY_ARRAY)
|
||||
continue;
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid hostname string "
|
||||
"for tag %s", cn->key);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(cv->v.str, cmd->hostname)) {
|
||||
*passes = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!strcmp(cn->key, "host_filter")) {
|
||||
log_error("host_filter not supported yet");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_tags(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_node *tn, *cn;
|
||||
const char *tag;
|
||||
int passes;
|
||||
|
||||
list_init(&cmd->tags);
|
||||
|
||||
if (!(tn = find_config_node(cmd->cft->root, "tags")) ||
|
||||
!tn->child) {
|
||||
log_very_verbose("No tags defined in config file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (find_config_int(cmd->cft->root, "tags/hosttags",
|
||||
DEFAULT_HOSTTAGS)) {
|
||||
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||
if (!_set_tag(cmd, cmd->hostname)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (cn = tn->child; cn; cn = cn->sib) {
|
||||
if (cn->v)
|
||||
continue;
|
||||
tag = cn->key;
|
||||
if (*tag == '@')
|
||||
tag++;
|
||||
if (!validate_name(tag)) {
|
||||
log_error("Invalid tag in config file: %s", cn->key);
|
||||
return 0;
|
||||
}
|
||||
if (cn->child) {
|
||||
passes = 0;
|
||||
if (!_check_host_filters(cmd, cn->child, &passes)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!passes)
|
||||
continue;
|
||||
}
|
||||
if (!_set_tag(cmd, tag)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
{
|
||||
@ -599,7 +708,10 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
}
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->args = the_args;
|
||||
cmd->hosttags = 0;
|
||||
list_init(&cmd->formats);
|
||||
list_init(&cmd->tags);
|
||||
list_init(&cmd->config_files);
|
||||
|
||||
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
|
||||
|
||||
@ -610,16 +722,28 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||
goto error;
|
||||
|
||||
if (!_init_config(cmd))
|
||||
goto error;
|
||||
|
||||
_init_logging(cmd);
|
||||
|
||||
if (!(cmd->libmem = pool_create(4 * 1024))) {
|
||||
log_error("Library memory pool creation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_init_lvm_conf(cmd))
|
||||
goto error;
|
||||
|
||||
_init_logging(cmd);
|
||||
|
||||
if (!_init_hostname(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_tags(cmd, cmd->cft))
|
||||
goto error;
|
||||
|
||||
if (!_init_tag_configs(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_merge_config_files(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_process_config(cmd))
|
||||
goto error;
|
||||
|
||||
@ -639,14 +763,9 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
if (!_init_formats(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_hostname(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_tags(cmd))
|
||||
goto error;
|
||||
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
cmd->config_valid = 1;
|
||||
return cmd;
|
||||
|
||||
error:
|
||||
@ -654,16 +773,6 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int refresh_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
_init_logging(cmd);
|
||||
_init_tags(cmd);
|
||||
|
||||
/* FIXME Reset filters and dev_cache */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_formats(struct list *formats)
|
||||
{
|
||||
struct list *fmtl, *tmp;
|
||||
@ -682,6 +791,61 @@ static void _destroy_formats(struct list *formats)
|
||||
}
|
||||
}
|
||||
|
||||
int refresh_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
log_verbose("Reloading config files");
|
||||
|
||||
if (cmd->config_valid) {
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
}
|
||||
|
||||
activation_exit();
|
||||
lvmcache_destroy();
|
||||
label_exit();
|
||||
_destroy_formats(&cmd->formats);
|
||||
if (cmd->filter) {
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
cmd->filter = NULL;
|
||||
}
|
||||
dev_cache_exit();
|
||||
_destroy_tags(cmd);
|
||||
_destroy_tag_configs(cmd);
|
||||
|
||||
cmd->config_valid = 0;
|
||||
|
||||
cmd->hosttags = 0;
|
||||
|
||||
if (!_init_lvm_conf(cmd))
|
||||
return 0;
|
||||
|
||||
_init_logging(cmd);
|
||||
|
||||
if (!_init_tags(cmd, cmd->cft))
|
||||
return 0;
|
||||
|
||||
if (!_init_tag_configs(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_merge_config_files(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_process_config(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
return 0;
|
||||
|
||||
cmd->config_valid = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
if (cmd->dump_filter)
|
||||
@ -694,7 +858,8 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
pool_destroy(cmd->mem);
|
||||
dev_cache_exit();
|
||||
destroy_config_tree(cmd->cft);
|
||||
_destroy_tags(cmd);
|
||||
_destroy_tag_configs(cmd);
|
||||
pool_destroy(cmd->libmem);
|
||||
dbg_free(cmd);
|
||||
|
||||
|
@ -17,9 +17,7 @@
|
||||
#define _LVM_TOOLCONTEXT_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
#include "config.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
@ -47,6 +45,8 @@ struct config_info {
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
struct config_tree;
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
@ -68,12 +68,15 @@ struct cmd_context {
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
|
||||
struct list config_files;
|
||||
int config_valid;
|
||||
struct config_tree *cft;
|
||||
struct config_info default_settings;
|
||||
struct config_info current_settings;
|
||||
|
||||
/* List of defined tags */
|
||||
struct list tags;
|
||||
int hosttags;
|
||||
|
||||
char sys_dir[PATH_MAX];
|
||||
char dev_dir[PATH_MAX];
|
||||
@ -83,5 +86,6 @@ struct cmd_context {
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "crc.h"
|
||||
#include "pool.h"
|
||||
#include "device.h"
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@ -56,6 +58,7 @@ struct cs {
|
||||
struct pool *mem;
|
||||
time_t timestamp;
|
||||
char *filename;
|
||||
int exists;
|
||||
};
|
||||
|
||||
static void _get_token(struct parser *p, int tok_prev);
|
||||
@ -93,7 +96,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
||||
/*
|
||||
* public interface
|
||||
*/
|
||||
struct config_tree *create_config_tree(void)
|
||||
struct config_tree *create_config_tree(const char *filename)
|
||||
{
|
||||
struct cs *c;
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
@ -103,7 +106,7 @@ struct config_tree *create_config_tree(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||
if (!(c = pool_zalloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
@ -112,7 +115,9 @@ struct config_tree *create_config_tree(void)
|
||||
c->mem = mem;
|
||||
c->cft.root = (struct config_node *) NULL;
|
||||
c->timestamp = 0;
|
||||
c->filename = NULL;
|
||||
c->exists = 0;
|
||||
if (filename)
|
||||
c->filename = pool_strdup(c->mem, filename);
|
||||
return &c->cft;
|
||||
}
|
||||
|
||||
@ -204,29 +209,33 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
int read_config_file(struct config_tree *cft, const char *file)
|
||||
int read_config_file(struct config_tree *cft)
|
||||
{
|
||||
struct cs *c = (struct cs *) cft;
|
||||
struct stat info;
|
||||
struct device *dev;
|
||||
int r = 1;
|
||||
|
||||
if (stat(file, &info)) {
|
||||
log_sys_error("stat", file);
|
||||
if (stat(c->filename, &info)) {
|
||||
log_sys_error("stat", c->filename);
|
||||
c->exists = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
log_error("%s is not a regular file", file);
|
||||
log_error("%s is not a regular file", c->filename);
|
||||
c->exists = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->exists = 1;
|
||||
|
||||
if (info.st_size == 0) {
|
||||
log_verbose("%s is empty", file);
|
||||
log_verbose("%s is empty", c->filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dev = dev_create_file(file, NULL, NULL))) {
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@ -242,7 +251,6 @@ int read_config_file(struct config_tree *cft, const char *file)
|
||||
dev_close(dev);
|
||||
|
||||
c->timestamp = info.st_mtime;
|
||||
c->filename = pool_strdup(c->mem, file);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -255,74 +263,43 @@ time_t config_file_timestamp(struct config_tree *cft)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if config file reloaded
|
||||
* Return 1 if config files ought to be reloaded
|
||||
*/
|
||||
int reload_config_file(struct config_tree **cft)
|
||||
int config_file_changed(struct config_tree *cft)
|
||||
{
|
||||
struct config_tree *new_cft;
|
||||
struct cs *c = (struct cs *) *cft;
|
||||
struct cs *new_cs;
|
||||
struct cs *c = (struct cs *) cft;
|
||||
struct stat info;
|
||||
struct device *dev;
|
||||
int r;
|
||||
|
||||
if (!c->filename)
|
||||
return 0;
|
||||
|
||||
if (stat(c->filename, &info) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return 1;
|
||||
/* Ignore a deleted config file: still use original data */
|
||||
if (errno == ENOENT) {
|
||||
if (!c->exists)
|
||||
return 0;
|
||||
log_very_verbose("Config file %s has disappeared!",
|
||||
c->filename);
|
||||
goto reload;
|
||||
}
|
||||
log_sys_error("stat", c->filename);
|
||||
log_error("Failed to reload configuration file");
|
||||
log_error("Failed to reload configuration files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
log_error("Configuration file %s is not a regular file",
|
||||
c->filename);
|
||||
return 0;
|
||||
goto reload;
|
||||
}
|
||||
|
||||
/* Unchanged? */
|
||||
if (c->timestamp == info.st_mtime)
|
||||
return 0;
|
||||
|
||||
log_verbose("Detected config file change: Reloading %s", c->filename);
|
||||
|
||||
if (info.st_size == 0) {
|
||||
log_verbose("Config file reload: %s is empty", c->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(new_cft = create_config_tree())) {
|
||||
log_error("Allocation of new config_tree failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_config_fd(new_cft, dev, 0, (size_t) info.st_size,
|
||||
0, 0, (checksum_fn_t) NULL, 0);
|
||||
|
||||
dev_close(dev);
|
||||
|
||||
if (r) {
|
||||
new_cs = (struct cs *) new_cft;
|
||||
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
|
||||
new_cs->timestamp = info.st_mtime;
|
||||
destroy_config_tree(*cft);
|
||||
*cft = new_cft;
|
||||
}
|
||||
|
||||
return r;
|
||||
reload:
|
||||
log_verbose("Detected config file change to %s", c->filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _write_value(FILE *fp, struct config_value *v)
|
||||
@ -739,7 +716,8 @@ static char *_dup_tok(struct parser *p)
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
struct config_node *find_config_node(struct config_node *cn, const char *path)
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path)
|
||||
{
|
||||
const char *e;
|
||||
|
||||
@ -767,13 +745,13 @@ struct config_node *find_config_node(struct config_node *cn, const char *path)
|
||||
path = e;
|
||||
}
|
||||
|
||||
return cn;
|
||||
return (struct config_node *) cn;
|
||||
}
|
||||
|
||||
const char *find_config_str(struct config_node *cn,
|
||||
const char *find_config_str(const struct config_node *cn,
|
||||
const char *path, const char *fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path);
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
|
||||
if (n && n->v->type == CFG_STRING) {
|
||||
if (*n->v->v.str)
|
||||
@ -787,9 +765,9 @@ const char *find_config_str(struct config_node *cn,
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_int(struct config_node *cn, const char *path, int fail)
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path);
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
@ -801,9 +779,10 @@ int find_config_int(struct config_node *cn, const char *path, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
float find_config_float(struct config_node *cn, const char *path, float fail)
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path);
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
|
||||
if (n && n->v->type == CFG_FLOAT) {
|
||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||
@ -843,9 +822,9 @@ static int _str_to_bool(const char *str, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_bool(struct config_node *cn, const char *path, int fail)
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path);
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
struct config_value *v;
|
||||
|
||||
if (!n)
|
||||
@ -864,10 +843,10 @@ int find_config_bool(struct config_node *cn, const char *path, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
int get_config_uint32(struct config_node *cn, const char *path,
|
||||
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||
uint32_t *result)
|
||||
{
|
||||
struct config_node *n;
|
||||
const struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path);
|
||||
|
||||
@ -878,10 +857,10 @@ int get_config_uint32(struct config_node *cn, const char *path,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_config_uint64(struct config_node *cn, const char *path,
|
||||
int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
uint64_t *result)
|
||||
{
|
||||
struct config_node *n;
|
||||
const struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path);
|
||||
|
||||
@ -893,9 +872,10 @@ int get_config_uint64(struct config_node *cn, const char *path,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_config_str(struct config_node *cn, const char *path, char **result)
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result)
|
||||
{
|
||||
struct config_node *n;
|
||||
const struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path);
|
||||
|
||||
@ -905,3 +885,115 @@ int get_config_str(struct config_node *cn, const char *path, char **result)
|
||||
*result = n->v->v.str;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Insert cn2 after cn1 */
|
||||
static void _insert_config_node(struct config_node **cn1,
|
||||
struct config_node *cn2)
|
||||
{
|
||||
if (!*cn1) {
|
||||
*cn1 = cn2;
|
||||
cn2->sib = NULL;
|
||||
} else {
|
||||
cn2->sib = (*cn1)->sib;
|
||||
(*cn1)->sib = cn2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge section cn2 into section cn1 (which has the same name)
|
||||
* overwriting any existing cn1 nodes with matching names.
|
||||
*/
|
||||
static void _merge_section(struct config_node *cn1, struct config_node *cn2)
|
||||
{
|
||||
struct config_node *cn, *nextn, *oldn;
|
||||
struct config_value *cv;
|
||||
|
||||
for (cn = cn2->child; cn; cn = nextn) {
|
||||
nextn = cn->sib;
|
||||
|
||||
/* Skip "tags" */
|
||||
if (!strcmp(cn->key, "tags"))
|
||||
continue;
|
||||
|
||||
/* Subsection? */
|
||||
if (!cn->v)
|
||||
/* Ignore - we don't have any of these yet */
|
||||
continue;
|
||||
/* Not already present? */
|
||||
if (!(oldn = find_config_node(cn1->child, cn->key))) {
|
||||
_insert_config_node(&cn1->child, cn);
|
||||
continue;
|
||||
}
|
||||
/* Merge certain value lists */
|
||||
if ((!strcmp(cn1->key, "activation") &&
|
||||
!strcmp(cn->key, "volume_list")) ||
|
||||
(!strcmp(cn1->key, "devices") &&
|
||||
(!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
|
||||
cv = cn->v;
|
||||
while (cv->next)
|
||||
cv = cv->next;
|
||||
cv->next = oldn->v;
|
||||
}
|
||||
|
||||
/* Replace values */
|
||||
oldn->v = cn->v;
|
||||
}
|
||||
}
|
||||
|
||||
static int _match_host_tags(struct list *tags, struct config_node *tn)
|
||||
{
|
||||
struct config_value *tv;
|
||||
const char *str;
|
||||
|
||||
for (tv = tn->v; tv; tv = tv->next) {
|
||||
if (tv->type != CFG_STRING)
|
||||
continue;
|
||||
str = tv->v.str;
|
||||
if (*str == '@')
|
||||
str++;
|
||||
if (!*str)
|
||||
continue;
|
||||
if (str_list_match_item(tags, str))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Destructively merge a new config tree into an existing one */
|
||||
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
struct config_tree *newdata)
|
||||
{
|
||||
struct config_node *root = cft->root;
|
||||
struct config_node *cn, *nextn, *oldn, *tn, *cn2;
|
||||
|
||||
for (cn = newdata->root; cn; cn = nextn) {
|
||||
nextn = cn->sib;
|
||||
/* Ignore tags section */
|
||||
if (!strcmp(cn->key, "tags"))
|
||||
continue;
|
||||
/* If there's a tags node, skip if host tags don't match */
|
||||
if ((tn = find_config_node(cn->child, "tags"))) {
|
||||
if (!_match_host_tags(&cmd->tags, tn))
|
||||
continue;
|
||||
}
|
||||
if (!(oldn = find_config_node(root, cn->key))) {
|
||||
_insert_config_node(&cft->root, cn);
|
||||
/* Remove any "tags" nodes */
|
||||
for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
|
||||
if (!strcmp(cn2->key, "tags")) {
|
||||
cn->child = cn2->sib;
|
||||
continue;
|
||||
}
|
||||
if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
|
||||
cn2->sib = cn2->sib->sib;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_merge_section(oldn, cn);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -16,7 +16,8 @@
|
||||
#ifndef _LVM_CONFIG_H
|
||||
#define _LVM_CONFIG_H
|
||||
|
||||
#include "device.h"
|
||||
struct device;
|
||||
struct cmd_context;
|
||||
|
||||
enum {
|
||||
CFG_STRING,
|
||||
@ -45,42 +46,51 @@ struct config_tree {
|
||||
struct config_node *root;
|
||||
};
|
||||
|
||||
struct config_tree *create_config_tree(void);
|
||||
void destroy_config_tree(struct config_tree *cf);
|
||||
struct config_tree_list {
|
||||
struct list list;
|
||||
struct config_tree *cft;
|
||||
};
|
||||
|
||||
struct config_tree *create_config_tree(const char *filename);
|
||||
void destroy_config_tree(struct config_tree *cft);
|
||||
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||
|
||||
int read_config_fd(struct config_tree *cf, struct device *dev,
|
||||
int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||
|
||||
int read_config_file(struct config_tree *cf, const char *file);
|
||||
int write_config_file(struct config_tree *cf, const char *file);
|
||||
int reload_config_file(struct config_tree **cf);
|
||||
time_t config_file_timestamp(struct config_tree *cf);
|
||||
int read_config_file(struct config_tree *cft);
|
||||
int write_config_file(struct config_tree *cft, const char *file);
|
||||
time_t config_file_timestamp(struct config_tree *cft);
|
||||
int config_file_changed(struct config_tree *cft);
|
||||
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
struct config_tree *newdata);
|
||||
|
||||
struct config_node *find_config_node(struct config_node *cn,
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path);
|
||||
|
||||
const char *find_config_str(struct config_node *cn, const char *path,
|
||||
const char *find_config_str(const struct config_node *cn, const char *path,
|
||||
const char *fail);
|
||||
|
||||
int find_config_int(struct config_node *cn, const char *path, int fail);
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail);
|
||||
|
||||
float find_config_float(struct config_node *cn, const char *path, float fail);
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail);
|
||||
|
||||
/*
|
||||
* Understands (0, ~0), (y, n), (yes, no), (on,
|
||||
* off), (true, false).
|
||||
*/
|
||||
int find_config_bool(struct config_node *cn, const char *path, int fail);
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail);
|
||||
|
||||
int get_config_uint32(struct config_node *cn, const char *path,
|
||||
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||
uint32_t *result);
|
||||
|
||||
int get_config_uint64(struct config_node *cn, const char *path,
|
||||
int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
uint64_t *result);
|
||||
|
||||
int get_config_str(struct config_node *cn, const char *path, char **result);
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result);
|
||||
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ static void _destroy(struct dev_filter *f)
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
{
|
||||
struct dev_filter **filters_copy, *cf;
|
||||
struct dev_filter **filters_copy, *cft;
|
||||
|
||||
if (!filters) {
|
||||
stack;
|
||||
@ -63,15 +63,15 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
memcpy(filters_copy, filters, sizeof(*filters) * n);
|
||||
filters_copy[n] = NULL;
|
||||
|
||||
if (!(cf = dbg_malloc(sizeof(*cf)))) {
|
||||
if (!(cft = dbg_malloc(sizeof(*cft)))) {
|
||||
log_error("compsoite filters allocation failed");
|
||||
dbg_free(filters_copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cf->passes_filter = _and_p;
|
||||
cf->destroy = _destroy;
|
||||
cf->private = filters_copy;
|
||||
cft->passes_filter = _and_p;
|
||||
cft->destroy = _destroy;
|
||||
cft->private = filters_copy;
|
||||
|
||||
return cf;
|
||||
return cft;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ int persistent_filter_wipe(struct dev_filter *f)
|
||||
static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||
const char *path, void *data)
|
||||
{
|
||||
struct config_node *cn;
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!(cn = find_config_node(cft->root, path))) {
|
||||
@ -99,12 +99,12 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
int r = 0;
|
||||
struct config_tree *cft;
|
||||
|
||||
if (!(cft = create_config_tree())) {
|
||||
if (!(cft = create_config_tree(pf->file))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_config_file(cft, pf->file)) {
|
||||
if (!read_config_file(cft)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
||||
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
{
|
||||
char line[80];
|
||||
char proc_devices[PATH_MAX];
|
||||
@ -199,7 +199,7 @@ static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
||||
}
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||
struct config_node *cn)
|
||||
const struct config_node *cn)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||
struct config_node *cn);
|
||||
const struct config_node *cn);
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
|
@ -49,12 +49,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cft = create_config_tree())) {
|
||||
if (!(cft = create_config_tree(file))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((!dev && !read_config_file(cft, file)) ||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
(dev && !read_config_fd(cft, dev, offset, size,
|
||||
offset2, size2, checksum_fn, checksum))) {
|
||||
log_error("Couldn't read volume group metadata.");
|
||||
|
@ -758,7 +758,7 @@ static int _run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
set_cmd_name(cmd->command->name);
|
||||
|
||||
if (reload_config_file(&cmd->cft)) {
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
|
Loading…
x
Reference in New Issue
Block a user