From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> --- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.c | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_config.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/sanlock_helper.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/security/security_selinux.c | 2 +- src/uml/uml_conf.c | 2 +- src/util/conf.c | 1032 ------------------------------------- src/util/conf.h | 100 ---- src/util/virconf.c | 1032 +++++++++++++++++++++++++++++++++++++ src/util/virconf.h | 100 ++++ src/vmx/vmx.c | 2 +- src/vmx/vmx.h | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xm_internal.h | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_sxpr.h | 2 +- src/xenxs/xen_xm.c | 2 +- src/xenxs/xen_xm.h | 2 +- tests/conftest.c | 2 +- tests/libvirtdconftest.c | 2 +- 29 files changed, 1157 insertions(+), 1157 deletions(-) delete mode 100644 src/util/conf.c delete mode 100644 src/util/conf.h create mode 100644 src/util/virconf.c create mode 100644 src/util/virconf.h diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 7838044..0ca185c 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -24,7 +24,7 @@ #include <config.h> #include "libvirtd-config.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index f88be9b..9b0e45a 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -47,7 +47,7 @@ #include "uuid.h" #include "remote_driver.h" #include "memory.h" -#include "conf.h" +#include "virconf.h" #include "virnetlink.h" #include "virnetserver.h" #include "threads.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 843db7c..e80c413 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/conf.c src/util/dnsmasq.c src/util/event_poll.c src/util/hooks.c @@ -157,6 +156,7 @@ src/util/virauth.c src/util/virauthconfig.c src/util/vircgroup.c src/util/vircommand.c +src/util/virconf.c src/util/virdbus.c src/util/virfile.c src/util/virhash.c diff --git a/src/Makefile.am b/src/Makefile.am index 7e16d68..b53f1f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/conf.c util/conf.h \ util/event.c util/event.h \ util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virbitmap.c util/virbitmap.h \ util/virbuffer.c util/virbuffer.h \ util/vircommand.c util/vircommand.h \ + util/virconf.c util/virconf.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/libvirt.c b/src/libvirt.c index e28ed05..8f7a869 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -54,7 +54,7 @@ #include "memory.h" #include "configmake.h" #include "intprops.h" -#include "conf.h" +#include "virconf.h" #include "rpc/virnettlscontext.h" #include "vircommand.h" #include "virrandom.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1423073..884fca8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -34,7 +34,7 @@ #include "internal.h" #include "logging.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "datatypes.h" #include "virfile.h" #include "memory.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index d7906c5..08caa16 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -40,7 +40,7 @@ #include "virterror_internal.h" #include "logging.h" #include "memory.h" -#include "conf.h" +#include "virconf.h" #include "rpc/virnetserver.h" #include "virrandom.h" #include "virhash.h" diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c index c64de67..c2d9a76 100644 --- a/src/locking/lock_daemon_config.c +++ b/src/locking/lock_daemon_config.c @@ -24,7 +24,7 @@ #include <config.h> #include "lock_daemon_config.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index 3902ede..c88c5af 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -22,7 +22,7 @@ #include <config.h> #include "lock_driver.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index a072343..2eadc07 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -43,7 +43,7 @@ #include "util.h" #include "virfile.h" #include "md5.h" -#include "conf.h" +#include "virconf.h" #include "configmake.h" diff --git a/src/locking/sanlock_helper.c b/src/locking/sanlock_helper.c index a73b49c..ad69312 100644 --- a/src/locking/sanlock_helper.c +++ b/src/locking/sanlock_helper.c @@ -5,7 +5,7 @@ #include "configmake.h" #include "internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "domain_conf.h" diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index e512b8f..77667bd 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -31,7 +31,7 @@ #include "lxc_conf.h" #include "nodeinfo.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 4a8b857..7c8d826 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -42,7 +42,7 @@ #include "qemu_bridge_filter.h" #include "uuid.h" #include "virbuffer.h" -#include "conf.h" +#include "virconf.h" #include "util.h" #include "memory.h" #include "datatypes.h" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5c125fe..287312a 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -44,7 +44,7 @@ #include "virhash.h" #include "virrandom.h" #include "util.h" -#include "conf.h" +#include "virconf.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 6aec8fc..51e5a7a 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -38,7 +38,7 @@ #include "uml_conf.h" #include "uuid.h" #include "virbuffer.h" -#include "conf.h" +#include "virconf.h" #include "util.h" #include "memory.h" #include "nodeinfo.h" diff --git a/src/util/conf.c b/src/util/conf.c deleted file mode 100644 index 3b97545..0000000 --- a/src/util/conf.c +++ /dev/null @@ -1,1032 +0,0 @@ -/** - * conf.c: parser for a subset of the Python encoded Xen configuration files - * - * Copyright (C) 2006-2012 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Daniel Veillard <veillard@xxxxxxxxxx> - */ - -#include <config.h> - -#include <string.h> - -#include <stdio.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include "virterror_internal.h" -#include "virbuffer.h" -#include "conf.h" -#include "util.h" -#include "c-ctype.h" -#include "logging.h" -#include "memory.h" -#include "virfile.h" - -#define VIR_FROM_THIS VIR_FROM_CONF - -/************************************************************************ - * * - * Structures and macros used by the mini parser * - * * - ************************************************************************/ - -typedef struct _virConfParserCtxt virConfParserCtxt; -typedef virConfParserCtxt *virConfParserCtxtPtr; - -struct _virConfParserCtxt { - const char* filename; - const char* base; - const char* cur; - const char *end; - int line; - - virConfPtr conf; -}; - -#define CUR (*ctxt->cur) -#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++; -#define IS_EOL(c) (((c) == '\n') || ((c) == '\r')) - -#define SKIP_BLANKS_AND_EOL \ - do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \ - if (CUR == '\n') ctxt->line++; \ - ctxt->cur++;}} while (0) -#define SKIP_BLANKS \ - do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR))) \ - ctxt->cur++; } while (0) - -/************************************************************************ - * * - * Structures used by configuration data * - * * - ************************************************************************/ - -typedef struct _virConfEntry virConfEntry; -typedef virConfEntry *virConfEntryPtr; - -struct _virConfEntry { - virConfEntryPtr next; - char* name; - char* comment; - virConfValuePtr value; -}; - -struct _virConf { - const char* filename; - unsigned int flags; - virConfEntryPtr entries; -}; - -/** - * virConfError: - * @ctxt: the parser context if available or NULL - * @error: the error number - * @info: extra information string - * - * Handle an error at the xend daemon interface - */ -#define virConfError(ctxt, error, info) \ - virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info) -static void -virConfErrorHelper(const char *file, const char *func, size_t line, - virConfParserCtxtPtr ctxt, - virErrorNumber error, const char *info) -{ - if (error == VIR_ERR_OK) - return; - - /* Construct the string 'filename:line: info' if we have that. */ - if (ctxt && ctxt->filename) { - virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, - _("%s:%d: %s"), ctxt->filename, ctxt->line, info); - } else { - virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, - "%s", info); - } -} - - -/************************************************************************ - * * - * Structures allocations and deallocations * - * * - ************************************************************************/ - -/** - * virConfFreeList: - * @list: the list to free - * - * Free a list - */ -static void -virConfFreeList(virConfValuePtr list) -{ - virConfValuePtr next; - - while (list != NULL) { - next = list->next; - list->next = NULL; - virConfFreeValue(list); - list = next; - } -} - -/** - * virConfFreeValue: - * @val: the value to free - * - * Free a value - */ -void -virConfFreeValue(virConfValuePtr val) -{ - if (val == NULL) - return; - if (val->type == VIR_CONF_STRING && - val->str != NULL) - VIR_FREE(val->str); - if (val->type == VIR_CONF_LIST && - val->list != NULL) - virConfFreeList(val->list); - VIR_FREE(val); -} - -virConfPtr -virConfNew(void) -{ - virConfPtr ret; - - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - return NULL; - } - ret->filename = NULL; - ret->flags = 0; - - return ret; -} - -/** - * virConfCreate: - * @filename: the name to report errors - * @flags: combination of virConfFlag(s) - * - * Create a configuration internal structure - * - * Returns a pointer or NULL in case of error. - */ -static virConfPtr -virConfCreate(const char *filename, unsigned int flags) -{ - virConfPtr ret = virConfNew(); - if (ret) { - ret->filename = filename; - ret->flags = flags; - } - return ret; -} - -/** - * virConfAddEntry: - * @conf: the conf structure - * @name: name of the entry or NULL for comment - * @value: the value if any - * @comm: extra comment for that entry if any - * - * add one entry to the conf, the parameters are included in the conf - * if successful and freed on virConfFree() - * - * Returns a pointer to the entry or NULL in case of failure - */ -static virConfEntryPtr -virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm) -{ - virConfEntryPtr ret, prev; - - if (conf == NULL) - return NULL; - if ((comm == NULL) && (name == NULL)) - return NULL; - - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - return NULL; - } - - ret->name = name; - ret->value = value; - ret->comment = comm; - - if (conf->entries == NULL) { - conf->entries = ret; - } else { - prev = conf->entries; - while (prev->next != NULL) - prev = prev->next; - prev->next = ret; - } - return ret; -} - -/************************************************************************ - * * - * Serialization * - * * - ************************************************************************/ - -/** - * virConfSaveValue: - * @buf: output buffer - * @val: a value - * - * Serialize the value to the buffer - * - * Returns 0 in case of success, -1 in case of error. - */ -static int -virConfSaveValue(virBufferPtr buf, virConfValuePtr val) -{ - if (val == NULL) - return -1; - switch (val->type) { - case VIR_CONF_NONE: - return -1; - case VIR_CONF_LONG: - virBufferAsprintf(buf, "%ld", val->l); - break; - case VIR_CONF_STRING: - if (strchr(val->str, '\n') != NULL) { - virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); - } else if (strchr(val->str, '"') == NULL) { - virBufferAsprintf(buf, "\"%s\"", val->str); - } else if (strchr(val->str, '\'') == NULL) { - virBufferAsprintf(buf, "'%s'", val->str); - } else { - virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); - } - break; - case VIR_CONF_LIST: { - virConfValuePtr cur; - - cur = val->list; - virBufferAddLit(buf, "[ "); - if (cur != NULL) { - virConfSaveValue(buf, cur); - cur = cur->next; - while (cur != NULL) { - virBufferAddLit(buf, ", "); - virConfSaveValue(buf, cur); - cur = cur->next; - } - } - virBufferAddLit(buf, " ]"); - break; - } - default: - return -1; - } - return 0; -} - -/** - * virConfSaveEntry: - * @buf: output buffer - * @cur: a conf entry - * - * Serialize the entry to the buffer - * - * Returns 0 in case of success, -1 in case of error. - */ -static int -virConfSaveEntry(virBufferPtr buf, virConfEntryPtr cur) -{ - if (cur->name != NULL) { - virBufferAdd(buf, cur->name, -1); - virBufferAddLit(buf, " = "); - virConfSaveValue(buf, cur->value); - if (cur->comment != NULL) { - virBufferAddLit(buf, " #"); - virBufferAdd(buf, cur->comment, -1); - } - } else if (cur->comment != NULL) { - virBufferAddLit(buf, "#"); - virBufferAdd(buf, cur->comment, -1); - } - virBufferAddLit(buf, "\n"); - return 0; -} - -/************************************************************************ - * * - * The parser core * - * * - ************************************************************************/ - -/** - * virConfParseLong: - * @ctxt: the parsing context - * @val: the result - * - * Parse one long int value - * - * Returns 0 in case of success and -1 in case of error - */ -static int -virConfParseLong(virConfParserCtxtPtr ctxt, long *val) -{ - long l = 0; - int neg = 0; - - if (CUR == '-') { - neg = 1; - NEXT; - } else if (CUR == '+') { - NEXT; - } - if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number")); - return -1; - } - while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) { - l = l * 10 + (CUR - '0'); - NEXT; - } - if (neg) - l = -l; - *val = l; - return 0; -} - -/** - * virConfParseString: - * @ctxt: the parsing context - * - * Parse one string - * - * Returns a pointer to the string or NULL in case of error - */ -static char * -virConfParseString(virConfParserCtxtPtr ctxt) -{ - const char *base; - char *ret = NULL; - - if (CUR == '\'') { - NEXT; - base = ctxt->cur; - while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) - NEXT; - if (CUR != '\'') { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); - return NULL; - } - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - NEXT; - } else if ((ctxt->cur + 6 < ctxt->end) && - (STRPREFIX(ctxt->cur, "\"\"\""))) { - /* String starts with python-style triple quotes """ */ - ctxt->cur += 3; - base = ctxt->cur; - - /* Find the ending triple quotes */ - while ((ctxt->cur + 2 < ctxt->end) && - !(STRPREFIX(ctxt->cur, "\"\"\""))) { - if (CUR == '\n') - ctxt->line++; - NEXT; - } - - if (!STRPREFIX(ctxt->cur, "\"\"\"")) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); - return NULL; - } - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - ctxt->cur += 3; - } else if (CUR == '"') { - NEXT; - base = ctxt->cur; - while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) - NEXT; - if (CUR != '"') { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); - return NULL; - } - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - NEXT; - } - return ret; -} - -/** - * virConfParseValue: - * @ctxt: the parsing context - * - * Parse one value - * - * Returns a pointer to the value or NULL in case of error - */ -static virConfValuePtr -virConfParseValue(virConfParserCtxtPtr ctxt) -{ - virConfValuePtr ret, lst = NULL, tmp, prev; - virConfType type = VIR_CONF_NONE; - char *str = NULL; - long l = 0; - - SKIP_BLANKS; - if (ctxt->cur >= ctxt->end) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); - return NULL; - } - if ((CUR == '"') || (CUR == '\'')) { - type = VIR_CONF_STRING; - str = virConfParseString(ctxt); - if (str == NULL) - return NULL; - } else if (CUR == '[') { - if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, - _("lists not allowed in VMX format")); - return NULL; - } - type = VIR_CONF_LIST; - NEXT; - SKIP_BLANKS_AND_EOL; - if ((ctxt->cur < ctxt->end) && (CUR != ']')) { - if ((lst = virConfParseValue(ctxt)) == NULL) - return NULL; - SKIP_BLANKS_AND_EOL; - } - while ((ctxt->cur < ctxt->end) && (CUR != ']')) { - - /* Tell Clang that when execution reaches this point - "lst" is guaranteed to be non-NULL. This stops it - from issuing an invalid NULL-dereference warning about - "prev = lst; while (prev->next..." below. */ - sa_assert(lst); - - if (CUR != ',') { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, - _("expecting a separator in list")); - virConfFreeList(lst); - return NULL; - } - NEXT; - SKIP_BLANKS_AND_EOL; - if (CUR == ']') { - break; - } - tmp = virConfParseValue(ctxt); - if (tmp == NULL) { - virConfFreeList(lst); - return NULL; - } - prev = lst; - while (prev->next != NULL) prev = prev->next; - prev->next = tmp; - SKIP_BLANKS_AND_EOL; - } - if (CUR == ']') { - NEXT; - } else { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, - _("list is not closed with ]")); - virConfFreeList(lst); - return NULL; - } - } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) { - if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, - _("numbers not allowed in VMX format")); - return NULL; - } - if (virConfParseLong(ctxt, &l) < 0) { - return NULL; - } - type = VIR_CONF_LONG; - } else { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); - return NULL; - } - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - virConfFreeList(lst); - VIR_FREE(str); - return NULL; - } - ret->type = type; - ret->l = l; - ret->str = str; - ret->list = lst; - return ret; -} - -/** - * virConfParseName: - * @ctxt: the parsing context - * - * Parse one name - * - * Returns a copy of the new string, NULL in case of error - */ -static char * -virConfParseName(virConfParserCtxtPtr ctxt) -{ - const char *base; - char *ret; - - SKIP_BLANKS; - base = ctxt->cur; - /* TODO: probably need encoding support and UTF-8 parsing ! */ - if (!c_isalpha(CUR) && - !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name")); - return NULL; - } - while ((ctxt->cur < ctxt->end) && - (c_isalnum(CUR) || (CUR == '_') || - ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && - ((CUR == ':') || (CUR == '.') || (CUR == '-'))))) - NEXT; - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - return ret; -} - -/** - * virConfParseComment: - * @ctxt: the parsing context - * - * Parse one standalone comment in the configuration file - * - * Returns 0 in case of success and -1 in case of error - */ -static int -virConfParseComment(virConfParserCtxtPtr ctxt) -{ - const char *base; - char *comm; - - if (CUR != '#') - return -1; - NEXT; - base = ctxt->cur; - while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; - comm = strndup(base, ctxt->cur - base); - if (comm == NULL) { - virReportOOMError(); - return -1; - } - virConfAddEntry(ctxt->conf, NULL, NULL, comm); - return 0; -} - -/** - * virConfParseSeparator: - * @ctxt: the parsing context - * - * Parse one separator between statement if not at the end. - * - * Returns 0 in case of success and -1 in case of error - */ -static int -virConfParseSeparator(virConfParserCtxtPtr ctxt) -{ - SKIP_BLANKS; - if (ctxt->cur >= ctxt->end) - return 0; - if (IS_EOL(CUR)) { - SKIP_BLANKS_AND_EOL; - } else if (CUR == ';') { - NEXT; - SKIP_BLANKS_AND_EOL; - } else { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator")); - return -1; - } - return 0; -} - -/** - * virConfParseStatement: - * @ctxt: the parsing context - * - * Parse one statement in the conf file - * - * Returns 0 in case of success and -1 in case of error - */ -static int -virConfParseStatement(virConfParserCtxtPtr ctxt) -{ - const char *base; - char *name; - virConfValuePtr value; - char *comm = NULL; - - SKIP_BLANKS_AND_EOL; - if (CUR == '#') { - return virConfParseComment(ctxt); - } - name = virConfParseName(ctxt); - if (name == NULL) - return -1; - SKIP_BLANKS; - if (CUR != '=') { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment")); - VIR_FREE(name); - return -1; - } - NEXT; - SKIP_BLANKS; - value = virConfParseValue(ctxt); - if (value == NULL) { - VIR_FREE(name); - return -1; - } - SKIP_BLANKS; - if (CUR == '#') { - NEXT; - base = ctxt->cur; - while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; - comm = strndup(base, ctxt->cur - base); - if (comm == NULL) { - virReportOOMError(); - VIR_FREE(name); - virConfFreeValue(value); - return -1; - } - } - if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) { - VIR_FREE(name); - virConfFreeValue(value); - VIR_FREE(comm); - return -1; - } - return 0; -} - -/** - * virConfParse: - * @filename: the name to report errors - * @content: the configuration content in memory - * @len: the length in bytes - * @flags: combination of virConfFlag(s) - * - * Parse the subset of the Python language needed to handle simple - * Xen configuration files. - * - * Returns a handle to lookup settings or NULL if it failed to - * read or parse the file, use virConfFree() to free the data. - */ -static virConfPtr -virConfParse(const char *filename, const char *content, int len, - unsigned int flags) { - virConfParserCtxt ctxt; - - ctxt.filename = filename; - ctxt.base = ctxt.cur = content; - ctxt.end = content + len - 1; - ctxt.line = 1; - - ctxt.conf = virConfCreate(filename, flags); - if (ctxt.conf == NULL) - return NULL; - - while (ctxt.cur < ctxt.end) { - if (virConfParseStatement(&ctxt) < 0) - goto error; - if (virConfParseSeparator(&ctxt) < 0) - goto error; - } - - return ctxt.conf; - -error: - virConfFree(ctxt.conf); - return NULL; -} - -/************************************************************************ - * * - * The module entry points * - * * - ************************************************************************/ - -/* 10 MB limit on config file size as a sanity check */ -#define MAX_CONFIG_FILE_SIZE (1024*1024*10) - -/** - * virConfReadFile: - * @filename: the path to the configuration file. - * @flags: combination of virConfFlag(s) - * - * Reads a configuration file. - * - * Returns a handle to lookup settings or NULL if it failed to - * read or parse the file, use virConfFree() to free the data. - */ -virConfPtr -virConfReadFile(const char *filename, unsigned int flags) -{ - char *content; - int len; - virConfPtr conf; - - VIR_DEBUG("filename=%s", NULLSTR(filename)); - - if (filename == NULL) { - virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); - return NULL; - } - - if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) { - return NULL; - } - - conf = virConfParse(filename, content, len, flags); - - VIR_FREE(content); - - return conf; -} - -/** - * virConfReadMem: - * @memory: pointer to the content of the configuration file - * @len: length in byte - * @flags: combination of virConfFlag(s) - * - * Reads a configuration file loaded in memory. The string can be - * zero terminated in which case @len can be 0 - * - * Returns a handle to lookup settings or NULL if it failed to - * parse the content, use virConfFree() to free the data. - */ -virConfPtr -virConfReadMem(const char *memory, int len, unsigned int flags) -{ - if ((memory == NULL) || (len < 0)) { - virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); - return NULL; - } - if (len == 0) - len = strlen(memory); - - return virConfParse("memory conf", memory, len, flags); -} - -/** - * virConfFree: - * @conf: a configuration file handle - * - * Frees all data associated to the handle - * - * Returns 0 in case of success, -1 in case of error. - */ -int -virConfFree(virConfPtr conf) -{ - virConfEntryPtr tmp; - if (conf == NULL) - return 0; - - tmp = conf->entries; - while (tmp) { - virConfEntryPtr next; - VIR_FREE(tmp->name); - virConfFreeValue(tmp->value); - VIR_FREE(tmp->comment); - next = tmp->next; - VIR_FREE(tmp); - tmp = next; - } - VIR_FREE(conf); - return 0; -} - -/** - * virConfGetValue: - * @conf: a configuration file handle - * @entry: the name of the entry - * - * Lookup the value associated to this entry in the configuration file - * - * Returns a pointer to the value or NULL if the lookup failed, the data - * associated will be freed when virConfFree() is called - */ -virConfValuePtr -virConfGetValue(virConfPtr conf, const char *setting) -{ - virConfEntryPtr cur; - - if (conf == NULL) - return NULL; - - cur = conf->entries; - while (cur != NULL) { - if ((cur->name != NULL) && - ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT && - STRCASEEQ(cur->name, setting)) || - STREQ(cur->name, setting))) - return cur->value; - cur = cur->next; - } - return NULL; -} - -/** - * virConfSetValue: - * @conf: a configuration file handle - * @entry: the name of the entry - * @value: the new configuration value - * - * Set (or replace) the value associated to this entry in the configuration - * file. The passed in 'value' will be owned by the conf object upon return - * of this method, even in case of error. It should not be referenced again - * by the caller. - * - * Returns 0 on success, or -1 on failure. - */ -int -virConfSetValue(virConfPtr conf, - const char *setting, - virConfValuePtr value) -{ - virConfEntryPtr cur, prev = NULL; - - if (value && value->type == VIR_CONF_STRING && value->str == NULL) - return -1; - - cur = conf->entries; - while (cur != NULL) { - if ((cur->name != NULL) && (STREQ(cur->name, setting))) { - break; - } - prev = cur; - cur = cur->next; - } - - if (!cur) { - if (VIR_ALLOC(cur) < 0) { - virReportOOMError(); - virConfFreeValue(value); - return -1; - } - cur->comment = NULL; - if (!(cur->name = strdup(setting))) { - virReportOOMError(); - virConfFreeValue(value); - VIR_FREE(cur); - return -1; - } - cur->value = value; - if (prev) { - cur->next = prev->next; - prev->next = cur; - } else { - cur->next = conf->entries; - conf->entries = cur; - } - } else { - virConfFreeValue(cur->value); - cur->value = value; - } - return 0; -} - - -/** - * virConfWriteFile: - * @filename: the path to the configuration file. - * @conf: the conf - * - * Writes a configuration file back to a file. - * - * Returns the number of bytes written or -1 in case of error. - */ -int -virConfWriteFile(const char *filename, virConfPtr conf) -{ - virBuffer buf = VIR_BUFFER_INITIALIZER; - virConfEntryPtr cur; - int ret; - int fd; - char *content; - unsigned int use; - - if (conf == NULL) - return -1; - - cur = conf->entries; - while (cur != NULL) { - virConfSaveEntry(&buf, cur); - cur = cur->next; - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - virBufferFreeAndReset(&buf); - virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file")); - return -1; - } - - use = virBufferUse(&buf); - content = virBufferContentAndReset(&buf); - ret = safewrite(fd, content, use); - VIR_FREE(content); - VIR_FORCE_CLOSE(fd); - if (ret != (int)use) { - virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content")); - return -1; - } - - return ret; -} - -/** - * virConfWriteMem: - * @memory: pointer to the memory to store the config file - * @len: pointer to the length in bytes of the store, on output the size - * @conf: the conf - * - * Writes a configuration file back to a memory area. @len is an IN/OUT - * parameter, it indicates the size available in bytes, and on output the - * size required for the configuration file (even if the call fails due to - * insufficient space). - * - * Returns the number of bytes written or -1 in case of error. - */ -int -virConfWriteMem(char *memory, int *len, virConfPtr conf) -{ - virBuffer buf = VIR_BUFFER_INITIALIZER; - virConfEntryPtr cur; - char *content; - unsigned int use; - - if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL)) - return -1; - - cur = conf->entries; - while (cur != NULL) { - virConfSaveEntry(&buf, cur); - cur = cur->next; - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - - use = virBufferUse(&buf); - content = virBufferContentAndReset(&buf); - - if ((int)use >= *len) { - *len = (int)use; - VIR_FREE(content); - return -1; - } - memcpy(memory, content, use); - VIR_FREE(content); - *len = use; - return use; -} diff --git a/src/util/conf.h b/src/util/conf.h deleted file mode 100644 index 224592d..0000000 --- a/src/util/conf.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * conf.h: parser for a subset of the Python encoded Xen configuration files - * - * Copyright (C) 2006, 2007 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Daniel Veillard <veillard@xxxxxxxxxx> - */ - -#ifndef __VIR_CONF_H__ -# define __VIR_CONF_H__ - -/** - * virConfType: - * one of the possible type for a value from the configuration file - * - * TODO: we probably need a float too. - */ -typedef enum { - VIR_CONF_NONE = 0, /* undefined */ - VIR_CONF_LONG = 1, /* a long int */ - VIR_CONF_STRING = 2, /* a string */ - VIR_CONF_LIST = 3 /* a list */ -} virConfType; - -typedef enum { - VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow ':', '.' and '-' in names for compatibility - with VMware VMX configuration file, but restrict - allowed value types to string only */ -} virConfFlags; - -static inline const char * -virConfTypeName (virConfType t) -{ - switch (t) { - case VIR_CONF_LONG: - return "long"; - case VIR_CONF_STRING: - return "string"; - case VIR_CONF_LIST: - return "list"; - default: - return "*unexpected*"; - } -} - -/** - * virConfValue: - * a value from the configuration file - */ -typedef struct _virConfValue virConfValue; -typedef virConfValue *virConfValuePtr; - -struct _virConfValue { - virConfType type; /* the virConfType */ - virConfValuePtr next; /* next element if in a list */ - long l; /* long integer */ - char *str; /* pointer to 0 terminated string */ - virConfValuePtr list; /* list of a list */ -}; - -/** - * virConfPtr: - * a pointer to a parsed configuration file - */ -typedef struct _virConf virConf; -typedef virConf *virConfPtr; - -virConfPtr virConfNew (void); -virConfPtr virConfReadFile (const char *filename, unsigned int flags); -virConfPtr virConfReadMem (const char *memory, - int len, unsigned int flags); -int virConfFree (virConfPtr conf); -void virConfFreeValue (virConfValuePtr val); - -virConfValuePtr virConfGetValue (virConfPtr conf, - const char *setting); -int virConfSetValue (virConfPtr conf, - const char *setting, - virConfValuePtr value); -int virConfWriteFile (const char *filename, - virConfPtr conf); -int virConfWriteMem (char *memory, - int *len, - virConfPtr conf); - -#endif /* __VIR_CONF_H__ */ diff --git a/src/util/virconf.c b/src/util/virconf.c new file mode 100644 index 0000000..221a1eb --- /dev/null +++ b/src/util/virconf.c @@ -0,0 +1,1032 @@ +/** + * conf.c: parser for a subset of the Python encoded Xen configuration files + * + * Copyright (C) 2006-2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@xxxxxxxxxx> + */ + +#include <config.h> + +#include <string.h> + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "virterror_internal.h" +#include "virbuffer.h" +#include "virconf.h" +#include "util.h" +#include "c-ctype.h" +#include "logging.h" +#include "memory.h" +#include "virfile.h" + +#define VIR_FROM_THIS VIR_FROM_CONF + +/************************************************************************ + * * + * Structures and macros used by the mini parser * + * * + ************************************************************************/ + +typedef struct _virConfParserCtxt virConfParserCtxt; +typedef virConfParserCtxt *virConfParserCtxtPtr; + +struct _virConfParserCtxt { + const char* filename; + const char* base; + const char* cur; + const char *end; + int line; + + virConfPtr conf; +}; + +#define CUR (*ctxt->cur) +#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++; +#define IS_EOL(c) (((c) == '\n') || ((c) == '\r')) + +#define SKIP_BLANKS_AND_EOL \ + do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \ + if (CUR == '\n') ctxt->line++; \ + ctxt->cur++;}} while (0) +#define SKIP_BLANKS \ + do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR))) \ + ctxt->cur++; } while (0) + +/************************************************************************ + * * + * Structures used by configuration data * + * * + ************************************************************************/ + +typedef struct _virConfEntry virConfEntry; +typedef virConfEntry *virConfEntryPtr; + +struct _virConfEntry { + virConfEntryPtr next; + char* name; + char* comment; + virConfValuePtr value; +}; + +struct _virConf { + const char* filename; + unsigned int flags; + virConfEntryPtr entries; +}; + +/** + * virConfError: + * @ctxt: the parser context if available or NULL + * @error: the error number + * @info: extra information string + * + * Handle an error at the xend daemon interface + */ +#define virConfError(ctxt, error, info) \ + virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info) +static void +virConfErrorHelper(const char *file, const char *func, size_t line, + virConfParserCtxtPtr ctxt, + virErrorNumber error, const char *info) +{ + if (error == VIR_ERR_OK) + return; + + /* Construct the string 'filename:line: info' if we have that. */ + if (ctxt && ctxt->filename) { + virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, + _("%s:%d: %s"), ctxt->filename, ctxt->line, info); + } else { + virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, + "%s", info); + } +} + + +/************************************************************************ + * * + * Structures allocations and deallocations * + * * + ************************************************************************/ + +/** + * virConfFreeList: + * @list: the list to free + * + * Free a list + */ +static void +virConfFreeList(virConfValuePtr list) +{ + virConfValuePtr next; + + while (list != NULL) { + next = list->next; + list->next = NULL; + virConfFreeValue(list); + list = next; + } +} + +/** + * virConfFreeValue: + * @val: the value to free + * + * Free a value + */ +void +virConfFreeValue(virConfValuePtr val) +{ + if (val == NULL) + return; + if (val->type == VIR_CONF_STRING && + val->str != NULL) + VIR_FREE(val->str); + if (val->type == VIR_CONF_LIST && + val->list != NULL) + virConfFreeList(val->list); + VIR_FREE(val); +} + +virConfPtr +virConfNew(void) +{ + virConfPtr ret; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(); + return NULL; + } + ret->filename = NULL; + ret->flags = 0; + + return ret; +} + +/** + * virConfCreate: + * @filename: the name to report errors + * @flags: combination of virConfFlag(s) + * + * Create a configuration internal structure + * + * Returns a pointer or NULL in case of error. + */ +static virConfPtr +virConfCreate(const char *filename, unsigned int flags) +{ + virConfPtr ret = virConfNew(); + if (ret) { + ret->filename = filename; + ret->flags = flags; + } + return ret; +} + +/** + * virConfAddEntry: + * @conf: the conf structure + * @name: name of the entry or NULL for comment + * @value: the value if any + * @comm: extra comment for that entry if any + * + * add one entry to the conf, the parameters are included in the conf + * if successful and freed on virConfFree() + * + * Returns a pointer to the entry or NULL in case of failure + */ +static virConfEntryPtr +virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm) +{ + virConfEntryPtr ret, prev; + + if (conf == NULL) + return NULL; + if ((comm == NULL) && (name == NULL)) + return NULL; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(); + return NULL; + } + + ret->name = name; + ret->value = value; + ret->comment = comm; + + if (conf->entries == NULL) { + conf->entries = ret; + } else { + prev = conf->entries; + while (prev->next != NULL) + prev = prev->next; + prev->next = ret; + } + return ret; +} + +/************************************************************************ + * * + * Serialization * + * * + ************************************************************************/ + +/** + * virConfSaveValue: + * @buf: output buffer + * @val: a value + * + * Serialize the value to the buffer + * + * Returns 0 in case of success, -1 in case of error. + */ +static int +virConfSaveValue(virBufferPtr buf, virConfValuePtr val) +{ + if (val == NULL) + return -1; + switch (val->type) { + case VIR_CONF_NONE: + return -1; + case VIR_CONF_LONG: + virBufferAsprintf(buf, "%ld", val->l); + break; + case VIR_CONF_STRING: + if (strchr(val->str, '\n') != NULL) { + virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); + } else if (strchr(val->str, '"') == NULL) { + virBufferAsprintf(buf, "\"%s\"", val->str); + } else if (strchr(val->str, '\'') == NULL) { + virBufferAsprintf(buf, "'%s'", val->str); + } else { + virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); + } + break; + case VIR_CONF_LIST: { + virConfValuePtr cur; + + cur = val->list; + virBufferAddLit(buf, "[ "); + if (cur != NULL) { + virConfSaveValue(buf, cur); + cur = cur->next; + while (cur != NULL) { + virBufferAddLit(buf, ", "); + virConfSaveValue(buf, cur); + cur = cur->next; + } + } + virBufferAddLit(buf, " ]"); + break; + } + default: + return -1; + } + return 0; +} + +/** + * virConfSaveEntry: + * @buf: output buffer + * @cur: a conf entry + * + * Serialize the entry to the buffer + * + * Returns 0 in case of success, -1 in case of error. + */ +static int +virConfSaveEntry(virBufferPtr buf, virConfEntryPtr cur) +{ + if (cur->name != NULL) { + virBufferAdd(buf, cur->name, -1); + virBufferAddLit(buf, " = "); + virConfSaveValue(buf, cur->value); + if (cur->comment != NULL) { + virBufferAddLit(buf, " #"); + virBufferAdd(buf, cur->comment, -1); + } + } else if (cur->comment != NULL) { + virBufferAddLit(buf, "#"); + virBufferAdd(buf, cur->comment, -1); + } + virBufferAddLit(buf, "\n"); + return 0; +} + +/************************************************************************ + * * + * The parser core * + * * + ************************************************************************/ + +/** + * virConfParseLong: + * @ctxt: the parsing context + * @val: the result + * + * Parse one long int value + * + * Returns 0 in case of success and -1 in case of error + */ +static int +virConfParseLong(virConfParserCtxtPtr ctxt, long *val) +{ + long l = 0; + int neg = 0; + + if (CUR == '-') { + neg = 1; + NEXT; + } else if (CUR == '+') { + NEXT; + } + if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number")); + return -1; + } + while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) { + l = l * 10 + (CUR - '0'); + NEXT; + } + if (neg) + l = -l; + *val = l; + return 0; +} + +/** + * virConfParseString: + * @ctxt: the parsing context + * + * Parse one string + * + * Returns a pointer to the string or NULL in case of error + */ +static char * +virConfParseString(virConfParserCtxtPtr ctxt) +{ + const char *base; + char *ret = NULL; + + if (CUR == '\'') { + NEXT; + base = ctxt->cur; + while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) + NEXT; + if (CUR != '\'') { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); + return NULL; + } + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + NEXT; + } else if ((ctxt->cur + 6 < ctxt->end) && + (STRPREFIX(ctxt->cur, "\"\"\""))) { + /* String starts with python-style triple quotes """ */ + ctxt->cur += 3; + base = ctxt->cur; + + /* Find the ending triple quotes */ + while ((ctxt->cur + 2 < ctxt->end) && + !(STRPREFIX(ctxt->cur, "\"\"\""))) { + if (CUR == '\n') + ctxt->line++; + NEXT; + } + + if (!STRPREFIX(ctxt->cur, "\"\"\"")) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); + return NULL; + } + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + ctxt->cur += 3; + } else if (CUR == '"') { + NEXT; + base = ctxt->cur; + while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) + NEXT; + if (CUR != '"') { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); + return NULL; + } + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + NEXT; + } + return ret; +} + +/** + * virConfParseValue: + * @ctxt: the parsing context + * + * Parse one value + * + * Returns a pointer to the value or NULL in case of error + */ +static virConfValuePtr +virConfParseValue(virConfParserCtxtPtr ctxt) +{ + virConfValuePtr ret, lst = NULL, tmp, prev; + virConfType type = VIR_CONF_NONE; + char *str = NULL; + long l = 0; + + SKIP_BLANKS; + if (ctxt->cur >= ctxt->end) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); + return NULL; + } + if ((CUR == '"') || (CUR == '\'')) { + type = VIR_CONF_STRING; + str = virConfParseString(ctxt); + if (str == NULL) + return NULL; + } else if (CUR == '[') { + if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, + _("lists not allowed in VMX format")); + return NULL; + } + type = VIR_CONF_LIST; + NEXT; + SKIP_BLANKS_AND_EOL; + if ((ctxt->cur < ctxt->end) && (CUR != ']')) { + if ((lst = virConfParseValue(ctxt)) == NULL) + return NULL; + SKIP_BLANKS_AND_EOL; + } + while ((ctxt->cur < ctxt->end) && (CUR != ']')) { + + /* Tell Clang that when execution reaches this point + "lst" is guaranteed to be non-NULL. This stops it + from issuing an invalid NULL-dereference warning about + "prev = lst; while (prev->next..." below. */ + sa_assert(lst); + + if (CUR != ',') { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, + _("expecting a separator in list")); + virConfFreeList(lst); + return NULL; + } + NEXT; + SKIP_BLANKS_AND_EOL; + if (CUR == ']') { + break; + } + tmp = virConfParseValue(ctxt); + if (tmp == NULL) { + virConfFreeList(lst); + return NULL; + } + prev = lst; + while (prev->next != NULL) prev = prev->next; + prev->next = tmp; + SKIP_BLANKS_AND_EOL; + } + if (CUR == ']') { + NEXT; + } else { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, + _("list is not closed with ]")); + virConfFreeList(lst); + return NULL; + } + } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) { + if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, + _("numbers not allowed in VMX format")); + return NULL; + } + if (virConfParseLong(ctxt, &l) < 0) { + return NULL; + } + type = VIR_CONF_LONG; + } else { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); + return NULL; + } + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(); + virConfFreeList(lst); + VIR_FREE(str); + return NULL; + } + ret->type = type; + ret->l = l; + ret->str = str; + ret->list = lst; + return ret; +} + +/** + * virConfParseName: + * @ctxt: the parsing context + * + * Parse one name + * + * Returns a copy of the new string, NULL in case of error + */ +static char * +virConfParseName(virConfParserCtxtPtr ctxt) +{ + const char *base; + char *ret; + + SKIP_BLANKS; + base = ctxt->cur; + /* TODO: probably need encoding support and UTF-8 parsing ! */ + if (!c_isalpha(CUR) && + !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name")); + return NULL; + } + while ((ctxt->cur < ctxt->end) && + (c_isalnum(CUR) || (CUR == '_') || + ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && + ((CUR == ':') || (CUR == '.') || (CUR == '-'))))) + NEXT; + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + return ret; +} + +/** + * virConfParseComment: + * @ctxt: the parsing context + * + * Parse one standalone comment in the configuration file + * + * Returns 0 in case of success and -1 in case of error + */ +static int +virConfParseComment(virConfParserCtxtPtr ctxt) +{ + const char *base; + char *comm; + + if (CUR != '#') + return -1; + NEXT; + base = ctxt->cur; + while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; + comm = strndup(base, ctxt->cur - base); + if (comm == NULL) { + virReportOOMError(); + return -1; + } + virConfAddEntry(ctxt->conf, NULL, NULL, comm); + return 0; +} + +/** + * virConfParseSeparator: + * @ctxt: the parsing context + * + * Parse one separator between statement if not at the end. + * + * Returns 0 in case of success and -1 in case of error + */ +static int +virConfParseSeparator(virConfParserCtxtPtr ctxt) +{ + SKIP_BLANKS; + if (ctxt->cur >= ctxt->end) + return 0; + if (IS_EOL(CUR)) { + SKIP_BLANKS_AND_EOL; + } else if (CUR == ';') { + NEXT; + SKIP_BLANKS_AND_EOL; + } else { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator")); + return -1; + } + return 0; +} + +/** + * virConfParseStatement: + * @ctxt: the parsing context + * + * Parse one statement in the conf file + * + * Returns 0 in case of success and -1 in case of error + */ +static int +virConfParseStatement(virConfParserCtxtPtr ctxt) +{ + const char *base; + char *name; + virConfValuePtr value; + char *comm = NULL; + + SKIP_BLANKS_AND_EOL; + if (CUR == '#') { + return virConfParseComment(ctxt); + } + name = virConfParseName(ctxt); + if (name == NULL) + return -1; + SKIP_BLANKS; + if (CUR != '=') { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment")); + VIR_FREE(name); + return -1; + } + NEXT; + SKIP_BLANKS; + value = virConfParseValue(ctxt); + if (value == NULL) { + VIR_FREE(name); + return -1; + } + SKIP_BLANKS; + if (CUR == '#') { + NEXT; + base = ctxt->cur; + while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; + comm = strndup(base, ctxt->cur - base); + if (comm == NULL) { + virReportOOMError(); + VIR_FREE(name); + virConfFreeValue(value); + return -1; + } + } + if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) { + VIR_FREE(name); + virConfFreeValue(value); + VIR_FREE(comm); + return -1; + } + return 0; +} + +/** + * virConfParse: + * @filename: the name to report errors + * @content: the configuration content in memory + * @len: the length in bytes + * @flags: combination of virConfFlag(s) + * + * Parse the subset of the Python language needed to handle simple + * Xen configuration files. + * + * Returns a handle to lookup settings or NULL if it failed to + * read or parse the file, use virConfFree() to free the data. + */ +static virConfPtr +virConfParse(const char *filename, const char *content, int len, + unsigned int flags) { + virConfParserCtxt ctxt; + + ctxt.filename = filename; + ctxt.base = ctxt.cur = content; + ctxt.end = content + len - 1; + ctxt.line = 1; + + ctxt.conf = virConfCreate(filename, flags); + if (ctxt.conf == NULL) + return NULL; + + while (ctxt.cur < ctxt.end) { + if (virConfParseStatement(&ctxt) < 0) + goto error; + if (virConfParseSeparator(&ctxt) < 0) + goto error; + } + + return ctxt.conf; + +error: + virConfFree(ctxt.conf); + return NULL; +} + +/************************************************************************ + * * + * The module entry points * + * * + ************************************************************************/ + +/* 10 MB limit on config file size as a sanity check */ +#define MAX_CONFIG_FILE_SIZE (1024*1024*10) + +/** + * virConfReadFile: + * @filename: the path to the configuration file. + * @flags: combination of virConfFlag(s) + * + * Reads a configuration file. + * + * Returns a handle to lookup settings or NULL if it failed to + * read or parse the file, use virConfFree() to free the data. + */ +virConfPtr +virConfReadFile(const char *filename, unsigned int flags) +{ + char *content; + int len; + virConfPtr conf; + + VIR_DEBUG("filename=%s", NULLSTR(filename)); + + if (filename == NULL) { + virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return NULL; + } + + if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) { + return NULL; + } + + conf = virConfParse(filename, content, len, flags); + + VIR_FREE(content); + + return conf; +} + +/** + * virConfReadMem: + * @memory: pointer to the content of the configuration file + * @len: length in byte + * @flags: combination of virConfFlag(s) + * + * Reads a configuration file loaded in memory. The string can be + * zero terminated in which case @len can be 0 + * + * Returns a handle to lookup settings or NULL if it failed to + * parse the content, use virConfFree() to free the data. + */ +virConfPtr +virConfReadMem(const char *memory, int len, unsigned int flags) +{ + if ((memory == NULL) || (len < 0)) { + virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return NULL; + } + if (len == 0) + len = strlen(memory); + + return virConfParse("memory conf", memory, len, flags); +} + +/** + * virConfFree: + * @conf: a configuration file handle + * + * Frees all data associated to the handle + * + * Returns 0 in case of success, -1 in case of error. + */ +int +virConfFree(virConfPtr conf) +{ + virConfEntryPtr tmp; + if (conf == NULL) + return 0; + + tmp = conf->entries; + while (tmp) { + virConfEntryPtr next; + VIR_FREE(tmp->name); + virConfFreeValue(tmp->value); + VIR_FREE(tmp->comment); + next = tmp->next; + VIR_FREE(tmp); + tmp = next; + } + VIR_FREE(conf); + return 0; +} + +/** + * virConfGetValue: + * @conf: a configuration file handle + * @entry: the name of the entry + * + * Lookup the value associated to this entry in the configuration file + * + * Returns a pointer to the value or NULL if the lookup failed, the data + * associated will be freed when virConfFree() is called + */ +virConfValuePtr +virConfGetValue(virConfPtr conf, const char *setting) +{ + virConfEntryPtr cur; + + if (conf == NULL) + return NULL; + + cur = conf->entries; + while (cur != NULL) { + if ((cur->name != NULL) && + ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT && + STRCASEEQ(cur->name, setting)) || + STREQ(cur->name, setting))) + return cur->value; + cur = cur->next; + } + return NULL; +} + +/** + * virConfSetValue: + * @conf: a configuration file handle + * @entry: the name of the entry + * @value: the new configuration value + * + * Set (or replace) the value associated to this entry in the configuration + * file. The passed in 'value' will be owned by the conf object upon return + * of this method, even in case of error. It should not be referenced again + * by the caller. + * + * Returns 0 on success, or -1 on failure. + */ +int +virConfSetValue(virConfPtr conf, + const char *setting, + virConfValuePtr value) +{ + virConfEntryPtr cur, prev = NULL; + + if (value && value->type == VIR_CONF_STRING && value->str == NULL) + return -1; + + cur = conf->entries; + while (cur != NULL) { + if ((cur->name != NULL) && (STREQ(cur->name, setting))) { + break; + } + prev = cur; + cur = cur->next; + } + + if (!cur) { + if (VIR_ALLOC(cur) < 0) { + virReportOOMError(); + virConfFreeValue(value); + return -1; + } + cur->comment = NULL; + if (!(cur->name = strdup(setting))) { + virReportOOMError(); + virConfFreeValue(value); + VIR_FREE(cur); + return -1; + } + cur->value = value; + if (prev) { + cur->next = prev->next; + prev->next = cur; + } else { + cur->next = conf->entries; + conf->entries = cur; + } + } else { + virConfFreeValue(cur->value); + cur->value = value; + } + return 0; +} + + +/** + * virConfWriteFile: + * @filename: the path to the configuration file. + * @conf: the conf + * + * Writes a configuration file back to a file. + * + * Returns the number of bytes written or -1 in case of error. + */ +int +virConfWriteFile(const char *filename, virConfPtr conf) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virConfEntryPtr cur; + int ret; + int fd; + char *content; + unsigned int use; + + if (conf == NULL) + return -1; + + cur = conf->entries; + while (cur != NULL) { + virConfSaveEntry(&buf, cur); + cur = cur->next; + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd < 0) { + virBufferFreeAndReset(&buf); + virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file")); + return -1; + } + + use = virBufferUse(&buf); + content = virBufferContentAndReset(&buf); + ret = safewrite(fd, content, use); + VIR_FREE(content); + VIR_FORCE_CLOSE(fd); + if (ret != (int)use) { + virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content")); + return -1; + } + + return ret; +} + +/** + * virConfWriteMem: + * @memory: pointer to the memory to store the config file + * @len: pointer to the length in bytes of the store, on output the size + * @conf: the conf + * + * Writes a configuration file back to a memory area. @len is an IN/OUT + * parameter, it indicates the size available in bytes, and on output the + * size required for the configuration file (even if the call fails due to + * insufficient space). + * + * Returns the number of bytes written or -1 in case of error. + */ +int +virConfWriteMem(char *memory, int *len, virConfPtr conf) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virConfEntryPtr cur; + char *content; + unsigned int use; + + if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL)) + return -1; + + cur = conf->entries; + while (cur != NULL) { + virConfSaveEntry(&buf, cur); + cur = cur->next; + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + + use = virBufferUse(&buf); + content = virBufferContentAndReset(&buf); + + if ((int)use >= *len) { + *len = (int)use; + VIR_FREE(content); + return -1; + } + memcpy(memory, content, use); + VIR_FREE(content); + *len = use; + return use; +} diff --git a/src/util/virconf.h b/src/util/virconf.h new file mode 100644 index 0000000..224592d --- /dev/null +++ b/src/util/virconf.h @@ -0,0 +1,100 @@ +/** + * conf.h: parser for a subset of the Python encoded Xen configuration files + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@xxxxxxxxxx> + */ + +#ifndef __VIR_CONF_H__ +# define __VIR_CONF_H__ + +/** + * virConfType: + * one of the possible type for a value from the configuration file + * + * TODO: we probably need a float too. + */ +typedef enum { + VIR_CONF_NONE = 0, /* undefined */ + VIR_CONF_LONG = 1, /* a long int */ + VIR_CONF_STRING = 2, /* a string */ + VIR_CONF_LIST = 3 /* a list */ +} virConfType; + +typedef enum { + VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow ':', '.' and '-' in names for compatibility + with VMware VMX configuration file, but restrict + allowed value types to string only */ +} virConfFlags; + +static inline const char * +virConfTypeName (virConfType t) +{ + switch (t) { + case VIR_CONF_LONG: + return "long"; + case VIR_CONF_STRING: + return "string"; + case VIR_CONF_LIST: + return "list"; + default: + return "*unexpected*"; + } +} + +/** + * virConfValue: + * a value from the configuration file + */ +typedef struct _virConfValue virConfValue; +typedef virConfValue *virConfValuePtr; + +struct _virConfValue { + virConfType type; /* the virConfType */ + virConfValuePtr next; /* next element if in a list */ + long l; /* long integer */ + char *str; /* pointer to 0 terminated string */ + virConfValuePtr list; /* list of a list */ +}; + +/** + * virConfPtr: + * a pointer to a parsed configuration file + */ +typedef struct _virConf virConf; +typedef virConf *virConfPtr; + +virConfPtr virConfNew (void); +virConfPtr virConfReadFile (const char *filename, unsigned int flags); +virConfPtr virConfReadMem (const char *memory, + int len, unsigned int flags); +int virConfFree (virConfPtr conf); +void virConfFreeValue (virConfValuePtr val); + +virConfValuePtr virConfGetValue (virConfPtr conf, + const char *setting); +int virConfSetValue (virConfPtr conf, + const char *setting, + virConfValuePtr value); +int virConfWriteFile (const char *filename, + virConfPtr conf); +int virConfWriteMem (char *memory, + int *len, + virConfPtr conf); + +#endif /* __VIR_CONF_H__ */ diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index e051de5..0d34453 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/vmx/vmx.h b/src/vmx/vmx.h index 406c27e..f4877b1 100644 --- a/src/vmx/vmx.h +++ b/src/vmx/vmx.h @@ -24,7 +24,7 @@ # define __VIR_VMX_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" typedef struct _virVMXContext virVMXContext; diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 2e40015..bcafdd0 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -32,7 +32,7 @@ #include "driver.h" #include "memory.h" #include "xen_driver.h" -#include "conf.h" +#include "virconf.h" #include "domain_conf.h" #include "xen_inotify.h" #include "xend_internal.h" diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h index 98b5ad7..df77ac8 100644 --- a/src/xen/xm_internal.h +++ b/src/xen/xm_internal.h @@ -27,7 +27,7 @@ # include "internal.h" # include "driver.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" extern struct xenUnifiedDriver xenXMDriver; diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 3e8396b..ed0c9e1 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "verify.h" #include "uuid.h" diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h index d4502bd..4ff640c 100644 --- a/src/xenxs/xen_sxpr.h +++ b/src/xenxs/xen_sxpr.h @@ -28,7 +28,7 @@ # define __VIR_XEN_SXPR_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" # include "sexpr.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 23b3037..7bde7ab 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "verify.h" #include "uuid.h" diff --git a/src/xenxs/xen_xm.h b/src/xenxs/xen_xm.h index c3d0ad4..629a4b3 100644 --- a/src/xenxs/xen_xm.h +++ b/src/xenxs/xen_xm.h @@ -27,7 +27,7 @@ # define __VIR_XEN_XM_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" virConfPtr xenFormatXM(virConnectPtr conn, virDomainDefPtr def, diff --git a/tests/conftest.c b/tests/conftest.c index 4342a52..aacc526 100644 --- a/tests/conftest.c +++ b/tests/conftest.c @@ -5,7 +5,7 @@ #include <stdio.h> #include <string.h> #include <errno.h> -#include "conf.h" +#include "virconf.h" #include "memory.h" int main(int argc, char **argv) diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index ee1f8a0..c2b02a6 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -28,7 +28,7 @@ #include "c-ctype.h" #include "virterror_internal.h" #include "logging.h" -#include "conf.h" +#include "virconf.h" #define VIR_FROM_THIS VIR_FROM_NONE -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list