summaryrefslogtreecommitdiff
path: root/lib/config/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/config/config.c')
-rw-r--r--lib/config/config.c1322
1 files changed, 216 insertions, 1106 deletions
diff --git a/lib/config/config.c b/lib/config/config.c
index 72908f2..00bfcab 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -13,1149 +13,325 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "lib.h"
+
#include "config.h"
#include "crc.h"
#include "device.h"
#include "str_list.h"
#include "toolcontext.h"
-#include "lvm-string.h"
#include "lvm-file.h"
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
-#include <ctype.h>
-
-#define SECTION_B_CHAR '{'
-#define SECTION_E_CHAR '}'
-
-enum {
- TOK_INT,
- TOK_FLOAT,
- TOK_STRING, /* Single quotes */
- TOK_STRING_ESCAPED, /* Double quotes */
- TOK_EQ,
- TOK_SECTION_B,
- TOK_SECTION_E,
- TOK_ARRAY_B,
- TOK_ARRAY_E,
- TOK_IDENTIFIER,
- TOK_COMMA,
- TOK_EOF
-};
-
-struct parser {
- const char *fb, *fe; /* file limits */
-
- int t; /* token limits and type */
- const char *tb, *te;
-
- int fd; /* descriptor for file being parsed */
- int line; /* line number we are on */
-
- struct dm_pool *mem;
-};
+#include <assert.h>
-struct cs {
- struct config_tree cft;
- struct dm_pool *mem;
+struct config_file {
time_t timestamp;
+ off_t st_size;
char *filename;
int exists;
int keep_open;
struct device *dev;
};
-struct output_line {
- FILE *fp;
- struct dm_pool *mem;
- putline_fn putline;
- void *putline_baton;
-};
-
-static void _get_token(struct parser *p, int tok_prev);
-static void _eat_space(struct parser *p);
-static struct config_node *_file(struct parser *p);
-static struct config_node *_section(struct parser *p);
-static struct config_value *_value(struct parser *p);
-static struct config_value *_type(struct parser *p);
-static int _match_aux(struct parser *p, int t);
-static struct config_value *_create_value(struct dm_pool *mem);
-static struct config_node *_create_node(struct dm_pool *mem);
-static char *_dup_tok(struct parser *p);
-
-static const int sep = '/';
-
-#define MAX_INDENT 32
-
-#define match(t) do {\
- if (!_match_aux(p, (t))) {\
- log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
- p->tb - p->fb + 1, p->line); \
- return 0;\
- } \
-} while(0);
-
-static int _tok_match(const char *str, const char *b, const char *e)
-{
- while (*str && (b != e)) {
- if (*str++ != *b++)
- return 0;
- }
-
- return !(*str || (b != e));
-}
-
/*
* public interface
*/
-struct config_tree *create_config_tree(const char *filename, int keep_open)
-{
- struct cs *c;
- struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
-
- if (!mem) {
- log_error("Failed to allocate config pool.");
- return 0;
- }
-
- if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
- log_error("Failed to allocate config tree.");
- dm_pool_destroy(mem);
- return 0;
- }
-
- c->mem = mem;
- c->cft.root = (struct config_node *) NULL;
- c->timestamp = 0;
- c->exists = 0;
- c->keep_open = keep_open;
- c->dev = 0;
- if (filename)
- c->filename = dm_pool_strdup(c->mem, filename);
- return &c->cft;
-}
-
-void destroy_config_tree(struct config_tree *cft)
-{
- struct cs *c = (struct cs *) cft;
-
- if (c->dev)
- dev_close(c->dev);
-
- dm_pool_destroy(c->mem);
-}
-
-static int _parse_config_file(struct parser *p, struct config_tree *cft)
-{
- p->tb = p->te = p->fb;
- p->line = 1;
- _get_token(p, TOK_SECTION_E);
- if (!(cft->root = _file(p)))
- return_0;
-
- return 1;
-}
-
-struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute__((unused)),
- const char *config_settings)
+struct dm_config_tree *config_file_open(const char *filename, int keep_open)
{
- struct cs *c;
- struct config_tree *cft;
- struct parser *p;
-
- if (!(cft = create_config_tree(NULL, 0)))
- return_NULL;
-
- c = (struct cs *) cft;
- if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
- log_error("Failed to allocate config tree parser.");
- destroy_config_tree(cft);
+ struct dm_config_tree *cft = dm_config_create();
+ struct config_file *cf;
+ if (!cft)
return NULL;
- }
- p->mem = c->mem;
- p->fb = config_settings;
- p->fe = config_settings + strlen(config_settings);
+ cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file));
+ if (!cf) goto fail;
- if (!_parse_config_file(p, cft)) {
- destroy_config_tree(cft);
- return_NULL;
- }
-
- return cft;
-}
+ cf->timestamp = 0;
+ cf->exists = 0;
+ cf->keep_open = keep_open;
+ dm_config_set_custom(cft, cf);
-int override_config_tree_from_string(struct cmd_context *cmd,
- const char *config_settings)
-{
- if (!(cmd->cft_override = create_config_tree_from_string(cmd,config_settings))) {
- log_error("Failed to set overridden configuration entries.");
- return 1;
+ if (filename &&
+ !(cf->filename = dm_pool_strdup(cft->mem, filename))) {
+ log_error("Failed to duplicate filename.");
+ goto fail;
}
- return 0;
+ return cft;
+fail:
+ dm_config_destroy(cft);
+ return NULL;
}
-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)
+/*
+ * Doesn't populate filename if the file is empty.
+ */
+int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info)
{
- struct cs *c = (struct cs *) cft;
- struct parser *p;
- int r = 0;
- int use_mmap = 1;
- off_t mmap_offset = 0;
- char *buf = NULL;
+ struct config_file *cf = dm_config_get_custom(cft);
+ struct stat _info;
- if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
- return_0;
- p->mem = c->mem;
-
- /* Only use mmap with regular files */
- if (!(dev->flags & DEV_REGULAR) || size2)
- use_mmap = 0;
-
- if (use_mmap) {
- mmap_offset = offset % lvm_getpagesize();
- /* memory map the file */
- p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
- MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
- if (p->fb == (caddr_t) (-1)) {
- log_sys_error("mmap", dev_name(dev));
- goto out;
- }
- p->fb = p->fb + mmap_offset;
- } else {
- if (!(buf = dm_malloc(size + size2)))
- return_0;
- if (!dev_read_circular(dev, (uint64_t) offset, size,
- (uint64_t) offset2, size2, buf)) {
- goto out;
- }
- p->fb = buf;
- }
-
- if (checksum_fn && checksum !=
- (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)p->fb, size),
- (const uint8_t *)(p->fb + size), size2))) {
- log_error("%s: Checksum error", dev_name(dev));
- goto out;
- }
-
- p->fe = p->fb + size + size2;
-
- if (!_parse_config_file(p, cft))
- goto_out;
-
- r = 1;
+ if (!info)
+ info = &_info;
- out:
- if (!use_mmap)
- dm_free(buf);
- else {
- /* unmap the file */
- if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
- log_sys_error("munmap", dev_name(dev));
- r = 0;
- }
- }
-
- return r;
-}
-
-int read_config_file(struct config_tree *cft)
-{
- struct cs *c = (struct cs *) cft;
- struct stat info;
- int r = 1;
-
- if (stat(c->filename, &info)) {
- log_sys_error("stat", c->filename);
- c->exists = 0;
+ if (stat(cf->filename, info)) {
+ log_sys_error("stat", cf->filename);
+ cf->exists = 0;
return 0;
}
- if (!S_ISREG(info.st_mode)) {
- log_error("%s is not a regular file", c->filename);
- c->exists = 0;
+ if (!S_ISREG(info->st_mode)) {
+ log_error("%s is not a regular file", cf->filename);
+ cf->exists = 0;
return 0;
}
- c->exists = 1;
-
- if (info.st_size == 0) {
- log_verbose("%s is empty", c->filename);
- return 1;
- }
-
- if (!c->dev) {
- if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
- return_0;
+ cf->exists = 1;
+ cf->timestamp = info->st_ctime;
+ cf->st_size = info->st_size;
- if (!dev_open_flags(c->dev, O_RDONLY, 0, 0)) {
- c->dev = 0;
- return_0;
- }
- }
-
- r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
- (checksum_fn_t) NULL, 0);
-
- if (!c->keep_open) {
- dev_close(c->dev);
- c->dev = 0;
- }
+ if (info->st_size == 0)
+ log_verbose("%s is empty", cf->filename);
+ else if (filename)
+ *filename = cf->filename;
- c->timestamp = info.st_ctime;
-
- return r;
-}
-
-time_t config_file_timestamp(struct config_tree *cft)
-{
- struct cs *c = (struct cs *) cft;
-
- return c->timestamp;
+ return 1;
}
/*
* Return 1 if config files ought to be reloaded
*/
-int config_file_changed(struct config_tree *cft)
+int config_file_changed(struct dm_config_tree *cft)
{
- struct cs *c = (struct cs *) cft;
+ struct config_file *cf = dm_config_get_custom(cft);
struct stat info;
- if (!c->filename)
+ if (!cf->filename)
return 0;
- if (stat(c->filename, &info) == -1) {
+ if (stat(cf->filename, &info) == -1) {
/* Ignore a deleted config file: still use original data */
if (errno == ENOENT) {
- if (!c->exists)
+ if (!cf->exists)
return 0;
log_very_verbose("Config file %s has disappeared!",
- c->filename);
+ cf->filename);
goto reload;
}
- log_sys_error("stat", c->filename);
+ log_sys_error("stat", cf->filename);
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);
+ cf->filename);
goto reload;
}
/* Unchanged? */
- if (c->timestamp == info.st_ctime)
+ if (cf->timestamp == info.st_ctime && cf->st_size == info.st_size)
return 0;
reload:
- log_verbose("Detected config file change to %s", c->filename);
+ log_verbose("Detected config file change to %s", cf->filename);
return 1;
}
-static int _line_start(struct output_line *outline)
+void config_file_destroy(struct dm_config_tree *cft)
{
- if (!dm_pool_begin_object(outline->mem, 128)) {
- log_error("dm_pool_begin_object failed for config line");
- return 0;
- }
+ struct config_file *cf = dm_config_get_custom(cft);
- return 1;
+ if (cf && cf->dev)
+ if (!dev_close(cf->dev))
+ stack;
+
+ dm_config_destroy(cft);
}
-static int _line_append(struct output_line *outline, const char *fmt, ...)
- __attribute__ ((format(printf, 2, 3)));
-static int _line_append(struct output_line *outline, const char *fmt, ...)
+/*
+ * Returns config tree if it was removed.
+ */
+struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd)
{
- char buf[4096];
- va_list ap;
- int n;
-
- va_start(ap, fmt);
- n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
- va_end(ap);
+ struct dm_config_tree *old_cft = cmd->cft;
+ struct dm_config_tree *cft = dm_config_remove_cascaded_tree(cmd->cft);
- if (n < 0 || n > (int) sizeof buf - 1) {
- log_error("vsnprintf failed for config line");
- return 0;
- }
+ if (!cft)
+ return NULL;
- if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
- log_error("dm_pool_grow_object failed for config line");
- return 0;
- }
+ cmd->cft = cft;
- return 1;
+ return old_cft;
}
-#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
-
-static int _line_end(struct output_line *outline)
+int override_config_tree_from_string(struct cmd_context *cmd,
+ const char *config_settings)
{
- const char *line;
+ struct dm_config_tree *cft_new;
- if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
- log_error("dm_pool_grow_object failed for config line");
- return 0;
+ if (!(cft_new = dm_config_from_string(config_settings))) {
+ log_error("Failed to set overridden configuration entries.");
+ return 1;
}
- line = dm_pool_end_object(outline->mem);
- if (outline->putline)
- outline->putline(line, outline->putline_baton);
- else {
- if (!outline->fp)
- log_print("%s", line);
- else
- fprintf(outline->fp, "%s\n", line);
- }
+ cmd->cft = dm_config_insert_cascaded_tree(cft_new, cmd->cft);
- return 1;
+ return 0;
}
-static int _write_value(struct output_line *outline, const struct config_value *v)
+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,
+ checksum_fn_t checksum_fn, uint32_t checksum)
{
- char *buf;
+ char *fb, *fe;
+ int r = 0;
+ int use_mmap = 1;
+ off_t mmap_offset = 0;
+ char *buf = NULL;
- switch (v->type) {
- case CFG_STRING:
- if (!(buf = alloca(escaped_len(v->v.str)))) {
- log_error("temporary stack allocation for a config "
- "string failed");
+ /* Only use mmap with regular files */
+ if (!(dev->flags & DEV_REGULAR) || size2)
+ use_mmap = 0;
+
+ if (use_mmap) {
+ mmap_offset = offset % lvm_getpagesize();
+ /* memory map the file */
+ fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
+ MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
+ if (fb == (caddr_t) (-1)) {
+ log_sys_error("mmap", dev_name(dev));
+ goto out;
+ }
+ fb = fb + mmap_offset;
+ } else {
+ if (!(buf = dm_malloc(size + size2))) {
+ log_error("Failed to allocate circular buffer.");
return 0;
}
- line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
- break;
-
- case CFG_FLOAT:
- line_append("%f", v->v.r);
- break;
-
- case CFG_INT:
- line_append("%" PRId64, v->v.i);
- break;
-
- case CFG_EMPTY_ARRAY:
- line_append("[]");
- break;
-
- default:
- log_error("_write_value: Unknown value type: %d", v->type);
-
- }
-
- return 1;
-}
-
-static int _write_config(const struct config_node *n, int only_one,
- struct output_line *outline, int level)
-{
- char space[MAX_INDENT + 1];
- int l = (level < MAX_INDENT) ? level : MAX_INDENT;
- int i;
-
- if (!n)
- return 1;
-
- for (i = 0; i < l; i++)
- space[i] = '\t';
- space[i] = '\0';
-
- do {
- if (!_line_start(outline))
- return_0;
- line_append("%s%s", space, n->key);
- if (!n->v) {
- /* it's a sub section */
- line_append(" {");
- if (!_line_end(outline))
- return_0;
- _write_config(n->child, 0, outline, level + 1);
- if (!_line_start(outline))
- return_0;
- line_append("%s}", space);
- } else {
- /* it's a value */
- const struct config_value *v = n->v;
- line_append("=");
- if (v->next) {
- line_append("[");
- while (v) {
- if (!_write_value(outline, v))
- return_0;
- v = v->next;
- if (v)
- line_append(", ");
- }
- line_append("]");
- } else
- if (!_write_value(outline, v))
- return_0;
+ if (!dev_read_circular(dev, (uint64_t) offset, size,
+ (uint64_t) offset2, size2, buf)) {
+ goto out;
}
- if (!_line_end(outline))
- return_0;
- n = n->sib;
- } while (n && !only_one);
- /* FIXME: add error checking */
- return 1;
-}
-
-int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
-{
- struct output_line outline;
- outline.fp = NULL;
- if (!(outline.mem = dm_pool_create("config_line", 1024)))
- return_0;
- outline.putline = putline;
- outline.putline_baton = baton;
- if (!_write_config(cn, 0, &outline, 0)) {
- dm_pool_destroy(outline.mem);
- return_0;
+ fb = buf;
}
- dm_pool_destroy(outline.mem);
- return 1;
-}
-int write_config_file(struct config_tree *cft, const char *file,
- int argc, char **argv)
-{
- const struct config_node *cn;
- int r = 1;
- struct output_line outline;
- outline.fp = NULL;
- outline.putline = NULL;
-
- if (!file)
- file = "stdout";
- else if (!(outline.fp = fopen(file, "w"))) {
- log_sys_error("open", file);
- return 0;
+ if (checksum_fn && checksum !=
+ (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
+ (const uint8_t *)(fb + size), size2))) {
+ log_error("%s: Checksum error", dev_name(dev));
+ goto out;
}
- if (!(outline.mem = dm_pool_create("config_line", 1024))) {
- r = 0;
+ fe = fb + size + size2;
+ if (!dm_config_parse(cft, fb, fe))
goto_out;
- }
- log_verbose("Dumping configuration to %s", file);
- if (!argc) {
- if (!_write_config(cft->root, 0, &outline, 0)) {
- log_error("Failure while writing to %s", file);
- r = 0;
- }
- } else while (argc--) {
- if ((cn = find_config_node(cft->root, *argv))) {
- if (!_write_config(cn, 1, &outline, 0)) {
- log_error("Failure while writing to %s", file);
- r = 0;
- }
- } else {
- log_error("Configuration node %s not found", *argv);
+ r = 1;
+
+ out:
+ if (!use_mmap)
+ dm_free(buf);
+ else {
+ /* unmap the file */
+ if (munmap(fb - mmap_offset, size + mmap_offset)) {
+ log_sys_error("munmap", dev_name(dev));
r = 0;
}
- argv++;
- }
-
- dm_pool_destroy(outline.mem);
-
-out:
- if (outline.fp && lvm_fclose(outline.fp, file)) {
- stack;
- r = 0;
}
return r;
}
-/*
- * parser
- */
-static struct config_node *_file(struct parser *p)
-{
- struct config_node *root = NULL, *n, *l = NULL;
- while (p->t != TOK_EOF) {
- if (!(n = _section(p)))
- return_0;
-
- if (!root)
- root = n;
- else
- l->sib = n;
- n->parent = root;
- l = n;
- }
- return root;
-}
-
-static struct config_node *_section(struct parser *p)
+int config_file_read(struct dm_config_tree *cft)
{
- /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
- struct config_node *root, *n, *l = NULL;
- if (!(root = _create_node(p->mem)))
- return_0;
+ const char *filename = NULL;
+ struct config_file *cf = dm_config_get_custom(cft);
+ struct stat info;
+ int r;
- if (!(root->key = _dup_tok(p)))
+ if (!config_file_check(cft, &filename, &info))
return_0;
- match(TOK_IDENTIFIER);
-
- if (p->t == TOK_SECTION_B) {
- match(TOK_SECTION_B);
- while (p->t != TOK_SECTION_E) {
- if (!(n = _section(p)))
- return_0;
-
- if (!root->child)
- root->child = n;
- else
- l->sib = n;
- n->parent = root;
- l = n;
- }
- match(TOK_SECTION_E);
- } else {
- match(TOK_EQ);
- if (!(root->v = _value(p)))
- return_0;
- }
-
- return root;
-}
-
-static struct config_value *_value(struct parser *p)
-{
- /* '[' TYPE* ']' | TYPE */
- struct config_value *h = NULL, *l, *ll = NULL;
- if (p->t == TOK_ARRAY_B) {
- match(TOK_ARRAY_B);
- while (p->t != TOK_ARRAY_E) {
- if (!(l = _type(p)))
- return_0;
-
- if (!h)
- h = l;
- else
- ll->next = l;
- ll = l;
-
- if (p->t == TOK_COMMA)
- match(TOK_COMMA);
- }
- match(TOK_ARRAY_E);
- /*
- * Special case for an empty array.
- */
- if (!h) {
- if (!(h = _create_value(p->mem)))
- return NULL;
-
- h->type = CFG_EMPTY_ARRAY;
- }
-
- } else
- h = _type(p);
-
- return h;
-}
-
-static struct config_value *_type(struct parser *p)
-{
- /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
- struct config_value *v = _create_value(p->mem);
- char *str;
-
- if (!v)
- return NULL;
-
- switch (p->t) {
- case TOK_INT:
- v->type = CFG_INT;
- v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
- match(TOK_INT);
- break;
-
- case TOK_FLOAT:
- v->type = CFG_FLOAT;
- v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
- match(TOK_FLOAT);
- break;
-
- case TOK_STRING:
- v->type = CFG_STRING;
+ /* Nothing to do. E.g. empty file. */
+ if (!filename)
+ return 1;
- p->tb++, p->te--; /* strip "'s */
- if (!(v->v.str = _dup_tok(p)))
+ if (!cf->dev) {
+ if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
return_0;
- p->te++;
- match(TOK_STRING);
- break;
- case TOK_STRING_ESCAPED:
- v->type = CFG_STRING;
-
- p->tb++, p->te--; /* strip "'s */
- if (!(str = _dup_tok(p)))
+ if (!dev_open_readonly_buffered(cf->dev))
return_0;
- unescape_double_quotes(str);
- v->v.str = str;
- p->te++;
- match(TOK_STRING_ESCAPED);
- break;
-
- default:
- log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
- p->tb - p->fb + 1, p->line);
- return 0;
}
- return v;
-}
-
-static int _match_aux(struct parser *p, int t)
-{
- if (p->t != t)
- return 0;
-
- _get_token(p, t);
- return 1;
-}
-
-/*
- * tokeniser
- */
-static void _get_token(struct parser *p, int tok_prev)
-{
- int values_allowed = 0;
-
- const char *te;
-
- p->tb = p->te;
- _eat_space(p);
- if (p->tb == p->fe || !*p->tb) {
- p->t = TOK_EOF;
- return;
- }
-
- /* Should next token be interpreted as value instead of identifier? */
- if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
- tok_prev == TOK_COMMA)
- values_allowed = 1;
-
- p->t = TOK_INT; /* fudge so the fall through for
- floats works */
-
- te = p->te;
- switch (*te) {
- case SECTION_B_CHAR:
- p->t = TOK_SECTION_B;
- te++;
- break;
-
- case SECTION_E_CHAR:
- p->t = TOK_SECTION_E;
- te++;
- break;
-
- case '[':
- p->t = TOK_ARRAY_B;
- te++;
- break;
-
- case ']':
- p->t = TOK_ARRAY_E;
- te++;
- break;
-
- case ',':
- p->t = TOK_COMMA;
- te++;
- break;
-
- case '=':
- p->t = TOK_EQ;
- te++;
- break;
-
- case '"':
- p->t = TOK_STRING_ESCAPED;
- te++;
- while ((te != p->fe) && (*te) && (*te != '"')) {
- if ((*te == '\\') && (te + 1 != p->fe) &&
- *(te + 1))
- te++;
- te++;
- }
-
- if ((te != p->fe) && (*te))
- te++;
- break;
-
- case '\'':
- p->t = TOK_STRING;
- te++;
- while ((te != p->fe) && (*te) && (*te != '\''))
- te++;
-
- if ((te != p->fe) && (*te))
- te++;
- break;
-
- case '.':
- p->t = TOK_FLOAT;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '+':
- case '-':
- if (values_allowed) {
- te++;
- while ((te != p->fe) && (*te)) {
- if (*te == '.') {
- if (p->t == TOK_FLOAT)
- break;
- p->t = TOK_FLOAT;
- } else if (!isdigit((int) *te))
- break;
- te++;
- }
- break;
- }
-
- default:
- p->t = TOK_IDENTIFIER;
- while ((te != p->fe) && (*te) && !isspace(*te) &&
- (*te != '#') && (*te != '=') &&
- (*te != SECTION_B_CHAR) &&
- (*te != SECTION_E_CHAR))
- te++;
- break;
- }
-
- p->te = te;
-}
-
-static void _eat_space(struct parser *p)
-{
- while ((p->tb != p->fe) && (*p->tb)) {
- if (*p->te == '#')
- while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
- p->te++;
-
- else if (isspace(*p->te)) {
- while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
- if (*p->te == '\n')
- p->line++;
- p->te++;
- }
- }
- else
- return;
+ r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
+ (checksum_fn_t) NULL, 0);
- p->tb = p->te;
+ if (!cf->keep_open) {
+ if (!dev_close(cf->dev))
+ stack;
+ cf->dev = NULL;
}
-}
-/*
- * memory management
- */
-static struct config_value *_create_value(struct dm_pool *mem)
-{
- return dm_pool_zalloc(mem, sizeof(struct config_value));
+ return r;
}
-static struct config_node *_create_node(struct dm_pool *mem)
+time_t config_file_timestamp(struct dm_config_tree *cft)
{
- return dm_pool_zalloc(mem, sizeof(struct config_node));
+ struct config_file *cf = dm_config_get_custom(cft);
+ assert(cf);
+ return cf->timestamp;
}
-static char *_dup_tok(struct parser *p)
-{
- size_t len = p->te - p->tb;
- char *str = dm_pool_alloc(p->mem, len + 1);
- if (!str)
- return_0;
- strncpy(str, p->tb, len);
- str[len] = '\0';
- return str;
-}
-
-/*
- * utility functions
- */
-static const struct config_node *_find_config_node(const struct config_node *cn,
+const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd,
const char *path)
{
- const char *e;
- const struct config_node *cn_found = NULL;
-
- while (cn) {
- /* trim any leading slashes */
- while (*path && (*path == sep))
- path++;
-
- /* find the end of this segment */
- for (e = path; *e && (*e != sep); e++) ;
-
- /* hunt for the node */
- cn_found = NULL;
- while (cn) {
- if (_tok_match(cn->key, path, e)) {
- /* Inefficient */
- if (!cn_found)
- cn_found = cn;
- else
- log_warn("WARNING: Ignoring duplicate"
- " config node: %s ("
- "seeking %s)", cn->key, path);
- }
-
- cn = cn->sib;
- }
-
- if (cn_found && *e)
- cn = cn_found->child;
- else
- break; /* don't move into the last node */
-
- path = e;
- }
-
- return cn_found;
-}
-
-static const struct config_node *_find_first_config_node(const struct config_node *cn1,
- const struct config_node *cn2,
- const char *path)
-{
- const struct config_node *cn;
-
- if (cn1 && (cn = _find_config_node(cn1, path)))
- return cn;
-
- if (cn2 && (cn = _find_config_node(cn2, path)))
- return cn;
-
- return NULL;
-}
-
-const struct config_node *find_config_node(const struct config_node *cn,
- const char *path)
-{
- return _find_config_node(cn, path);
-}
-
-static const char *_find_config_str(const struct config_node *cn1,
- const struct config_node *cn2,
- const char *path, const char *fail)
-{
- const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
- /* Empty strings are ignored */
- if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
- log_very_verbose("Setting %s to %s", path, n->v->v.str);
- return n->v->v.str;
- }
-
- if (fail)
- log_very_verbose("%s not found in config: defaulting to %s",
- path, fail);
- return fail;
-}
-
-const char *find_config_str(const struct config_node *cn,
- const char *path, const char *fail)
-{
- return _find_config_str(cn, NULL, path, fail);
-}
-
-static int64_t _find_config_int64(const struct config_node *cn1,
- const struct config_node *cn2,
- const char *path, int64_t fail)
-{
- const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
- if (n && n->v && n->v->type == CFG_INT) {
- log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
- return n->v->v.i;
- }
-
- log_very_verbose("%s not found in config: defaulting to %" PRId64,
- path, fail);
- return fail;
-}
-
-int find_config_int(const struct config_node *cn, const char *path, int fail)
-{
- /* FIXME Add log_error message on overflow */
- return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
-}
-
-static float _find_config_float(const struct config_node *cn1,
- const struct config_node *cn2,
- const char *path, float fail)
-{
- const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
- if (n && n->v && n->v->type == CFG_FLOAT) {
- log_very_verbose("Setting %s to %f", path, n->v->v.r);
- return n->v->v.r;
- }
-
- log_very_verbose("%s not found in config: defaulting to %f",
- path, fail);
-
- return fail;
-
-}
-
-float find_config_float(const struct config_node *cn, const char *path,
- float fail)
-{
- return _find_config_float(cn, NULL, path, fail);
-}
-
-const struct config_node *find_config_tree_node(struct cmd_context *cmd,
- const char *path)
-{
- return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, 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 _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, 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)
+const char *find_config_tree_str_allow_empty(struct cmd_context *cmd,
+ const char *path, const char *fail)
{
- /* FIXME Add log_error message on overflow */
- return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
+ return dm_config_tree_find_str_allow_empty(cmd->cft, path, fail);
}
-float find_config_tree_float(struct cmd_context *cmd, const char *path,
- float fail)
-{
- return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-static int _str_in_array(const char *str, const char * const values[])
-{
- int i;
-
- for (i = 0; values[i]; i++)
- if (!strcasecmp(str, values[i]))
- return 1;
-
- return 0;
-}
-
-static int _str_to_bool(const char *str, int fail)
+int find_config_tree_int(struct cmd_context *cmd, const char *path,
+ int fail)
{
- const char * const _true_values[] = { "y", "yes", "on", "true", NULL };
- const char * const _false_values[] = { "n", "no", "off", "false", NULL };
-
- if (_str_in_array(str, _true_values))
- return 1;
-
- if (_str_in_array(str, _false_values))
- return 0;
-
- return fail;
+ return dm_config_tree_find_int(cmd->cft, path, fail);
}
-static int _find_config_bool(const struct config_node *cn1,
- const struct config_node *cn2,
- const char *path, int fail)
+int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail)
{
- const struct config_node *n = _find_first_config_node(cn1, cn2, path);
- const struct config_value *v;
-
- if (!n)
- return fail;
-
- v = n->v;
-
- switch (v->type) {
- case CFG_INT:
- return v->v.i ? 1 : 0;
-
- case CFG_STRING:
- return _str_to_bool(v->v.str, fail);
- }
-
- return fail;
+ return dm_config_tree_find_int64(cmd->cft, path, fail);
}
-int find_config_bool(const struct config_node *cn, const char *path, int fail)
+float find_config_tree_float(struct cmd_context *cmd, const char *path,
+ float fail)
{
- return _find_config_bool(cn, NULL, 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 _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-int get_config_uint32(const struct config_node *cn, const char *path,
- uint32_t *result)
-{
- const struct config_node *n;
-
- n = find_config_node(cn, path);
-
- if (!n || !n->v || n->v->type != CFG_INT)
- return 0;
-
- *result = n->v->v.i;
- return 1;
-}
-
-int get_config_uint64(const struct config_node *cn, const char *path,
- uint64_t *result)
-{
- const struct config_node *n;
-
- n = find_config_node(cn, path);
-
- if (!n || !n->v || n->v->type != CFG_INT)
- return 0;
-
- *result = (uint64_t) n->v->v.i;
- return 1;
-}
-
-int get_config_str(const struct config_node *cn, const char *path,
- const char **result)
-{
- const struct config_node *n;
-
- n = find_config_node(cn, path);
-
- if (!n || !n->v || n->v->type != CFG_STRING)
- return 0;
-
- *result = n->v->v.str;
- return 1;
+ return dm_config_tree_find_bool(cmd->cft, path, fail);
}
/* Insert cn2 after cn1 */
-static void _insert_config_node(struct config_node **cn1,
- struct config_node *cn2)
+static void _insert_config_node(struct dm_config_node **cn1,
+ struct dm_config_node *cn2)
{
if (!*cn1) {
*cn1 = cn2;
@@ -1170,10 +346,10 @@ static void _insert_config_node(struct config_node **cn1,
* 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)
+static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2)
{
- struct config_node *cn, *nextn, *oldn;
- struct config_value *cv;
+ struct dm_config_node *cn, *nextn, *oldn;
+ struct dm_config_value *cv;
for (cn = cn2->child; cn; cn = nextn) {
nextn = cn->sib;
@@ -1187,7 +363,7 @@ static void _merge_section(struct config_node *cn1, struct config_node *cn2)
/* Ignore - we don't have any of these yet */
continue;
/* Not already present? */
- if (!(oldn = (struct config_node*)find_config_node(cn1->child, cn->key))) {
+ if (!(oldn = dm_config_find_node(cn1->child, cn->key))) {
_insert_config_node(&cn1->child, cn);
continue;
}
@@ -1207,13 +383,13 @@ static void _merge_section(struct config_node *cn1, struct config_node *cn2)
}
}
-static int _match_host_tags(struct dm_list *tags, const struct config_node *tn)
+static int _match_host_tags(struct dm_list *tags, const struct dm_config_node *tn)
{
- const struct config_value *tv;
+ const struct dm_config_value *tv;
const char *str;
for (tv = tn->v; tv; tv = tv->next) {
- if (tv->type != CFG_STRING)
+ if (tv->type != DM_CFG_STRING)
continue;
str = tv->v.str;
if (*str == '@')
@@ -1228,12 +404,12 @@ static int _match_host_tags(struct dm_list *tags, const struct config_node *tn)
}
/* 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)
+int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
+ struct dm_config_tree *newdata)
{
- const struct config_node *root = cft->root;
- struct config_node *cn, *nextn, *oldn, *cn2;
- const struct config_node *tn;
+ struct dm_config_node *root = cft->root;
+ struct dm_config_node *cn, *nextn, *oldn, *cn2;
+ const struct dm_config_node *tn;
for (cn = newdata->root; cn; cn = nextn) {
nextn = cn->sib;
@@ -1241,11 +417,11 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
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 ((tn = dm_config_find_node(cn->child, "tags"))) {
if (!_match_host_tags(&cmd->tags, tn))
continue;
}
- if (!(oldn = (struct config_node *)find_config_node(root, cn->key))) {
+ if (!(oldn = dm_config_find_node(root, cn->key))) {
_insert_config_node(&cft->root, cn);
/* Remove any "tags" nodes */
for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
@@ -1266,117 +442,51 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
return 1;
}
-/*
- * Convert a token type to the char it represents.
- */
-static char _token_type_to_char(int type)
-{
- switch (type) {
- case TOK_SECTION_B:
- return SECTION_B_CHAR;
- case TOK_SECTION_E:
- return SECTION_E_CHAR;
- default:
- return 0;
- }
-}
-
-/*
- * Returns:
- * # of 'type' tokens in 'str'.
- */
-static unsigned _count_tokens(const char *str, unsigned len, int type)
-{
- char c;
-
- c = _token_type_to_char(type);
-
- return count_chars(str, len, c);
-}
+static int _putline_fn(const char *line, void *baton) {
+ FILE *fp = baton;
+ fprintf(fp, "%s\n", line);
+ return 1;
+};
-const char *config_parent_name(const struct config_node *n)
+int config_write(struct dm_config_tree *cft, const char *file,
+ int argc, char **argv)
{
- return (n->parent ? n->parent->key : "(root)");
-}
-/*
- * Heuristic function to make a quick guess as to whether a text
- * region probably contains a valid config "section". (Useful for
- * scanning areas of the disk for old metadata.)
- * Config sections contain various tokens, may contain other sections
- * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
- * end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
- * count the number of begin and end tokens, and see if they are
- * non-zero and the counts match.
- * Full validation of the section should be done with another function
- * (for example, read_config_fd).
- *
- * Returns:
- * 0 - probably is not a valid config section
- * 1 - probably _is_ a valid config section
- */
-unsigned maybe_config_section(const char *str, unsigned len)
-{
- int begin_count;
- int end_count;
-
- begin_count = _count_tokens(str, len, TOK_SECTION_B);
- end_count = _count_tokens(str, len, TOK_SECTION_E);
+ const struct dm_config_node *cn;
+ int r = 1;
+ FILE *fp = NULL;
- if (begin_count && end_count && (begin_count == end_count))
- return 1;
- else
+ if (!file) {
+ fp = stdout;
+ file = "stdout";
+ } else if (!(fp = fopen(file, "w"))) {
+ log_sys_error("open", file);
return 0;
-}
-
-static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
-{
- struct config_value *new_cv;
-
- if (!v)
- return NULL;
-
- if (!(new_cv = _create_value(mem))) {
- log_error("Failed to clone config value.");
- return NULL;
}
- new_cv->type = v->type;
- if (v->type == CFG_STRING) {
- if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
- log_error("Failed to clone config string value.");
- return NULL;
+ log_verbose("Dumping configuration to %s", file);
+ if (!argc) {
+ if (!dm_config_write_node(cft->root, _putline_fn, fp)) {
+ log_error("Failure while writing to %s", file);
+ r = 0;
}
- } else
- new_cv->v = v->v;
-
- if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
- return_NULL;
-
- return new_cv;
-}
-
-struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
- int siblings)
-{
- struct config_node *new_cn;
-
- if (!cn)
- return NULL;
-
- if (!(new_cn = _create_node(mem))) {
- log_error("Failed to clone config node.");
- return NULL;
+ } else while (argc--) {
+ if ((cn = dm_config_find_node(cft->root, *argv))) {
+ if (!dm_config_write_one_node(cn, _putline_fn, fp)) {
+ log_error("Failure while writing to %s", file);
+ r = 0;
+ }
+ } else {
+ log_error("Configuration node %s not found", *argv);
+ r = 0;
+ }
+ argv++;
}
- if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
- log_error("Failed to clone config node key.");
- return NULL;
+ if (fp && dm_fclose(fp)) {
+ stack;
+ r = 0;
}
- if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
- (cn->child && !(new_cn->child = clone_config_node(mem, cn->child, 1))) ||
- (siblings && cn->sib && !(new_cn->sib = clone_config_node(mem, cn->sib, siblings))))
- return_NULL; /* 'new_cn' released with mem pool */
-
- return new_cn;
+ return r;
}
+