aboutsummaryrefslogtreecommitdiff
path: root/lib/config/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/config/config.c')
-rw-r--r--lib/config/config.c189
1 files changed, 148 insertions, 41 deletions
diff --git a/lib/config/config.c b/lib/config/config.c
index aec158823..df65d38a7 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -30,8 +30,15 @@
#include <assert.h>
#include <ctype.h>
+static const char *_config_source_names[] = {
+ [CONFIG_UNDEFINED] = "undefined",
+ [CONFIG_FILE] = "file",
+ [CONFIG_MERGED_FILES] = "merged files",
+ [CONFIG_STRING] = "string",
+ [CONFIG_PROFILE] = "profile"
+};
+
struct config_file {
- time_t timestamp;
off_t st_size;
char *filename;
int exists;
@@ -39,6 +46,15 @@ struct config_file {
struct device *dev;
};
+struct config_source {
+ config_source_t type;
+ time_t timestamp;
+ union {
+ struct config_file *file;
+ struct config_file *profile;
+ } source;
+};
+
static char _cfg_path[CFG_PATH_MAX_LEN];
/*
@@ -54,30 +70,49 @@ static struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
#undef cfg_array
};
+config_source_t config_get_source_type(struct dm_config_tree *cft)
+{
+ struct config_source *cs = dm_config_get_custom(cft);
+ return cs ? cs->type : CONFIG_UNDEFINED;
+}
+
/*
* public interface
*/
-struct dm_config_tree *config_file_open(const char *filename, int keep_open)
+struct dm_config_tree *config_open(config_source_t source,
+ const char *filename,
+ int keep_open)
{
struct dm_config_tree *cft = dm_config_create();
+ struct config_source *cs;
struct config_file *cf;
+
if (!cft)
return NULL;
- if (!(cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file)))) {
- log_error("Failed to allocate config tree.");
+ if (!(cs = dm_pool_zalloc(cft->mem, sizeof(struct config_source)))) {
+ log_error("Failed to allocate config source.");
goto fail;
}
- cf->keep_open = keep_open;
- dm_config_set_custom(cft, cf);
+ if ((source == CONFIG_FILE) || (source == CONFIG_PROFILE)) {
+ if (!(cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file)))) {
+ log_error("Failed to allocate config file.");
+ goto fail;
+ }
- if (filename &&
- !(cf->filename = dm_pool_strdup(cft->mem, filename))) {
- log_error("Failed to duplicate filename.");
- goto fail;
+ cf->keep_open = keep_open;
+ if (filename &&
+ !(cf->filename = dm_pool_strdup(cft->mem, filename))) {
+ log_error("Failed to duplicate filename.");
+ goto fail;
+ }
+
+ cs->source.file = cf;
}
+ cs->type = source;
+ dm_config_set_custom(cft, cs);
return cft;
fail:
dm_config_destroy(cft);
@@ -89,12 +124,21 @@ fail:
*/
int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info)
{
- struct config_file *cf = dm_config_get_custom(cft);
+ struct config_source *cs = dm_config_get_custom(cft);
+ struct config_file *cf;
struct stat _info;
+ if ((cs->type != CONFIG_FILE) && (cs->type != CONFIG_PROFILE)) {
+ log_error(INTERNAL_ERROR "config_file_check: expected file or profile config source, "
+ "found %s config source.", _config_source_names[cs->type]);
+ return 0;
+ }
+
if (!info)
info = &_info;
+ cf = cs->source.file;
+
if (stat(cf->filename, info)) {
log_sys_error("stat", cf->filename);
cf->exists = 0;
@@ -107,8 +151,8 @@ int config_file_check(struct dm_config_tree *cft, const char **filename, struct
return 0;
}
+ cs->timestamp = info->st_ctime;
cf->exists = 1;
- cf->timestamp = info->st_ctime;
cf->st_size = info->st_size;
if (info->st_size == 0)
@@ -124,9 +168,18 @@ int config_file_check(struct dm_config_tree *cft, const char **filename, struct
*/
int config_file_changed(struct dm_config_tree *cft)
{
- struct config_file *cf = dm_config_get_custom(cft);
+ struct config_source *cs = dm_config_get_custom(cft);
+ struct config_file *cf;
struct stat info;
+ if (cs->type != CONFIG_FILE) {
+ log_error(INTERNAL_ERROR "config_file_changed: expected file config source, "
+ "found %s config source.", _config_source_names[cs->type]);
+ return 0;
+ }
+
+ cf = cs->source.file;
+
if (!cf->filename)
return 0;
@@ -151,7 +204,7 @@ int config_file_changed(struct dm_config_tree *cft)
}
/* Unchanged? */
- if (cf->timestamp == info.st_ctime && cf->st_size == info.st_size)
+ if (cs->timestamp == info.st_ctime && cf->st_size == info.st_size)
return 0;
reload:
@@ -159,30 +212,41 @@ int config_file_changed(struct dm_config_tree *cft)
return 1;
}
-void config_file_destroy(struct dm_config_tree *cft)
+void config_destroy(struct dm_config_tree *cft)
{
- struct config_file *cf = dm_config_get_custom(cft);
+ struct config_source *cs;
+ struct config_file *cf;
- if (cf && cf->dev)
- if (!dev_close(cf->dev))
- stack;
+ if (!cft)
+ return;
+
+ cs = dm_config_get_custom(cft);
+
+ if ((cs->type == CONFIG_FILE) || (cs->type == CONFIG_PROFILE)) {
+ cf = cs->source.file;
+ if (cf && cf->dev)
+ if (!dev_close(cf->dev))
+ stack;
+ }
dm_config_destroy(cft);
}
-struct dm_config_tree *config_file_open_and_read(const char *config_file)
+struct dm_config_tree *config_file_open_and_read(const char *config_file,
+ config_source_t source)
{
struct dm_config_tree *cft;
struct stat info;
- if (!(cft = config_file_open(config_file, 0))) {
+ if (!(cft = config_open(source, config_file, 0))) {
log_error("config_tree allocation failed");
return NULL;
}
/* Is there a config file? */
if (stat(config_file, &info) == -1) {
- if (errno == ENOENT)
+ /* Profile file must be present! */
+ if (errno == ENOENT && (source != CONFIG_PROFILE))
return cft;
log_sys_error("stat", config_file);
goto bad;
@@ -196,36 +260,69 @@ struct dm_config_tree *config_file_open_and_read(const char *config_file)
return cft;
bad:
- config_file_destroy(cft);
+ config_destroy(cft);
return NULL;
}
/*
* Returns config tree if it was removed.
*/
-struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd)
+struct dm_config_tree *remove_config_tree_by_source(struct cmd_context *cmd,
+ config_source_t source)
{
- struct dm_config_tree *old_cft = cmd->cft;
- struct dm_config_tree *cft = dm_config_remove_cascaded_tree(cmd->cft);
-
- if (!cft)
- return NULL;
-
- cmd->cft = cft;
+ struct dm_config_tree *previous_cft = NULL;
+ struct dm_config_tree *cft = cmd->cft;
+ struct config_source *cs;
+
+ while (cft) {
+ cs = dm_config_get_custom(cft);
+ if (cs && (cs->type == source)) {
+ if (previous_cft) {
+ previous_cft->cascade = cft->cascade;
+ cmd->cft = previous_cft;
+ } else
+ cmd->cft = cft->cascade;
+ cft->cascade = NULL;
+ break;
+ }
+ previous_cft = cft;
+ cft = cft->cascade;
+ }
- return old_cft;
+ return cft;
}
int override_config_tree_from_string(struct cmd_context *cmd,
const char *config_settings)
{
struct dm_config_tree *cft_new;
+ struct config_source *cs = dm_config_get_custom(cmd->cft);
+
+ /*
+ * Follow this sequence:
+ * CONFIG_STRING -> CONFIG_FILE/CONFIG_MERGED_FILES
+ */
+
+ if (cs->type == CONFIG_STRING) {
+ log_error(INTERNAL_ERROR "override_config_tree_from_string: "
+ "config cascade already contains a string config.");
+ return 0;
+ }
if (!(cft_new = dm_config_from_string(config_settings))) {
log_error("Failed to set overridden configuration entries.");
return 0;
}
+ if (!(cs = dm_pool_zalloc(cft_new->mem, sizeof(struct config_source)))) {
+ log_error("Failed to allocate config source.");
+ dm_config_destroy(cft_new);
+ return 0;
+ }
+
+ cs->type = CONFIG_STRING;
+ dm_config_set_custom(cft_new, cs);
+
cmd->cft = dm_config_insert_cascaded_tree(cft_new, cmd->cft);
return 1;
@@ -240,6 +337,13 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
int use_mmap = 1;
off_t mmap_offset = 0;
char *buf = NULL;
+ struct config_source *cs = dm_config_get_custom(cft);
+
+ if ((cs->type != CONFIG_FILE) && (cs->type != CONFIG_PROFILE)) {
+ log_error(INTERNAL_ERROR "config_file_read_fd: expected file or profile config source, "
+ "found %s config source.", _config_source_names[cs->type]);
+ return 0;
+ }
/* Only use mmap with regular files */
if (!(dev->flags & DEV_REGULAR) || size2)
@@ -297,7 +401,8 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
int config_file_read(struct dm_config_tree *cft)
{
const char *filename = NULL;
- struct config_file *cf = dm_config_get_custom(cft);
+ struct config_source *cs = dm_config_get_custom(cft);
+ struct config_file *cf;
struct stat info;
int r;
@@ -308,6 +413,8 @@ int config_file_read(struct dm_config_tree *cft)
if (!filename)
return 1;
+ cf = cs->source.file;
+
if (!cf->dev) {
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
return_0;
@@ -330,9 +437,8 @@ int config_file_read(struct dm_config_tree *cft)
time_t config_file_timestamp(struct dm_config_tree *cft)
{
- struct config_file *cf = dm_config_get_custom(cft);
- assert(cf);
- return cf->timestamp;
+ struct config_source *cs = dm_config_get_custom(cft);
+ return cs->timestamp;
}
#define cfg_def_get_item_p(id) (&_cfg_def_items[id])
@@ -798,7 +904,7 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
struct dm_config_node *root = cft->root;
struct dm_config_node *cn, *nextn, *oldn, *cn2;
const struct dm_config_node *tn;
- struct config_file *cf, *cfn;
+ struct config_source *cs, *csn;
for (cn = newdata->root; cn; cn = nextn) {
nextn = cn->sib;
@@ -833,10 +939,11 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
* so we need to know the newest timestamp to make right decision
* whether the .cache isn't older then any of configs
*/
- if ((cf = dm_config_get_custom(cft)) &&
- (cfn = dm_config_get_custom(newdata)) &&
- cf->timestamp < cfn->timestamp)
- cf->timestamp = cfn->timestamp;
+ cs = dm_config_get_custom(cft);
+ csn = dm_config_get_custom(cft);
+
+ if (cs && csn && (cs->timestamp < csn->timestamp))
+ cs->timestamp = csn->timestamp;
return 1;
}