diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index fd845b75a..34fb99729 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -558,13 +558,13 @@ static int _init_tag_configs(struct cmd_context *cmd) return 1; } -static int _merge_config_files(struct cmd_context *cmd) +struct dm_config_tree *_merge_config_files(struct cmd_context *cmd, struct dm_config_tree *cft) { struct config_tree_list *cfl; /* Replace temporary duplicate copy of lvm.conf */ - if (cmd->cft->root) { - if (!(cmd->cft = dm_config_create(NULL, 0))) { + if (cft->root) { + if (!(cft = dm_config_create(NULL, 0))) { log_error("Failed to create config tree"); return 0; } @@ -572,11 +572,11 @@ static int _merge_config_files(struct cmd_context *cmd) dm_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)) + if (!merge_config_tree(cmd, cft, cfl->cft)) return_0; } - return 1; + return cft; } static void _destroy_tags(struct cmd_context *cmd) @@ -600,9 +600,19 @@ int config_files_changed(struct cmd_context *cmd) return 0; } -static void _destroy_tag_configs(struct cmd_context *cmd) +/* + * Returns cmdline config_tree that overrides all others, if present. + */ +static struct dm_config_tree *_destroy_tag_configs(struct cmd_context *cmd) { struct config_tree_list *cfl; + struct dm_config_tree *cft_cmdline = NULL, *cft; + + cft = dm_config_remove_cascaded_tree(cmd->cft); + if (cft) { + cft_cmdline = cmd->cft; + cmd->cft = cft; + } dm_list_iterate_items(cfl, &cmd->config_files) { if (cfl->cft == cmd->cft) @@ -616,6 +626,8 @@ static void _destroy_tag_configs(struct cmd_context *cmd) } dm_list_init(&cmd->config_files); + + return cft_cmdline; } static int _init_dev_cache(struct cmd_context *cmd) @@ -1285,7 +1297,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived, if (!_init_tag_configs(cmd)) goto_out; - if (!_merge_config_files(cmd)) + if (!(cmd->cft = _merge_config_files(cmd, cmd->cft))) goto_out; if (!_process_config(cmd)) @@ -1397,6 +1409,8 @@ int refresh_filters(struct cmd_context *cmd) int refresh_toolcontext(struct cmd_context *cmd) { + struct dm_config_tree *cft_cmdline, *cft_tmp; + log_verbose("Reloading config files"); /* @@ -1415,7 +1429,7 @@ int refresh_toolcontext(struct cmd_context *cmd) } dev_cache_exit(); _destroy_tags(cmd); - _destroy_tag_configs(cmd); + cft_cmdline = _destroy_tag_configs(cmd); cmd->config_valid = 0; @@ -1424,17 +1438,31 @@ int refresh_toolcontext(struct cmd_context *cmd) if (!_init_lvm_conf(cmd)) return 0; + /* Temporary duplicate cft pointer holding lvm.conf - replaced later */ + cft_tmp = cmd->cft; + if (cft_cmdline) + cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cft_tmp); + + /* Uses cmd->cft i.e. cft_cmdline + lvm.conf */ _init_logging(cmd); - if (!_init_tags(cmd, cmd->cft)) + /* Init tags from lvm.conf. */ + if (!_init_tags(cmd, cft_tmp)) return 0; + /* Doesn't change cmd->cft */ if (!_init_tag_configs(cmd)) return 0; - if (!_merge_config_files(cmd)) + /* Merge all the tag config files with lvm.conf, returning a + * fresh cft pointer in place of cft_tmp. */ + if (!(cmd->cft = _merge_config_files(cmd, cft_tmp))) return 0; + /* Finally we can make the proper, fully-merged, cmd->cft */ + if (cft_cmdline) + cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cmd->cft); + if (!_process_config(cmd)) return 0; @@ -1464,6 +1492,8 @@ int refresh_toolcontext(struct cmd_context *cmd) void destroy_toolcontext(struct cmd_context *cmd) { + struct dm_config_tree *cft_cmdline; + if (cmd->dump_filter) persistent_filter_dump(cmd->filter, 1); @@ -1479,7 +1509,8 @@ void destroy_toolcontext(struct cmd_context *cmd) dm_pool_destroy(cmd->mem); dev_cache_exit(); _destroy_tags(cmd); - _destroy_tag_configs(cmd); + if ((cft_cmdline = _destroy_tag_configs(cmd))) + dm_config_destroy(cft_cmdline); if (cmd->libmem) dm_pool_destroy(cmd->libmem); diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 978d34f10..e66a14b75 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -93,7 +93,6 @@ struct cmd_context { struct dm_list config_files; int config_valid; struct dm_config_tree *cft; - struct dm_config_tree *cft_override; struct config_info default_settings; struct config_info current_settings; diff --git a/lib/config/config.c b/lib/config/config.c index 340b4b543..00dc5c388 100644 --- a/lib/config/config.c +++ b/lib/config/config.c @@ -40,14 +40,34 @@ void destroy_config_tree(struct dm_config_tree *cft) dm_config_destroy(cft); } +/* + * Returns config tree if it was removed. + */ +struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd) +{ + 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; + + return old_cft; +} + int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings) { - if (!(cmd->cft_override = dm_config_from_string(config_settings))) { + struct dm_config_tree *cft_new; + + if (!(cft_new = dm_config_from_string(config_settings))) { log_error("Failed to set overridden configuration entries."); return 1; } + cmd->cft = dm_config_insert_cascaded_tree(cft_new, cmd->cft); + return 0; } @@ -114,7 +134,7 @@ int read_config_fd(struct dm_config_tree *cft, struct device *dev, int read_config_file(struct dm_config_tree *cft) { - const char *filename; + const char *filename = NULL; struct device *dev = dm_config_get_custom(cft); struct stat info; int r; @@ -122,6 +142,10 @@ int read_config_file(struct dm_config_tree *cft) if (!dm_config_check_file(cft, &filename, &info)) return_0; + /* Nothing to do. E.g. empty file. */ + if (!filename) + return 1; + if (!dev) { if (!(dev = dev_create_file(filename, NULL, NULL, 1))) return_0; @@ -142,51 +166,38 @@ int read_config_file(struct dm_config_tree *cft) return r; } -// FIXME AGK Move to override_config_tree_from_string before next release -static struct dm_config_tree *_setup_context_tree(struct cmd_context *cmd) -{ - struct dm_config_tree *cft = cmd->cft_override; - - if (cft) - cft->cascade = cmd->cft; - else - cft = cmd->cft; - - return cft; -} - const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, const char *path) { - return dm_config_tree_find_node(_setup_context_tree(cmd), path); + return dm_config_tree_find_node(cmd->cft, path); } const char *find_config_tree_str(struct cmd_context *cmd, const char *path, const char *fail) { - return dm_config_tree_find_str(_setup_context_tree(cmd), path, fail); + return dm_config_tree_find_str(cmd->cft, path, fail); } int find_config_tree_int(struct cmd_context *cmd, const char *path, int fail) { - return dm_config_tree_find_int(_setup_context_tree(cmd), path, fail); + return dm_config_tree_find_int(cmd->cft, path, fail); } int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail) { - return dm_config_tree_find_int64(_setup_context_tree(cmd), path, fail); + return dm_config_tree_find_int64(cmd->cft, path, fail); } float find_config_tree_float(struct cmd_context *cmd, const char *path, float fail) { - return dm_config_tree_find_float(_setup_context_tree(cmd), path, fail); + return dm_config_tree_find_float(cmd->cft, path, fail); } int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail) { - return dm_config_tree_find_bool(_setup_context_tree(cmd), path, fail); + return dm_config_tree_find_bool(cmd->cft, path, fail); } /* Insert cn2 after cn1 */ diff --git a/lib/config/config.h b/lib/config/config.h index c2a93ad74..5edc6cc46 100644 --- a/lib/config/config.h +++ b/lib/config/config.h @@ -24,6 +24,7 @@ struct cmd_context; int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings); void destroy_config_tree(struct dm_config_tree *cft); +struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd); typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size); diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 6dbf1102e..c0b9fff19 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1248,6 +1248,7 @@ struct dm_config_node { struct dm_config_value *v; }; +/* FIXME Move cascade to dm_config_node and remove this struct */ struct dm_config_tree { struct dm_config_node *root; struct dm_config_tree *cascade; @@ -1263,6 +1264,17 @@ int dm_config_keep_open(struct dm_config_tree *ctf); void dm_config_set_custom(struct dm_config_tree *cft, void *custom); +/* + * If there's a cascaded dm_config_tree, remove the top layer + * and return the layer below. Otherwise return NULL. + */ +struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft); + +/* + * When searching, first_cft is checked before second_cft. + */ +struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft); + void dm_config_destroy(struct dm_config_tree *cft); int dm_config_write(struct dm_config_tree *cft, const char *file, diff --git a/libdm/libdm-config.c b/libdm/libdm-config.c index af1aec18a..c9291e9cb 100644 --- a/libdm/libdm-config.c +++ b/libdm/libdm-config.c @@ -159,6 +159,29 @@ void dm_config_destroy(struct dm_config_tree *cft) dm_pool_destroy(c->mem); } +/* + * If there's a cascaded dm_config_tree, remove and return it, otherwise + * return NULL. + */ +struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft) +{ + struct dm_config_tree *second_cft = cft->cascade; + + cft->cascade = NULL; + + return second_cft; +} + +/* + * When searching, first_cft is checked before second_cft. + */ +struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft) +{ + first_cft->cascade = second_cft; + + return first_cft; +} + int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end) { /* TODO? if (start == end) return 1; */ @@ -196,14 +219,16 @@ struct dm_config_tree *dm_config_from_string(const char *config_settings) return cft; } +/* + * Doesn't populate filename if the file is empty. + */ int dm_config_check_file(struct dm_config_tree *cft, const char **filename, struct stat *info) { struct cs *c = (struct cs *) cft; struct stat _info; + if (!info) info = &_info; - if (filename) - *filename = c->filename; if (stat(c->filename, info)) { log_sys_error("stat", c->filename); @@ -218,12 +243,13 @@ int dm_config_check_file(struct dm_config_tree *cft, const char **filename, stru } c->exists = 1; + c->timestamp = info->st_ctime; + c->st_size = info->st_size; if (info->st_size == 0) log_verbose("%s is empty", c->filename); - - c->timestamp = info->st_ctime; - c->st_size = info->st_size; + else if (filename) + *filename = c->filename; return 1; } diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 299087436..a8e46b18f 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -996,6 +996,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) { int ret = 0; int locking_type; + struct dm_config_tree *old_cft; init_error_message_produced(0); @@ -1020,8 +1021,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) set_cmd_name(cmd->command->name); if (arg_count(cmd, config_ARG)) - if (override_config_tree_from_string(cmd, - arg_str_value(cmd, config_ARG, ""))) { + if (override_config_tree_from_string(cmd, arg_str_value(cmd, config_ARG, ""))) { ret = EINVALID_CMD_LINE; goto_out; } @@ -1029,10 +1029,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) { /* Reinitialise various settings inc. logging, filters */ if (!refresh_toolcontext(cmd)) { - if (cmd->cft_override) { - destroy_config_tree(cmd->cft_override); - cmd->cft_override = NULL; - } + old_cft = remove_overridden_config_tree(cmd); + if (old_cft) + dm_config_destroy(old_cft); log_error("Updated config file invalid. Aborting."); return ECMD_FAILED; } @@ -1081,9 +1080,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) lvmcache_destroy(cmd, 1); } - if (cmd->cft_override) { - destroy_config_tree(cmd->cft_override); - cmd->cft_override = NULL; + if ((old_cft = remove_overridden_config_tree(cmd))) { + dm_config_destroy(old_cft); /* Move this? */ if (!refresh_toolcontext(cmd)) stack;