libvirt/src/conf.c

969 lines
24 KiB
C
Raw Normal View History

/**
* conf.c: parser for a subset of the Python encoded Xen configuration files
*
* Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
*
* See COPYING.LIB for the License of this software
*
* Daniel Veillard <veillard@redhat.com>
*/
#include <config.h>
Use gnulib, starting with its physmem and getaddrinfo modules. New files go into these directories: gnulib/lib gnulib/m4 gnulib/tests * bootstrap: A wrapper around gnulib-tool. * configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY before any macro that uses AC_COMPILE_IFELSE. (AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile. * Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests early enough that those tests run before any libvirt unit tests. * m4/Makefile.am: Remove file. Not needed. * src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib. (LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la. * src/nodeinfo.c: Include "physmem.h". * qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h". (MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions. (virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate. * tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib. (LDADDS): Add ../gnulib/lib/libgnu.la. * qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la. * tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total memory from a file. Update expected output not to include "Memory: NNNN" * tests/nodeinfodata/linux-nodeinfo-1.txt: * tests/nodeinfodata/linux-nodeinfo-2.txt: * tests/nodeinfodata/linux-nodeinfo-3.txt: * tests/nodeinfodata/linux-nodeinfo-4.txt: * tests/nodeinfodata/linux-nodeinfo-5.txt: * tests/nodeinfodata/linux-nodeinfo-6.txt: * src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that would conflict with the one now in "config.h". * autogen.sh: Add -I gnulib/m4. * src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE. Instead, include "config.h". * qemud/qemud.c: Remove definition of _GNU_SOURCE. * src/openvz_driver.c: Likewise. * src/qemu_driver.c: Likewise. * src/remote_internal.c: Likewise. * configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch of gettextize-generated files go into build-aux/, rather than in the top-level directory. * .cvsignore: Adjust. * build-aux/.cvsignore: New file. Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "internal.h"
#include "buf.h"
#include "conf.h"
#include "util.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, 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->type == VIR_CONF_STRING &&
val->str != NULL)
free(val->str);
if (val->type == VIR_CONF_LIST &&
val->list != NULL)
virConfFreeList(val->list);
free(val);
}
2007-03-09 20:47:12 +00:00
virConfPtr
__virConfNew(void)
{
virConfPtr ret;
ret = calloc(1, sizeof(*ret));
if (ret == NULL) {
virConfError(NULL, VIR_ERR_NO_MEMORY, _("allocating configuration"), 0);
return(NULL);
}
ret->filename = NULL;
return(ret);
}
/**
* 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 = virConfNew();
if (ret)
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 = calloc(1, sizeof(*ret));
if (ret == NULL) {
virConfError(NULL, VIR_ERR_NO_MEMORY, _("allocating configuration"), 0);
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:
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;
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) || (!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;
}
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(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;
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;
}
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 = calloc(1, sizeof(*ret));
if (ret == NULL) {
virConfError(NULL, VIR_ERR_NO_MEMORY, _("allocating configuration"), 0);
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_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)) || (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);
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 *
* *
************************************************************************/
/* 10 MB limit on config file size as a sanity check */
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)
/**
2007-03-09 20:47:12 +00:00
* __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
2007-03-09 20:47:12 +00:00
__virConfReadFile(const char *filename)
{
char *content;
int len;
virConfPtr conf;
if (filename == NULL) {
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__, 0);
return(NULL);
}
if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) {
virConfError(NULL, VIR_ERR_OPEN_FAILED, filename, 0);
return NULL;
}
conf = virConfParse(filename, content, len);
free(content);
return conf;
}
/**
2007-03-09 20:47:12 +00:00
* __virConfReadMem:
* @memory: pointer to the content of the configuration file
* @len: length 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
2007-03-09 20:47:12 +00:00
__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));
}
/**
2007-03-09 20:47:12 +00:00
* __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
2007-03-09 20:47:12 +00:00
__virConfFree(virConfPtr conf)
{
virConfEntryPtr tmp;
if (conf == NULL) {
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__, 0);
return(-1);
}
tmp = conf->entries;
while (tmp) {
virConfEntryPtr next;
free(tmp->name);
virConfFreeValue(tmp->value);
free(tmp->comment);
next = tmp->next;
free(tmp);
tmp = next;
}
free(conf);
return(0);
}
/**
2007-03-09 20:47:12 +00:00
* __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
2007-03-09 20:47:12 +00:00
__virConfGetValue(virConfPtr conf, const char *setting)
{
virConfEntryPtr cur;
cur = conf->entries;
while (cur != NULL) {
if ((cur->name != NULL) && (STREQ(cur->name, setting)))
return(cur->value);
cur = cur->next;
}
return(NULL);
}
/**
2007-03-09 20:47:12 +00:00
* __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.
*/
2007-03-09 20:47:12 +00:00
int
__virConfSetValue (virConfPtr conf,
const char *setting,
virConfValuePtr value)
{
virConfEntryPtr cur, prev = NULL;
cur = conf->entries;
while (cur != NULL) {
if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
break;
}
prev = cur;
cur = cur->next;
}
if (!cur) {
if (!(cur = malloc(sizeof(*cur)))) {
virConfFreeValue(value);
return (-1);
}
cur->comment = NULL;
if (!(cur->name = strdup(setting))) {
virConfFreeValue(value);
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 {
if (cur->value) {
virConfFreeValue(cur->value);
}
cur->value = value;
}
return (0);
}
/**
2007-03-09 20:47:12 +00:00
* __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
2007-03-09 20:47:12 +00:00
__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)) {
virConfError(NULL, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
return -1;
}
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);
free(virBufferContentAndReset(&buf));
return -1;
}
use = virBufferUse(&buf);
content = virBufferContentAndReset(&buf);
ret = safewrite(fd, content, use);
free(content);
close(fd);
if (ret != (int)use) {
virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"), 0);
return -1;
}
return ret;
}
/**
2007-03-09 20:47:12 +00:00
* __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
2007-03-09 20:47:12 +00:00
__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)) {
virConfError(NULL, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
return -1;
}
use = virBufferUse(&buf);
content = virBufferContentAndReset(&buf);
if ((int)use >= *len) {
*len = (int)use;
free(content);
return -1;
}
memcpy(memory, content, use);
free(content);
*len = use;
return use;
}