All grouping inside cf_getopt() uses it, too.
}
static void
-final_commit(struct cf_context *cc)
+end_of_options(struct cf_context *cc)
{
- if (cc->postpone_commit)
- {
- cc->postpone_commit = 0;
- if (cf_done_stack(cc))
- die("Cannot commit after the initialization");
- }
+ load_default(cc);
+ if (cc->postpone_commit && cf_close_group())
+ die("Cannot commit after the initialization");
}
int
cf_getopt(int argc, char *const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
{
struct cf_context *cc = cf_get_context();
- cc->postpone_commit = 1;
+ if (!cc->postpone_commit)
+ cf_open_group();
while (1)
{
#ifdef CONFIG_UCW_DEBUG
else
{ /* --dumpconfig */
- load_default(cc);
- final_commit(cc);
+ end_of_options(cc);
struct fastbuf *b = bfdopen(1, 4096);
cf_dump_sections(b);
bclose(b);
{
/* unhandled option or end of options */
if (res != ':' && res != '?')
- {
- load_default(cc);
- final_commit(cc);
- }
+ end_of_options(cc);
cc->other_options++;
return res;
}
{
if (!cc->need_journal)
return;
- if (!cc->postpone_commit)
- return;
struct conf_entry *ce = cf_malloc(sizeof(*ce));
ce->type = type;
ce->arg = cf_strdup(arg);
clist old_entries;
clist_move(&old_entries, &cc->conf_entries);
- cc->postpone_commit = 1;
+ cf_open_group();
int err = 0;
if (file)
cf_remember_entry(cc, ce->type, ce->arg);
}
- cc->postpone_commit = 0;
- if (!err)
- err |= cf_done_stack(cc);
+ err |= cf_close_group();
if (!err) {
cf_journal_delete();
int is_active;
int config_loaded; // at least one config file was loaded
struct cf_parser_state *parser;
- uns everything_committed; // after the 1st load, this flag is set on
- uns postpone_commit; // used internally by cf_getopt()
- uns other_options;
+ uns everything_committed; // did we already commit each section?
+ uns postpone_commit; // counter of calls to cf_open_group()
+ uns other_options; // used internally by cf_getopt()
clist conf_entries; // files/strings to reload
- struct old_pools *pools;
- struct cf_journal_item *journal;
+ struct cf_journal_item *journal; // journalling
int need_journal;
+ struct old_pools *pools;
struct item_stack stack[MAX_STACK_SIZE]; // interpreter stack
uns stack_level;
struct cf_section sections; // root section
cf_done_stack(struct cf_context *cc)
{
if (cc->stack_level > 0) {
- msg(L_ERROR, "Unterminated block");
+ msg(L_ERROR, "Unterminated block"); // FIXME: Where?
return 1;
}
if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL))
cc->everything_committed = 1;
return 0;
}
+
+void
+cf_open_group(void)
+{
+ struct cf_context *cc = cf_get_context();
+ cc->postpone_commit++;
+}
+
+int
+cf_close_group(void)
+{
+ struct cf_context *cc = cf_get_context();
+ ASSERT(cc->postpone_commit);
+ if (!--cc->postpone_commit)
+ return cf_done_stack(cc);
+ else
+ return 0;
+}
* These functions can be used to to safely load or reload configuration.
*/
-int cf_reload(const char *file); /** Reload configuration from @file, replace the old one. **/
-int cf_load(const char *file); /** Load configuration from @file. If @file is NULL, reload all loaded configuration files. **/
+/**
+ * Load configuration from @file.
+ * Returns a non-zero value upon error. In that case, all changes to the
+ * configuration specified in the file are undone.
+ **/
+int cf_load(const char *file);
+/**
+ * Reload configuration from @file, replace the old one.
+ * If @file is NULL, reload all loaded configuration files and re-apply
+ * bits of configuration passed to cf_set().
+ * Returns a non-zero value upon error. In that case, all configuration
+ * settings are rolled back to the state before calling this function.
+ **/
+int cf_reload(const char *file);
/**
* Parse some part of configuration passed in @string.
* The syntax is the same as in the <<config:,configuration file>>.
+ * Returns a non-zero value upon error. In that case, all changes to the
+ * configuration specified by the already executed parts of the string
+ * are undone.
**/
int cf_set(const char *string);
+/**
+ * Sometimes, the configuration is split to multiple files and when only
+ * some of the are loaded, the settings are not consistent -- for example,
+ * they might have been rejected by a commit hook, because a mandatory setting
+ * is missing.
+ *
+ * This function opens a configuration group, in which multiple files can be
+ * loaded and all commit hooks are deferred until the group is closed.
+ **/
+void cf_open_group(void);
+
+/**
+ * Close a group opened by cf_open_group(). Returns a non-zero value upon error,
+ * which usually means that a commit hook has failed.
+ **/
+int cf_close_group(void);
+
/*** === Data types [[conf_types]] ***/
enum cf_class { /** Class of the configuration item. **/