mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 05:17:54 +03:00
* TODO libvirt.spec.in: update
* configure.in include/libvirt/virterror.h src/Makefile.am src/conf.c src/conf.h src/virterror.c src/xen_internal.c: adding a subset of Xen config file parser, and serializer * tests/Makefile.am tests/conftest.c tests/test_conf.sh tests/confdata/Makefile.am tests/confdata/fc4.conf tests/confdata/fc4.out: adding test program for config in and out Daniel
This commit is contained in:
parent
55bf738483
commit
3bbac7cdb6
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
Tue Aug 29 23:28:31 CEST 2006 Daniel Veillard <veillard@redhat.com>
|
||||
|
||||
* TODO libvirt.spec.in: update
|
||||
* configure.in include/libvirt/virterror.h src/Makefile.am
|
||||
src/conf.c src/conf.h src/virterror.c src/xen_internal.c:
|
||||
adding a subset of Xen config file parser, and serializer
|
||||
* tests/Makefile.am tests/conftest.c tests/test_conf.sh
|
||||
tests/confdata/Makefile.am tests/confdata/fc4.conf
|
||||
tests/confdata/fc4.out: adding test program for config in and out
|
||||
|
||||
Tue Aug 29 13:14:20 EDT 2006 Daniel Berrange <berrange@redhat.com>
|
||||
|
||||
* src/xend_internal.c: Add handling of HTTP 500 error code
|
||||
|
1
TODO
1
TODO
@ -1,4 +1,5 @@
|
||||
TODO:
|
||||
- libvirt-proxy dropping root priviledge after initialization.
|
||||
- check impact of HVM device rename
|
||||
http://lists.xensource.com/archives/html/xen-devel/2006-08/msg00369.html
|
||||
- Finish integration of vCPU and affinity APIs
|
||||
|
@ -257,4 +257,4 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \
|
||||
include/libvirt/Makefile include/libvirt/libvirt.h \
|
||||
python/Makefile python/tests/Makefile \
|
||||
tests/Makefile proxy/Makefile \
|
||||
tests/virshdata/Makefile)
|
||||
tests/virshdata/Makefile tests/confdata/Makefile)
|
||||
|
@ -45,7 +45,8 @@ typedef enum {
|
||||
VIR_FROM_XML, /* Error in the XML code */
|
||||
VIR_FROM_DOM, /* Error when operating on a domain */
|
||||
VIR_FROM_RPC, /* Error in the XML-RPC code */
|
||||
VIR_FROM_PROXY /* Error in the proxy code */
|
||||
VIR_FROM_PROXY, /* Error in the proxy code */
|
||||
VIR_FROM_CONF /* Error in the configuration file handling */
|
||||
} virErrorDomain;
|
||||
|
||||
|
||||
@ -106,7 +107,12 @@ typedef enum {
|
||||
VIR_ERR_CALL_FAILED, /* not supported by the drivers */
|
||||
VIR_ERR_XML_ERROR, /* an XML description is not well formed or broken */
|
||||
VIR_ERR_DOM_EXIST,/* the domain already exist */
|
||||
VIR_ERR_OPERATION_DENIED /* operation forbidden on read-only connections */
|
||||
VIR_ERR_OPERATION_DENIED, /* operation forbidden on read-only connections */
|
||||
VIR_ERR_OPEN_FAILED, /* failed to open a conf file */
|
||||
VIR_ERR_READ_FAILED, /* failed to read a conf file */
|
||||
VIR_ERR_PARSE_FAILED, /* failed to parse a conf file */
|
||||
VIR_ERR_CONF_SYNTAX, /* failed to parse the syntax of a conf file */
|
||||
VIR_ERR_WRITE_FAILED /* failed to write a conf file */
|
||||
} virErrorNumber;
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@ Group: Development/Libraries
|
||||
Source: libvirt-%{version}.tar.gz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
URL: http://libvir.org/
|
||||
BuildRequires: xen python python-devel
|
||||
BuildRequires: python python-devel
|
||||
Requires: xen
|
||||
Requires: libxml2
|
||||
Requires: readline
|
||||
@ -107,6 +107,25 @@ rm -fr %{buildroot}
|
||||
%doc docs/examples/python
|
||||
|
||||
%changelog
|
||||
* Wed Aug 16 2006 Daniel Veillard <veillard@redhat.com> 0.1.4-1
|
||||
- vCPUs and affinity support
|
||||
- more complete XML, console and boot options
|
||||
- specific features support
|
||||
- enforced read-only connections
|
||||
- various improvements, bug fixes
|
||||
|
||||
* Wed Aug 2 2006 Jeremy Katz <katzj@redhat.com> - 0.1.3-6
|
||||
- add patch from pvetere to allow getting uuid from libvirt
|
||||
|
||||
* Wed Aug 2 2006 Jeremy Katz <katzj@redhat.com> - 0.1.3-5
|
||||
- build on ia64 now
|
||||
|
||||
* Thu Jul 27 2006 Jeremy Katz <katzj@redhat.com> - 0.1.3-4
|
||||
- don't BR xen, we just need xen-devel
|
||||
|
||||
* Thu Jul 27 2006 Daniel Veillard <veillard@redhat.com> 0.1.3-3
|
||||
- need rebuild since libxenstore is now versionned
|
||||
|
||||
* Mon Jul 24 2006 Mark McLoughlin <markmc@redhat.com> - 0.1.3-2
|
||||
- Add BuildRequires: xen-devel
|
||||
|
||||
|
@ -25,7 +25,8 @@ libvirt_la_SOURCES = \
|
||||
sexpr.c sexpr.h \
|
||||
virterror.c \
|
||||
driver.h \
|
||||
proxy_internal.c proxy_internal.h
|
||||
proxy_internal.c proxy_internal.h \
|
||||
conf.c conf.h
|
||||
|
||||
bin_PROGRAMS = virsh
|
||||
|
||||
|
868
src/conf.c
Normal file
868
src/conf.c
Normal file
@ -0,0 +1,868 @@
|
||||
/**
|
||||
* conf.c: parser for a subset of the Python encoded Xen configuration files
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc.
|
||||
*
|
||||
* See COPYING.LIB for the License of this software
|
||||
*
|
||||
* Daniel Veillard <veillard@redhat.com>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* want strndup ! */
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "xml.h"
|
||||
#include "conf.h"
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
* 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 IS_BLANK(c) (((c) == ' ') || ((c) == '\n') || ((c) == '\r') || \
|
||||
((c) == '\t'))
|
||||
#define SKIP_BLANKS {while ((ctxt->cur < ctxt->end) && (IS_BLANK(CUR))){\
|
||||
if (CUR == '\n') ctxt->line++; \
|
||||
ctxt->cur++;}}
|
||||
#define IS_SPACE(c) (((c) == ' ') || ((c) == '\t'))
|
||||
#define SKIP_SPACES {while ((ctxt->cur < ctxt->end) && (IS_SPACE(CUR))) \
|
||||
ctxt->cur++;}
|
||||
#define IS_CHAR(c) ((((c) >= 'a') && ((c) <= 'z')) || \
|
||||
(((c) >= 'A') && ((c) <= 'Z')))
|
||||
#define IS_DIGIT(c) (((c) >= '0') && ((c) <= '9'))
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
* 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;
|
||||
virConfEntryPtr entries;
|
||||
};
|
||||
|
||||
/**
|
||||
* virConfError:
|
||||
* @conf: the configuration if available
|
||||
* @error: the error number
|
||||
* @info: extra information string
|
||||
* @line: line for the error
|
||||
*
|
||||
* Handle an error at the xend daemon interface
|
||||
*/
|
||||
static void
|
||||
virConfError(virConfPtr conf ATTRIBUTE_UNUSED,
|
||||
virErrorNumber error, const char *info, int line)
|
||||
{
|
||||
const char *errmsg;
|
||||
|
||||
if (error == VIR_ERR_OK)
|
||||
return;
|
||||
|
||||
errmsg = __virErrorMsg(error, info);
|
||||
__virRaiseError(NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
|
||||
errmsg, info, NULL, line, 0, errmsg, info, line);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
* Structures allocations and deallocations *
|
||||
* *
|
||||
************************************************************************/
|
||||
static void virConfFreeValue(virConfValuePtr val);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static void
|
||||
virConfFreeValue(virConfValuePtr val)
|
||||
{
|
||||
if (val == NULL)
|
||||
return;
|
||||
if (val->str != NULL)
|
||||
free(val->str);
|
||||
if (val->list != NULL)
|
||||
virConfFreeList(val->list);
|
||||
free(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* virConfCreate:
|
||||
* @filename: the name to report errors
|
||||
*
|
||||
* Create a configuration internal structure
|
||||
*
|
||||
* Returns a pointer or NULL in case of error.
|
||||
*/
|
||||
static virConfPtr
|
||||
virConfCreate(const char *filename)
|
||||
{
|
||||
virConfPtr ret;
|
||||
|
||||
ret = (virConfPtr) malloc(sizeof(virConf));
|
||||
if (ret == NULL) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration", 0);
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(virConf));
|
||||
|
||||
ret->filename = filename;
|
||||
|
||||
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);
|
||||
|
||||
ret = (virConfEntryPtr) malloc(sizeof(virConfEntry));
|
||||
if (ret == NULL) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration", 0);
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(virConfEntry));
|
||||
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:
|
||||
virBufferVSprintf(buf, "%ld", val->l);
|
||||
break;
|
||||
case VIR_CONF_STRING:
|
||||
if (strchr(val->str, '\n') != NULL) {
|
||||
virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
|
||||
} else if (strchr(val->str, '"') == NULL) {
|
||||
virBufferVSprintf(buf, "\"%s\"", val->str);
|
||||
} else if (strchr(val->str, '\'') == NULL) {
|
||||
virBufferVSprintf(buf, "'%s'", val->str);
|
||||
} else {
|
||||
virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
|
||||
}
|
||||
break;
|
||||
case VIR_CONF_LIST: {
|
||||
virConfValuePtr cur;
|
||||
|
||||
cur = val->list;
|
||||
virBufferAdd(buf, "[ ", 2);
|
||||
if (cur != NULL) {
|
||||
virConfSaveValue(buf, cur);
|
||||
cur = cur->next;
|
||||
while (cur != NULL) {
|
||||
virBufferAdd(buf, ", ", 2);
|
||||
virConfSaveValue(buf, cur);
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
virBufferAdd(buf, " ]", 2);
|
||||
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);
|
||||
virBufferAdd(buf, " = ", 3);
|
||||
virConfSaveValue(buf, cur->value);
|
||||
if (cur->comment != NULL) {
|
||||
virBufferAdd(buf, " #", 2);
|
||||
virBufferAdd(buf, cur->comment, -1);
|
||||
}
|
||||
} else if (cur->comment != NULL) {
|
||||
virBufferAdd(buf, "#", 1);
|
||||
virBufferAdd(buf, cur->comment, -1);
|
||||
}
|
||||
virBufferAdd(buf, "\n", 1);
|
||||
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) || (!IS_DIGIT(CUR))) {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "unterminated number",
|
||||
ctxt->line);
|
||||
return(-1);
|
||||
}
|
||||
while ((ctxt->cur < ctxt->end) && (IS_DIGIT(CUR))) {
|
||||
l = l * 10 + (CUR - '0');
|
||||
NEXT;
|
||||
}
|
||||
*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(NULL, VIR_ERR_CONF_SYNTAX, "unterminated string",
|
||||
ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
ret = strndup(base, ctxt->cur - base);
|
||||
NEXT;
|
||||
} else if ((ctxt->cur + 6 < ctxt->end) && (ctxt->cur[0] == '"') &&
|
||||
(ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
|
||||
ctxt->cur += 3;
|
||||
base = ctxt->cur;
|
||||
while ((ctxt->cur + 2 < ctxt->end) && (ctxt->cur[0] == '"') &&
|
||||
(ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
|
||||
if (CUR == '\n') ctxt->line++;
|
||||
NEXT;
|
||||
}
|
||||
if ((ctxt->cur[0] != '"') || (ctxt->cur[1] != '"') ||
|
||||
(ctxt->cur[2] != '"')) {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "unterminated string",
|
||||
ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
ret = strndup(base, ctxt->cur - base);
|
||||
ctxt->cur += 3;
|
||||
} else if (CUR == '"') {
|
||||
NEXT;
|
||||
base = ctxt->cur;
|
||||
while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
|
||||
NEXT;
|
||||
if (CUR != '"') {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "unterminated string",
|
||||
ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
ret = strndup(base, ctxt->cur - base);
|
||||
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_SPACES;
|
||||
if (ctxt->cur >= ctxt->end) {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "expecting a value",
|
||||
ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
if ((CUR == '"') || (CUR == '\'')) {
|
||||
type = VIR_CONF_STRING;
|
||||
str = virConfParseString(ctxt);
|
||||
if (str == NULL)
|
||||
return(NULL);
|
||||
} else if (CUR == '[') {
|
||||
type = VIR_CONF_LIST;
|
||||
NEXT;
|
||||
SKIP_BLANKS;
|
||||
if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
|
||||
lst = virConfParseValue(ctxt);
|
||||
SKIP_BLANKS;
|
||||
}
|
||||
while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
|
||||
if (CUR != ',') {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX,
|
||||
"expecting a separator in list", ctxt->line);
|
||||
virConfFreeList(lst);
|
||||
return(NULL);
|
||||
}
|
||||
NEXT;
|
||||
SKIP_BLANKS;
|
||||
tmp = virConfParseValue(ctxt);
|
||||
if (tmp == NULL) {
|
||||
virConfFreeList(lst);
|
||||
return(NULL);
|
||||
}
|
||||
prev = lst;
|
||||
while (prev->next != NULL) prev = prev->next;
|
||||
prev->next = tmp;
|
||||
SKIP_BLANKS;
|
||||
}
|
||||
if (CUR == ']') {
|
||||
NEXT;
|
||||
} else {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX,
|
||||
"list is not closed with ] ", ctxt->line);
|
||||
virConfFreeList(lst);
|
||||
return(NULL);
|
||||
}
|
||||
} else if (IS_DIGIT(CUR) || (CUR == '-') || (CUR == '+')) {
|
||||
if (virConfParseLong(ctxt, &l) < 0) {
|
||||
return(NULL);
|
||||
}
|
||||
type = VIR_CONF_LONG;
|
||||
} else {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "expecting a value",
|
||||
ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
ret = (virConfValuePtr) malloc(sizeof(virConfValue));
|
||||
if (ret == NULL) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration", 0);
|
||||
if (str != NULL)
|
||||
free(str);
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(virConfValue));
|
||||
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_SPACES;
|
||||
base = ctxt->cur;
|
||||
/* TODO: probably need encoding support and UTF-8 parsing ! */
|
||||
if (!IS_CHAR(CUR)) {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "expecting a name", ctxt->line);
|
||||
return(NULL);
|
||||
}
|
||||
while ((ctxt->cur < ctxt->end) && ((IS_CHAR(CUR)) || (IS_DIGIT(CUR))))
|
||||
NEXT;
|
||||
ret = strndup(base, ctxt->cur - base);
|
||||
if (ret == NULL) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration",
|
||||
ctxt->line);
|
||||
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) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration",
|
||||
ctxt->line);
|
||||
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_SPACES;
|
||||
if (ctxt->cur >= ctxt->end)
|
||||
return(0);
|
||||
if (IS_EOL(CUR)) {
|
||||
SKIP_BLANKS
|
||||
} else if (CUR == ';') {
|
||||
NEXT;
|
||||
SKIP_BLANKS;
|
||||
} else {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "expecting a separator",
|
||||
ctxt->line);
|
||||
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;
|
||||
if (CUR == '#') {
|
||||
return(virConfParseComment(ctxt));
|
||||
}
|
||||
name = virConfParseName(ctxt);
|
||||
if (name == NULL)
|
||||
return(-1);
|
||||
SKIP_SPACES;
|
||||
if (CUR != '=') {
|
||||
virConfError(NULL, VIR_ERR_CONF_SYNTAX, "expecting an assignment",
|
||||
ctxt->line);
|
||||
return(-1);
|
||||
}
|
||||
NEXT;
|
||||
SKIP_SPACES;
|
||||
value = virConfParseValue(ctxt);
|
||||
if (value == NULL) {
|
||||
free(name);
|
||||
return(-1);
|
||||
}
|
||||
SKIP_SPACES;
|
||||
if (CUR == '#') {
|
||||
NEXT;
|
||||
base = ctxt->cur;
|
||||
while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
|
||||
comm = strndup(base, ctxt->cur - base);
|
||||
if (comm == NULL) {
|
||||
virConfError(NULL, VIR_ERR_NO_MEMORY, "Allocating configuration",
|
||||
ctxt->line);
|
||||
free(name);
|
||||
virConfFreeValue(value);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
|
||||
free(name);
|
||||
virConfFreeValue(value);
|
||||
if (comm != NULL)
|
||||
free(comm);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* virConfParse:
|
||||
* @filename: the name to report errors
|
||||
* @content: the configuration content in memory
|
||||
* @len: the length in bytes
|
||||
*
|
||||
* Parse the subset of the Python language needed to handle simple
|
||||
* Xen configuration files.
|
||||
*
|
||||
* Returns an 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) {
|
||||
virConfParserCtxt ctxt;
|
||||
|
||||
ctxt.filename = filename;
|
||||
ctxt.base = ctxt.cur = content;
|
||||
ctxt.end = content + len - 1;
|
||||
ctxt.line = 1;
|
||||
|
||||
ctxt.conf = virConfCreate(filename);
|
||||
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 *
|
||||
* *
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* virConfReadFile:
|
||||
* @filename: the path to the configuration file.
|
||||
*
|
||||
* Reads a configuration file.
|
||||
*
|
||||
* Returns an 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)
|
||||
{
|
||||
char content[4096];
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
if (filename == NULL) {
|
||||
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__, 0);
|
||||
return(NULL);
|
||||
}
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
virConfError(NULL, VIR_ERR_OPEN_FAILED, filename, 0);
|
||||
return(NULL);
|
||||
}
|
||||
len = read(fd, content, sizeof(content));
|
||||
close(fd);
|
||||
if (len <= 0) {
|
||||
virConfError(NULL, VIR_ERR_READ_FAILED, filename, 0);
|
||||
return(NULL);
|
||||
}
|
||||
return(virConfParse(filename, content, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* virConfReadMem:
|
||||
* @memory: pointer to the content of the configuration file
|
||||
* @len: lenght in byte
|
||||
*
|
||||
* Reads a configuration file loaded in memory. The string can be
|
||||
* zero terminated in which case @len can be 0
|
||||
*
|
||||
* Returns an 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)
|
||||
{
|
||||
if ((memory == NULL) || (len < 0)) {
|
||||
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__, 0);
|
||||
return(NULL);
|
||||
}
|
||||
if (len == 0)
|
||||
len = strlen(memory);
|
||||
|
||||
return(virConfParse("memory conf", memory, len));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (conf == NULL) {
|
||||
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__, 0);
|
||||
return(-1);
|
||||
}
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
virBufferPtr buf;
|
||||
virConfEntryPtr cur;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
if (conf == NULL)
|
||||
return(-1);
|
||||
|
||||
buf = virBufferNew(500);
|
||||
if (buf == NULL)
|
||||
return(-1);
|
||||
|
||||
cur = conf->entries;
|
||||
while (cur != NULL) {
|
||||
virConfSaveEntry(buf, cur);
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
|
||||
if (fd < 0) {
|
||||
virConfError(NULL, VIR_ERR_WRITE_FAILED, "failed to open file", 0);
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = write(fd, buf->content, buf->use);
|
||||
close(fd);
|
||||
if (ret != (int) buf->use) {
|
||||
virConfError(NULL, VIR_ERR_WRITE_FAILED, "failed to save content", 0);
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
virBufferFree(buf);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* virConfWriteMem:
|
||||
* @memory: pointer to the memory to store the config file
|
||||
* @len: pointer to the lenght in byte 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)
|
||||
{
|
||||
virBufferPtr buf;
|
||||
virConfEntryPtr cur;
|
||||
int ret;
|
||||
|
||||
if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
|
||||
return(-1);
|
||||
|
||||
buf = virBufferNew(500);
|
||||
if (buf == NULL)
|
||||
return(-1);
|
||||
|
||||
cur = conf->entries;
|
||||
while (cur != NULL) {
|
||||
virConfSaveEntry(buf, cur);
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if ((int) buf->use >= *len) {
|
||||
*len = buf->use;
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
memcpy(memory, buf->content, buf->use);
|
||||
ret = buf->use;
|
||||
|
||||
error:
|
||||
virBufferFree(buf);
|
||||
return(ret);
|
||||
}
|
69
src/conf.h
Normal file
69
src/conf.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* conf.h: parser for a subset of the Python encoded Xen configuration files
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc.
|
||||
*
|
||||
* See COPYING.LIB for the License of this software
|
||||
*
|
||||
* Daniel Veillard <veillard@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __VIR_CONF_H__
|
||||
#define __VIR_CONF_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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 virConfReadFile (const char *filename);
|
||||
virConfPtr virConfReadMem (const char *memory,
|
||||
int len);
|
||||
int virConfFree (virConfPtr conf);
|
||||
|
||||
virConfValuePtr virConfGetValue (virConfPtr conf,
|
||||
const char *setting);
|
||||
int virConfWriteFile (const char *filename,
|
||||
virConfPtr conf);
|
||||
int virConfWriteMem (char *memory,
|
||||
int *len,
|
||||
virConfPtr conf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __VIR_CONF_H__ */
|
@ -539,6 +539,36 @@ __virErrorMsg(virErrorNumber error, const char *info)
|
||||
else
|
||||
errmsg = "operation %s forbidden for read only access";
|
||||
break;
|
||||
case VIR_ERR_OPEN_FAILED:
|
||||
if (info == NULL)
|
||||
errmsg = "failed to open configuration file for reading";
|
||||
else
|
||||
errmsg = "failed to open %s for reading";
|
||||
break;
|
||||
case VIR_ERR_READ_FAILED:
|
||||
if (info == NULL)
|
||||
errmsg = "failed to read configuration file";
|
||||
else
|
||||
errmsg = "failed to read configuration file %s";
|
||||
break;
|
||||
case VIR_ERR_PARSE_FAILED:
|
||||
if (info == NULL)
|
||||
errmsg = "failed to parse configuration file";
|
||||
else
|
||||
errmsg = "failed to parse configuration file %s";
|
||||
break;
|
||||
case VIR_ERR_CONF_SYNTAX:
|
||||
if (info == NULL)
|
||||
errmsg = "configuration file syntax error";
|
||||
else
|
||||
errmsg = "configuration file syntax error: %s";
|
||||
break;
|
||||
case VIR_ERR_WRITE_FAILED:
|
||||
if (info == NULL)
|
||||
errmsg = "failed to write configuration file";
|
||||
else
|
||||
errmsg = "failed to write configuration file: %s";
|
||||
break;
|
||||
}
|
||||
return (errmsg);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* xen_internal.c: direct access to Xen hypervisor level
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc.
|
||||
* Copyright (C) 2005, 2006 Red Hat, Inc.
|
||||
*
|
||||
* See COPYING.LIB for the License of this software
|
||||
*
|
||||
|
@ -17,11 +17,11 @@ LDADDS = \
|
||||
@LIBXML_LIBS@ \
|
||||
$(LIBVIRT)
|
||||
|
||||
EXTRA_DIST = xmlrpcserver.py
|
||||
EXTRA_DIST = xmlrpcserver.py test_conf.sh
|
||||
|
||||
noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest virshtest
|
||||
noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest virshtest conftest
|
||||
|
||||
TESTS = xml2sexprtest sexpr2xmltest virshtest
|
||||
TESTS = xml2sexprtest sexpr2xmltest virshtest test_conf.sh
|
||||
|
||||
valgrind:
|
||||
$(MAKE) check TESTS_ENVIRONMENT="valgrind --quiet"
|
||||
@ -54,5 +54,10 @@ virshtest_SOURCES = \
|
||||
virshtest_LDFLAGS =
|
||||
virshtest_LDADD = $(LDADDS)
|
||||
|
||||
conftest_SOURCES = \
|
||||
conftest.c
|
||||
conftest_LDFLAGS =
|
||||
conftest_LDADD = $(LDADDS)
|
||||
|
||||
$(LIBVIRT):
|
||||
-@(cd $(top_builddir)/src && $(MAKE) MAKEFLAGS+=--silent)
|
||||
|
2
tests/confdata/Makefile.am
Normal file
2
tests/confdata/Makefile.am
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
EXTRA_DIST = $(wildcard *.in) $(wildcard *.out)
|
10
tests/confdata/fc4.conf
Normal file
10
tests/confdata/fc4.conf
Normal file
@ -0,0 +1,10 @@
|
||||
kernel="/boot/vmlinuz-2.6.15-1.2054_FC5xenU"
|
||||
ramdisk="/boot/initrd-2.6.15-1.2054_FC5xenU.img"
|
||||
memory=128 # should be enough
|
||||
name="fc4"
|
||||
vif = [ 'mac=aa:00:00:00:00:11, bridge=xenbr0' ]
|
||||
disk = ['file:/xen/fc4.img,sda1,w']
|
||||
root = "/dev/sda1"
|
||||
extra = "ro selinux=0 3"
|
||||
# just for testing ...
|
||||
tst = [ 1, 2, [ 3, 4 ], 5]
|
10
tests/confdata/fc4.out
Normal file
10
tests/confdata/fc4.out
Normal file
@ -0,0 +1,10 @@
|
||||
kernel = "/boot/vmlinuz-2.6.15-1.2054_FC5xenU"
|
||||
ramdisk = "/boot/initrd-2.6.15-1.2054_FC5xenU.img"
|
||||
memory = 128 # should be enough
|
||||
name = "fc4"
|
||||
vif = [ "mac=aa:00:00:00:00:11, bridge=xenbr0" ]
|
||||
disk = [ "file:/xen/fc4.img,sda1,w" ]
|
||||
root = "/dev/sda1"
|
||||
extra = "ro selinux=0 3"
|
||||
# just for testing ...
|
||||
tst = [ 1, 2, [ 3, 4 ], 5 ]
|
30
tests/conftest.c
Normal file
30
tests/conftest.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "conf.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
virConfPtr conf;
|
||||
int len = 10000;
|
||||
char buffer[10000];
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s conf_file\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
conf = virConfReadFile(argv[1]);
|
||||
if (conf == NULL) {
|
||||
fprintf(stderr, "Failed to process %s\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
ret = virConfWriteMem(&buffer[0], &len, conf);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to serialize %s back\n", argv[1]);
|
||||
exit(3);
|
||||
}
|
||||
printf("%s", buffer);
|
||||
virConfFree(conf);
|
||||
exit(0);
|
||||
}
|
17
tests/test_conf.sh
Executable file
17
tests/test_conf.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
NOK=0
|
||||
for f in confdata/*.conf
|
||||
do
|
||||
./conftest $f > conftest.$$
|
||||
outfile=`echo $f | sed s+\.conf+\.out+`
|
||||
diff $outfile conftest.$$ > /dev/null
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "$f FAILED"
|
||||
NOK=1
|
||||
else
|
||||
echo "$f OK"
|
||||
fi
|
||||
done
|
||||
rm -f conftest.$$
|
||||
exit $NOK
|
Loading…
Reference in New Issue
Block a user