2012-12-12 16:35:35 +00:00
|
|
|
/*
|
|
|
|
* virconf.c: parser for a subset of the Python encoded Xen configuration files
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
2014-03-18 08:14:35 +00:00
|
|
|
* Copyright (C) 2006-2014 Red Hat, Inc.
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
2012-07-27 09:39:53 +00:00
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-27 09:39:53 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2006-08-29 22:27:07 +00:00
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#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
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 16:35:35 +00:00
|
|
|
#include "virconf.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-05-24 07:19:51 +00:00
|
|
|
#include "virstring.h"
|
2015-10-12 14:09:53 +00:00
|
|
|
#include "configmake.h"
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2009-01-29 12:10:32 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_CONF
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.conf");
|
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
typedef struct _virConfParserCtxt virConfParserCtxt;
|
|
|
|
struct _virConfParserCtxt {
|
|
|
|
const char* filename;
|
|
|
|
const char* base;
|
|
|
|
const char* cur;
|
|
|
|
const char *end;
|
|
|
|
int line;
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *conf;
|
2006-08-29 22:27:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define CUR (*ctxt->cur)
|
|
|
|
#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++;
|
|
|
|
#define IS_EOL(c) (((c) == '\n') || ((c) == '\r'))
|
2019-11-18 14:07:06 +00:00
|
|
|
#define IS_BLANK(c) (((c) == ' ') || ((c) == '\t'))
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define SKIP_BLANKS_AND_EOL \
|
2019-11-18 14:07:06 +00:00
|
|
|
do { while ((ctxt->cur < ctxt->end) && (IS_BLANK(CUR) || IS_EOL(CUR))) { \
|
2017-11-03 12:09:47 +00:00
|
|
|
if (CUR == '\n') ctxt->line++; \
|
2013-05-24 16:58:25 +00:00
|
|
|
ctxt->cur++; } } while (0)
|
2017-11-03 12:09:47 +00:00
|
|
|
#define SKIP_BLANKS \
|
2019-11-18 14:07:06 +00:00
|
|
|
do { while ((ctxt->cur < ctxt->end) && (IS_BLANK(CUR))) \
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
ctxt->cur++; } while (0)
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virConf,
|
|
|
|
VIR_CONF_LAST,
|
2014-12-09 13:53:28 +00:00
|
|
|
"*unexpected*",
|
|
|
|
"long",
|
2014-12-09 15:22:09 +00:00
|
|
|
"unsigned long",
|
2014-12-09 13:53:28 +00:00
|
|
|
"string",
|
2019-01-20 16:30:15 +00:00
|
|
|
"list",
|
|
|
|
);
|
2014-12-09 13:53:28 +00:00
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
typedef struct _virConfEntry virConfEntry;
|
|
|
|
struct _virConfEntry {
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *next;
|
2006-08-29 22:27:07 +00:00
|
|
|
char* name;
|
|
|
|
char* comment;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *value;
|
2006-08-29 22:27:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _virConf {
|
2016-07-07 15:52:47 +00:00
|
|
|
char *filename;
|
2009-06-19 12:34:30 +00:00
|
|
|
unsigned int flags;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *entries;
|
2006-08-29 22:27:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfError:
|
2008-09-17 14:11:21 +00:00
|
|
|
* @ctxt: the parser context if available or NULL
|
2006-08-29 22:27:07 +00:00
|
|
|
* @error: the error number
|
|
|
|
* @info: extra information string
|
|
|
|
*
|
|
|
|
* Handle an error at the xend daemon interface
|
|
|
|
*/
|
2011-11-28 23:13:40 +00:00
|
|
|
#define virConfError(ctxt, error, info) \
|
|
|
|
virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info)
|
2006-08-29 22:27:07 +00:00
|
|
|
static void
|
2011-11-28 23:13:40 +00:00
|
|
|
virConfErrorHelper(const char *file, const char *func, size_t line,
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParserCtxt *ctxt,
|
2011-11-28 23:13:40 +00:00
|
|
|
virErrorNumber error, const char *info)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
if (error == VIR_ERR_OK)
|
|
|
|
return;
|
|
|
|
|
2008-09-17 14:11:21 +00:00
|
|
|
/* Construct the string 'filename:line: info' if we have that. */
|
|
|
|
if (ctxt && ctxt->filename) {
|
2011-11-28 23:13:40 +00:00
|
|
|
virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
|
|
|
|
_("%s:%d: %s"), ctxt->filename, ctxt->line, info);
|
2008-09-17 14:11:21 +00:00
|
|
|
} else {
|
2011-11-28 23:13:40 +00:00
|
|
|
virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
|
|
|
|
"%s", info);
|
2008-09-17 14:11:21 +00:00
|
|
|
}
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfFreeList:
|
|
|
|
* @list: the list to free
|
|
|
|
*
|
|
|
|
* Free a list
|
|
|
|
*/
|
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfFreeList(virConfValue *list)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *next;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
while (list != NULL) {
|
2021-03-24 09:32:58 +00:00
|
|
|
next = g_steal_pointer(&list->next);
|
2007-01-19 20:10:04 +00:00
|
|
|
virConfFreeValue(list);
|
|
|
|
list = next;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfFreeValue:
|
|
|
|
* @val: the value to free
|
|
|
|
*
|
|
|
|
* Free a value
|
|
|
|
*/
|
2008-05-29 19:20:22 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfFreeValue(virConfValue *val)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
if (val == NULL)
|
|
|
|
return;
|
2007-01-19 20:10:04 +00:00
|
|
|
if (val->type == VIR_CONF_STRING &&
|
|
|
|
val->str != NULL)
|
2021-02-09 17:27:39 +00:00
|
|
|
g_free(val->str);
|
2007-01-19 20:10:04 +00:00
|
|
|
if (val->type == VIR_CONF_LIST &&
|
|
|
|
val->list != NULL)
|
2006-08-29 22:27:07 +00:00
|
|
|
virConfFreeList(val->list);
|
2021-02-09 17:27:39 +00:00
|
|
|
g_free(val);
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *
|
2008-11-17 11:03:25 +00:00
|
|
|
virConfNew(void)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2020-10-05 17:09:27 +00:00
|
|
|
ret = g_new0(virConf, 1);
|
2006-11-15 19:46:23 +00:00
|
|
|
ret->filename = NULL;
|
2009-06-19 12:34:30 +00:00
|
|
|
ret->flags = 0;
|
2006-11-15 19:46:23 +00:00
|
|
|
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-11-15 19:46:23 +00:00
|
|
|
}
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2006-11-15 19:46:23 +00:00
|
|
|
/**
|
|
|
|
* virConfCreate:
|
|
|
|
* @filename: the name to report errors
|
2009-06-19 12:34:30 +00:00
|
|
|
* @flags: combination of virConfFlag(s)
|
2006-11-15 19:46:23 +00:00
|
|
|
*
|
|
|
|
* Create a configuration internal structure
|
|
|
|
*
|
|
|
|
* Returns a pointer or NULL in case of error.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virConf *
|
2009-06-19 12:34:30 +00:00
|
|
|
virConfCreate(const char *filename, unsigned int flags)
|
2006-11-15 19:46:23 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *ret = virConfNew();
|
2016-07-07 15:52:47 +00:00
|
|
|
if (!ret)
|
|
|
|
return NULL;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
ret->filename = g_strdup(filename);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
ret->flags = flags;
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virConfEntry *
|
|
|
|
virConfAddEntry(virConf *conf, char *name, virConfValue *value, char *comm)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *ret;
|
|
|
|
virConfEntry *prev;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
if (conf == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
if ((comm == NULL) && (name == NULL))
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2017-05-12 14:29:15 +00:00
|
|
|
/* don't log fully commented out lines */
|
|
|
|
if (name)
|
|
|
|
VIR_DEBUG("Add entry %s %p", name, value);
|
|
|
|
|
2020-10-05 17:09:27 +00:00
|
|
|
ret = g_new0(virConfEntry, 1);
|
2007-01-19 20:10:04 +00:00
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
ret->name = name;
|
|
|
|
ret->value = value;
|
|
|
|
ret->comment = comm;
|
|
|
|
|
|
|
|
if (conf->entries == NULL) {
|
|
|
|
conf->entries = ret;
|
|
|
|
} else {
|
|
|
|
prev = conf->entries;
|
2008-04-10 16:54:54 +00:00
|
|
|
while (prev->next != NULL)
|
|
|
|
prev = prev->next;
|
|
|
|
prev->next = ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfSaveValue(virBuffer *buf, virConfValue *val)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
if (val == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
switch (val->type) {
|
|
|
|
case VIR_CONF_NONE:
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2016-07-15 15:36:32 +00:00
|
|
|
case VIR_CONF_LLONG:
|
2016-07-07 15:52:47 +00:00
|
|
|
virBufferAsprintf(buf, "%lld", val->l);
|
|
|
|
break;
|
2016-07-15 15:36:32 +00:00
|
|
|
case VIR_CONF_ULLONG:
|
2016-07-07 15:52:47 +00:00
|
|
|
virBufferAsprintf(buf, "%llu", val->l);
|
2008-04-10 16:54:54 +00:00
|
|
|
break;
|
|
|
|
case VIR_CONF_STRING:
|
virConfSaveValue: protect against a NULL pointer reference
Fix xlconfigtest runs build for --enable-test-oom on
Xen XL-2-XML Parse channel-pty
Program received signal SIGSEGV, Segmentation fault.
#0 0x00007ffff3c2b373 in __strchr_sse2 () from /lib64/libc.so.6
==> #1 0x00007ffff7875701 in virConfSaveValue (buf=buf@entry=0x7fffffffd8a0, val=val@entry=0x674750) at util/virconf.c:290
#2 0x00007ffff7875668 in virConfSaveValue (buf=buf@entry=0x7fffffffd8a0, val=<optimized out>) at util/virconf.c:306
#3 0x00007ffff78757ef in virConfSaveEntry (buf=buf@entry=0x7fffffffd8a0, cur=cur@entry=0x674780) at util/virconf.c:338
#4 0x00007ffff78783eb in virConfWriteMem (memory=0x665570 "", len=len@entry=0x7fffffffd910, conf=conf@entry=0x65b940)
at util/virconf.c:1543
#5 0x000000000040eccb in testCompareParseXML (replaceVars=<optimized out>, xml=<optimized out>,
xlcfg=0x662c00 "/home/wtenhave/WORK/libvirt/OOMtesting/libvirt-devel/tests/xlconfigdata/test-channel-pty.cfg")
at xlconfigtest.c:108
#6 testCompareHelper (data=<optimized out>) at xlconfigtest.c:205
#7 0x0000000000410b3a in virTestRun (title=title@entry=0x432cc0 "Xen XL-2-XML Parse channel-pty",
body=body@entry=0x40e9b0 <testCompareHelper>, data=data@entry=0x7fffffffd9f0) at testutils.c:247
#8 0x000000000040f322 in mymain () at xlconfigtest.c:278
#9 0x0000000000411410 in virTestMain (argc=1, argv=0x7fffffffdba8, func=0x40f660 <mymain>) at testutils.c:992
#10 0x00007ffff3bc0401 in __libc_start_main () from /lib64/libc.so.6
#11 0x000000000040e86a in _start ()
(gdb) frame 1
#1 0x00007ffff7875701 in virConfSaveValue (buf=buf@entry=0x7fffffffd8a0, val=val@entry=0x674750) at util/virconf.c:290
290 if (strchr(val->str, '\n') != NULL) {
(gdb) print *val
$1 = {type = VIR_CONF_STRING, next = 0x0, l = 0, str = 0x0, list = 0x0}
Signed-off-by: Wim ten Have <wim.ten.have@oracle.com>
2017-03-27 20:20:43 +00:00
|
|
|
if (val->str) {
|
|
|
|
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);
|
|
|
|
}
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_CONF_LIST: {
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cur;
|
2008-04-10 16:54:54 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_CONF_LAST:
|
2008-04-10 16:54:54 +00:00
|
|
|
default:
|
2018-02-14 09:43:59 +00:00
|
|
|
virReportEnumRangeError(virConfType, val->type);
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfSaveEntry(virBuffer *buf, virConfEntry *cur)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
if (cur->name != NULL) {
|
|
|
|
virBufferAdd(buf, cur->name, -1);
|
2008-04-10 16:54:54 +00:00
|
|
|
virBufferAddLit(buf, " = ");
|
|
|
|
virConfSaveValue(buf, cur->value);
|
|
|
|
if (cur->comment != NULL) {
|
|
|
|
virBufferAddLit(buf, " #");
|
|
|
|
virBufferAdd(buf, cur->comment, -1);
|
|
|
|
}
|
2006-08-29 22:27:07 +00:00
|
|
|
} else if (cur->comment != NULL) {
|
2008-04-10 16:54:54 +00:00
|
|
|
virBufferAddLit(buf, "#");
|
|
|
|
virBufferAdd(buf, cur->comment, -1);
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
Eliminate all uses of virBufferAdd with string literals.
* Makefile.maint (sc_prohibit_virBufferAdd_with_string_literal):
New rule.
* src/buf.h (virBufferAddLit): Define.
* src/conf.c (virConfSaveValue): Use virBufferAddLit, in place
of virBufferAdd everywhere possible.
(virConfSaveEntry): Likewise.
* src/qemu_conf.c (qemudGenerateXML, qemudGenerateNetworkXML): Likewise.
* src/qemu_driver.c (qemudGetFeatures, qemudGetCapabilities): Likewise.
* src/test.c (testDomainDumpXML, testNetworkDumpXML): Likewise.
* src/xen_internal.c (xenHypervisorMakeCapabilitiesXML): Likewise.
* src/xend_internal.c (xend_parse_sexp_desc_os): Likewise.
(xend_parse_sexp_desc, sexpr_to_xend_topology_xml): Likewise.
* src/xm_internal.c (xenXMDomainFormatXML, xenXMDomainPinVcpu): Likewise.
* src/xml.c (virSaveCpuSet, virParseXenCpuTopology): Likewise.
(virDomainParseXMLGraphicsDescImage): Likewise.
(virDomainParseXMLGraphicsDescVFB, virDomainParseXMLOSDescHVM): Likewise.
(virDomainParseXMLOSDescPV, virDomainParseXMLDiskDesc): Likewise.
(virDomainParseXMLIfDesc, virDomainParseXMLDesc): Likewise.
2008-02-05 14:22:28 +00:00
|
|
|
virBufferAddLit(buf, "\n");
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseLong(virConfParserCtxt *ctxt, long long *val)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2016-07-15 11:53:57 +00:00
|
|
|
long long l = 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
int neg = 0;
|
|
|
|
|
|
|
|
if (CUR == '-') {
|
|
|
|
neg = 1;
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else if (CUR == '+') {
|
|
|
|
NEXT;
|
|
|
|
}
|
2019-11-18 14:13:11 +00:00
|
|
|
if ((ctxt->cur >= ctxt->end) || (!g_ascii_isdigit(CUR))) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2019-11-18 14:13:11 +00:00
|
|
|
while ((ctxt->cur < ctxt->end) && (g_ascii_isdigit(CUR))) {
|
2006-08-29 22:27:07 +00:00
|
|
|
l = l * 10 + (CUR - '0');
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2007-10-19 10:01:01 +00:00
|
|
|
if (neg)
|
|
|
|
l = -l;
|
2006-08-29 22:27:07 +00:00
|
|
|
*val = l;
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfParseString:
|
|
|
|
* @ctxt: the parsing context
|
|
|
|
*
|
|
|
|
* Parse one string
|
|
|
|
*
|
|
|
|
* Returns a pointer to the string or NULL in case of error
|
|
|
|
*/
|
|
|
|
static char *
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseString(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
const char *base;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (CUR == '\'') {
|
|
|
|
NEXT;
|
2008-04-10 16:54:54 +00:00
|
|
|
base = ctxt->cur;
|
|
|
|
while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
|
|
|
|
NEXT;
|
|
|
|
if (CUR != '\'') {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
2019-10-24 17:41:34 +00:00
|
|
|
ret = g_strndup(base, ctxt->cur - base);
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
2010-11-18 22:33:36 +00:00
|
|
|
} else if ((ctxt->cur + 6 < ctxt->end) &&
|
|
|
|
(STRPREFIX(ctxt->cur, "\"\"\""))) {
|
|
|
|
/* String starts with python-style triple quotes """ */
|
2008-04-10 16:54:54 +00:00
|
|
|
ctxt->cur += 3;
|
|
|
|
base = ctxt->cur;
|
2010-11-18 22:33:36 +00:00
|
|
|
|
2010-11-18 22:35:23 +00:00
|
|
|
/* Find the ending triple quotes */
|
2010-11-18 22:33:36 +00:00
|
|
|
while ((ctxt->cur + 2 < ctxt->end) &&
|
2010-11-18 22:35:23 +00:00
|
|
|
!(STRPREFIX(ctxt->cur, "\"\"\""))) {
|
2010-11-18 22:33:36 +00:00
|
|
|
if (CUR == '\n')
|
|
|
|
ctxt->line++;
|
|
|
|
NEXT;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
2010-11-18 22:33:36 +00:00
|
|
|
|
|
|
|
if (!STRPREFIX(ctxt->cur, "\"\"\"")) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
2019-10-24 17:41:34 +00:00
|
|
|
ret = g_strndup(base, ctxt->cur - base);
|
2008-04-10 16:54:54 +00:00
|
|
|
ctxt->cur += 3;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else if (CUR == '"') {
|
|
|
|
NEXT;
|
2008-04-10 16:54:54 +00:00
|
|
|
base = ctxt->cur;
|
|
|
|
while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
|
|
|
|
NEXT;
|
|
|
|
if (CUR != '"') {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
2019-10-24 17:41:34 +00:00
|
|
|
ret = g_strndup(base, ctxt->cur - base);
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
2014-02-05 14:09:59 +00:00
|
|
|
} else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) {
|
|
|
|
base = ctxt->cur;
|
|
|
|
/* LXC config format doesn't support comments after the value */
|
|
|
|
while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR)))
|
|
|
|
NEXT;
|
|
|
|
/* Reverse to exclude the trailing blanks from the value */
|
2019-11-18 14:07:06 +00:00
|
|
|
while ((ctxt->cur > base) && (IS_BLANK(CUR)))
|
2014-02-05 14:09:59 +00:00
|
|
|
ctxt->cur--;
|
2019-10-24 17:41:34 +00:00
|
|
|
ret = g_strndup(base, ctxt->cur - base);
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfParseValue:
|
|
|
|
* @ctxt: the parsing context
|
|
|
|
*
|
|
|
|
* Parse one value
|
|
|
|
*
|
|
|
|
* Returns a pointer to the value or NULL in case of error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virConfValue *
|
|
|
|
virConfParseValue(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *ret;
|
|
|
|
virConfValue *lst = NULL;
|
|
|
|
virConfValue *tmp;
|
|
|
|
virConfValue *prev;
|
2006-08-29 22:27:07 +00:00
|
|
|
virConfType type = VIR_CONF_NONE;
|
|
|
|
char *str = NULL;
|
2016-07-15 11:53:57 +00:00
|
|
|
long long l = 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
if (ctxt->cur >= ctxt->end) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2014-02-05 14:09:59 +00:00
|
|
|
if ((CUR == '"') || (CUR == '\'') ||
|
2018-09-19 08:38:14 +00:00
|
|
|
(ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) {
|
2006-08-29 22:27:07 +00:00
|
|
|
type = VIR_CONF_STRING;
|
|
|
|
str = virConfParseString(ctxt);
|
2008-04-10 16:54:54 +00:00
|
|
|
if (str == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else if (CUR == '[') {
|
2009-06-22 11:54:49 +00:00
|
|
|
if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
|
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("lists not allowed in VMX format"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2009-06-22 11:54:49 +00:00
|
|
|
}
|
2006-08-29 22:27:07 +00:00
|
|
|
type = VIR_CONF_LIST;
|
|
|
|
NEXT;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2008-04-10 16:54:54 +00:00
|
|
|
if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
|
2008-06-06 11:09:57 +00:00
|
|
|
if ((lst = virConfParseValue(ctxt)) == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
|
2010-04-07 18:54:50 +00:00
|
|
|
|
2008-04-10 16:54:54 +00:00
|
|
|
if (CUR != ',') {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("expecting a separator in list"));
|
2008-04-10 16:54:54 +00:00
|
|
|
virConfFreeList(lst);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
NEXT;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2014-11-13 14:28:18 +00:00
|
|
|
if (CUR == ']')
|
2008-04-10 16:54:54 +00:00
|
|
|
break;
|
|
|
|
tmp = virConfParseValue(ctxt);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
virConfFreeList(lst);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
prev = lst;
|
|
|
|
while (prev->next != NULL) prev = prev->next;
|
|
|
|
prev->next = tmp;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
if (CUR == ']') {
|
|
|
|
NEXT;
|
|
|
|
} else {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("list is not closed with ]"));
|
2008-04-10 16:54:54 +00:00
|
|
|
virConfFreeList(lst);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
2019-11-18 14:13:11 +00:00
|
|
|
} else if (g_ascii_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
|
2009-06-22 11:54:49 +00:00
|
|
|
if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
|
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("numbers not allowed in VMX format"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2009-06-22 11:54:49 +00:00
|
|
|
}
|
2016-07-15 15:36:32 +00:00
|
|
|
type = (CUR == '-') ? VIR_CONF_LLONG : VIR_CONF_ULLONG;
|
2014-11-13 14:28:18 +00:00
|
|
|
if (virConfParseLong(ctxt, &l) < 0)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2020-10-05 17:09:27 +00:00
|
|
|
ret = g_new0(virConfValue, 1);
|
2006-08-29 22:27:07 +00:00
|
|
|
ret->type = type;
|
|
|
|
ret->l = l;
|
|
|
|
ret->str = str;
|
|
|
|
ret->list = lst;
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfParseName:
|
|
|
|
* @ctxt: the parsing context
|
|
|
|
*
|
|
|
|
* Parse one name
|
|
|
|
*
|
|
|
|
* Returns a copy of the new string, NULL in case of error
|
|
|
|
*/
|
|
|
|
static char *
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseName(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
const char *base;
|
|
|
|
char *ret;
|
|
|
|
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
base = ctxt->cur;
|
|
|
|
/* TODO: probably need encoding support and UTF-8 parsing ! */
|
2019-11-18 14:11:46 +00:00
|
|
|
if (!g_ascii_isalpha(CUR) &&
|
2009-07-27 12:21:17 +00:00
|
|
|
!((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2009-06-19 12:34:30 +00:00
|
|
|
while ((ctxt->cur < ctxt->end) &&
|
2019-11-18 14:14:06 +00:00
|
|
|
(g_ascii_isalnum(CUR) || (CUR == '_') ||
|
2009-06-22 11:54:49 +00:00
|
|
|
((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
|
2014-02-05 14:09:59 +00:00
|
|
|
((CUR == ':') || (CUR == '.') || (CUR == '-'))) ||
|
|
|
|
((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) &&
|
|
|
|
(CUR == '.'))))
|
2006-08-29 22:27:07 +00:00
|
|
|
NEXT;
|
2019-10-24 17:41:34 +00:00
|
|
|
ret = g_strndup(base, ctxt->cur - base);
|
2012-03-22 11:33:35 +00:00
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseComment(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
const char *base;
|
|
|
|
char *comm;
|
|
|
|
|
|
|
|
if (CUR != '#')
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
NEXT;
|
|
|
|
base = ctxt->cur;
|
|
|
|
while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
|
2019-10-24 17:41:34 +00:00
|
|
|
comm = g_strndup(base, ctxt->cur - base);
|
2013-09-25 10:32:07 +00:00
|
|
|
if (virConfAddEntry(ctxt->conf, NULL, NULL, comm) == NULL) {
|
|
|
|
VIR_FREE(comm);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseSeparator(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
if (ctxt->cur >= ctxt->end)
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
if (IS_EOL(CUR)) {
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else if (CUR == ';') {
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2006-08-29 22:27:07 +00:00
|
|
|
} else {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfParseStatement(virConfParserCtxt *ctxt)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
|
|
|
const char *base;
|
|
|
|
char *name;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *value;
|
2006-08-29 22:27:07 +00:00
|
|
|
char *comm = NULL;
|
|
|
|
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS_AND_EOL;
|
2014-11-13 14:28:18 +00:00
|
|
|
if (CUR == '#')
|
2011-03-04 16:52:12 +00:00
|
|
|
return virConfParseComment(ctxt);
|
2006-08-29 22:27:07 +00:00
|
|
|
name = virConfParseName(ctxt);
|
|
|
|
if (name == NULL)
|
2011-03-04 16:52:12 +00:00
|
|
|
return -1;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
if (CUR != '=') {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
|
2011-03-04 16:52:12 +00:00
|
|
|
VIR_FREE(name);
|
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
NEXT;
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
value = virConfParseValue(ctxt);
|
|
|
|
if (value == NULL) {
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(name);
|
2011-03-04 16:52:12 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
SKIP_BLANKS;
|
2006-08-29 22:27:07 +00:00
|
|
|
if (CUR == '#') {
|
2008-04-10 16:54:54 +00:00
|
|
|
NEXT;
|
|
|
|
base = ctxt->cur;
|
|
|
|
while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
|
2019-10-24 17:41:34 +00:00
|
|
|
comm = g_strndup(base, ctxt->cur - base);
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(name);
|
2008-04-10 16:54:54 +00:00
|
|
|
virConfFreeValue(value);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(comm);
|
2011-03-04 16:52:12 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2011-03-04 16:52:12 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfParse:
|
|
|
|
* @filename: the name to report errors
|
|
|
|
* @content: the configuration content in memory
|
|
|
|
* @len: the length in bytes
|
2009-06-19 12:34:30 +00:00
|
|
|
* @flags: combination of virConfFlag(s)
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
|
|
|
* Parse the subset of the Python language needed to handle simple
|
|
|
|
* Xen configuration files.
|
|
|
|
*
|
2011-12-04 00:06:07 +00:00
|
|
|
* Returns a handle to lookup settings or NULL if it failed to
|
2006-08-29 22:27:07 +00:00
|
|
|
* read or parse the file, use virConfFree() to free the data.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virConf *
|
2009-06-19 12:34:30 +00:00
|
|
|
virConfParse(const char *filename, const char *content, int len,
|
2014-03-18 08:14:35 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2006-08-29 22:27:07 +00:00
|
|
|
virConfParserCtxt ctxt;
|
|
|
|
|
|
|
|
ctxt.filename = filename;
|
|
|
|
ctxt.base = ctxt.cur = content;
|
2017-11-07 21:20:44 +00:00
|
|
|
ctxt.end = content + len;
|
2006-08-29 22:27:07 +00:00
|
|
|
ctxt.line = 1;
|
|
|
|
|
2009-06-19 12:34:30 +00:00
|
|
|
ctxt.conf = virConfCreate(filename, flags);
|
2006-08-29 22:27:07 +00:00
|
|
|
if (ctxt.conf == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
while (ctxt.cur < ctxt.end) {
|
|
|
|
if (virConfParseStatement(&ctxt) < 0)
|
2008-04-10 16:54:54 +00:00
|
|
|
goto error;
|
|
|
|
if (virConfParseSeparator(&ctxt) < 0)
|
|
|
|
goto error;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
2012-03-22 11:33:35 +00:00
|
|
|
return ctxt.conf;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
error:
|
2006-08-29 22:27:07 +00:00
|
|
|
virConfFree(ctxt.conf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-07 15:21:33 +00:00
|
|
|
/* 10 MB limit on config file size as a sanity check */
|
|
|
|
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)
|
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfReadFile:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @filename: the path to the configuration file.
|
2009-06-19 12:34:30 +00:00
|
|
|
* @flags: combination of virConfFlag(s)
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
|
|
|
* Reads a configuration file.
|
|
|
|
*
|
2011-12-04 00:06:07 +00:00
|
|
|
* Returns a handle to lookup settings or NULL if it failed to
|
2006-08-29 22:27:07 +00:00
|
|
|
* read or parse the file, use virConfFree() to free the data.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *
|
2009-06-19 12:34:30 +00:00
|
|
|
virConfReadFile(const char *filename, unsigned int flags)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2008-01-07 15:21:33 +00:00
|
|
|
char *content;
|
2006-08-29 22:27:07 +00:00
|
|
|
int len;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *conf;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
2012-10-20 19:40:41 +00:00
|
|
|
VIR_DEBUG("filename=%s", NULLSTR(filename));
|
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
if (filename == NULL) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2008-01-07 15:21:33 +00:00
|
|
|
|
2014-11-13 14:28:18 +00:00
|
|
|
if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0)
|
2008-01-07 15:21:33 +00:00
|
|
|
return NULL;
|
|
|
|
|
2009-06-19 12:34:30 +00:00
|
|
|
conf = virConfParse(filename, content, len, flags);
|
2008-01-07 15:21:33 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(content);
|
2008-01-07 15:21:33 +00:00
|
|
|
|
|
|
|
return conf;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-08-07 15:12:02 +00:00
|
|
|
* virConfReadString:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @memory: pointer to the content of the configuration file
|
2009-06-19 12:34:30 +00:00
|
|
|
* @flags: combination of virConfFlag(s)
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
2017-08-07 15:12:02 +00:00
|
|
|
* Reads a configuration file loaded in memory. The string must be
|
|
|
|
* zero terminated.
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
2011-12-04 00:06:07 +00:00
|
|
|
* Returns a handle to lookup settings or NULL if it failed to
|
2006-08-29 22:27:07 +00:00
|
|
|
* parse the content, use virConfFree() to free the data.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virConf *
|
2017-08-07 15:12:02 +00:00
|
|
|
virConfReadString(const char *memory, unsigned int flags)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2017-08-07 15:12:02 +00:00
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (memory == NULL) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
2017-08-07 15:12:02 +00:00
|
|
|
len = strlen(memory);
|
2012-03-22 11:33:35 +00:00
|
|
|
return virConfParse("memory conf", memory, len, flags);
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfFree:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @conf: a configuration file handle
|
|
|
|
*
|
|
|
|
* Frees all data associated to the handle
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error.
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfFree(virConf *conf)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *tmp;
|
2011-10-13 10:49:45 +00:00
|
|
|
if (conf == NULL)
|
|
|
|
return 0;
|
2007-01-19 20:10:04 +00:00
|
|
|
|
|
|
|
tmp = conf->entries;
|
|
|
|
while (tmp) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *next;
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(tmp->name);
|
2007-01-19 20:10:04 +00:00
|
|
|
virConfFreeValue(tmp->value);
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(tmp->comment);
|
2007-01-19 20:10:04 +00:00
|
|
|
next = tmp->next;
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(tmp);
|
2007-01-19 20:10:04 +00:00
|
|
|
tmp = next;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(conf->filename);
|
|
|
|
g_free(conf);
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfGetValue:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @conf: a configuration file handle
|
2015-08-18 12:38:07 +00:00
|
|
|
* @setting: the name of the entry
|
2006-08-29 22:27:07 +00:00
|
|
|
*
|
|
|
|
* Lookup the value associated to this entry in the configuration file
|
|
|
|
*
|
2008-02-05 19:27:37 +00:00
|
|
|
* Returns a pointer to the value or NULL if the lookup failed, the data
|
2006-08-29 22:27:07 +00:00
|
|
|
* associated will be freed when virConfFree() is called
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *
|
|
|
|
virConfGetValue(virConf *conf, const char *setting)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *cur;
|
2006-08-29 22:45:44 +00:00
|
|
|
|
2012-03-19 10:05:30 +00:00
|
|
|
if (conf == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2006-08-29 22:45:44 +00:00
|
|
|
cur = conf->entries;
|
|
|
|
while (cur != NULL) {
|
2010-03-24 00:52:33 +00:00
|
|
|
if ((cur->name != NULL) &&
|
|
|
|
((conf->flags & VIR_CONF_FLAG_VMX_FORMAT &&
|
|
|
|
STRCASEEQ(cur->name, setting)) ||
|
|
|
|
STREQ(cur->name, setting)))
|
2012-03-22 11:33:35 +00:00
|
|
|
return cur->value;
|
2006-08-29 22:45:44 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return NULL;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueType:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
*
|
|
|
|
* Query the type of the configuration entry @setting.
|
|
|
|
*
|
|
|
|
* Returns: the entry type, or VIR_CONF_NONE if not set.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfType virConfGetValueType(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
if (!cval)
|
|
|
|
return VIR_CONF_NONE;
|
|
|
|
|
|
|
|
return cval->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueString:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold string value
|
|
|
|
*
|
|
|
|
* Get the string value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueString(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
char **value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value string %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (cval->type != VIR_CONF_STRING) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected a string for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(*value);
|
2019-10-20 11:49:46 +00:00
|
|
|
*value = g_strdup(cval->str);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueStringList:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @compatString: true to treat string entry as a 1 element list
|
|
|
|
* @value: pointer to hold NULL terminated string list
|
|
|
|
*
|
|
|
|
* Get the string list value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified. If @compatString is set to true
|
|
|
|
* and the value is present as a string, this will be turned into
|
|
|
|
* a 1 element list. The returned @value will be NULL terminated
|
|
|
|
* if set.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueStringList(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
bool compatString,
|
|
|
|
char ***values)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
size_t len;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *eval;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value string list %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2022-01-28 17:42:45 +00:00
|
|
|
g_clear_pointer(values, g_strfreev);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
switch (cval->type) {
|
|
|
|
case VIR_CONF_LIST:
|
|
|
|
/* Calc length and check items */
|
|
|
|
for (len = 0, eval = cval->list; eval; len++, eval = eval->next) {
|
|
|
|
if (eval->type != VIR_CONF_STRING) {
|
|
|
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
|
|
|
_("%s: expected a string list for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 17:09:27 +00:00
|
|
|
*values = g_new0(char *, len + 1);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
for (len = 0, eval = cval->list; eval; len++, eval = eval->next)
|
|
|
|
(*values)[len] = g_strdup(eval->str);
|
2016-07-07 15:52:47 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_CONF_STRING:
|
|
|
|
if (compatString) {
|
2020-10-05 17:09:27 +00:00
|
|
|
*values = g_new0(char *, cval->str ? 2 : 1);
|
2019-10-20 11:49:46 +00:00
|
|
|
if (cval->str)
|
|
|
|
(*values)[0] = g_strdup(cval->str);
|
2016-07-07 15:52:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-10-15 11:38:21 +00:00
|
|
|
G_GNUC_FALLTHROUGH;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_CONF_LLONG:
|
|
|
|
case VIR_CONF_ULLONG:
|
|
|
|
case VIR_CONF_NONE:
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
compatString ?
|
|
|
|
_("%s: expected a string or string list for '%s' parameter") :
|
|
|
|
_("%s: expected a string list for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
2018-02-14 09:43:59 +00:00
|
|
|
|
|
|
|
case VIR_CONF_LAST:
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virConfType, cval->type);
|
|
|
|
return -1;
|
2016-07-07 15:52:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueBool:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold boolean value
|
|
|
|
*
|
|
|
|
* Get the boolean value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value set is not 1 or 0.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueBool(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
bool *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value bool %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type != VIR_CONF_ULLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected a bool for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-15 15:07:38 +00:00
|
|
|
if (((unsigned long long)cval->l) > 1) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be 0 or 1"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = cval->l == 1;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueInt:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value is outside the
|
|
|
|
* range that can be stored in an 'int'
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueInt(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
int *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value int %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type != VIR_CONF_LLONG &&
|
|
|
|
cval->type != VIR_CONF_ULLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected a signed integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cval->l > INT_MAX || cval->l < INT_MIN) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be in range %d:%d"),
|
|
|
|
conf->filename, setting, INT_MIN, INT_MAX);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-15 16:48:07 +00:00
|
|
|
*value = (int)cval->l;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueUInt:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the unsigned integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value is outside the
|
|
|
|
* range that can be stored in an 'unsigned int'
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueUInt(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
unsigned int *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value uint %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type != VIR_CONF_ULLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected an unsigned integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-15 15:07:38 +00:00
|
|
|
if (((unsigned long long)cval->l) > UINT_MAX) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be in range 0:%u"),
|
|
|
|
conf->filename, setting, UINT_MAX);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-15 16:48:07 +00:00
|
|
|
*value = (unsigned int)cval->l;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueSizeT:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value is outside the
|
|
|
|
* range that can be stored in a 'size_t'
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueSizeT(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
size_t *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value size_t %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type != VIR_CONF_ULLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected an unsigned integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-15 15:07:38 +00:00
|
|
|
#if ULLONG_MAX > SIZE_MAX
|
|
|
|
if (((unsigned long long)cval->l) > SIZE_MAX) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be in range 0:%zu"),
|
|
|
|
conf->filename, setting, SIZE_MAX);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-07-14 10:21:30 +00:00
|
|
|
*value = (size_t)cval->l;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueSSizeT:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value is outside the
|
|
|
|
* range that can be stored in an 'ssize_t'
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueSSizeT(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
ssize_t *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value ssize_t %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type == VIR_CONF_ULLONG) {
|
2016-07-14 10:21:30 +00:00
|
|
|
if (((unsigned long long)cval->l) > SSIZE_MAX) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be in range %zd:%zd"),
|
|
|
|
conf->filename, setting, (ssize_t)-SSIZE_MAX - 1, (ssize_t)SSIZE_MAX);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-07-15 15:36:32 +00:00
|
|
|
} else if (cval->type == VIR_CONF_LLONG) {
|
2016-07-14 10:29:17 +00:00
|
|
|
#if SSIZE_MAX < LLONG_MAX
|
2016-07-14 10:21:30 +00:00
|
|
|
if (cval->l < (-SSIZE_MAX - 1) || cval->l > SSIZE_MAX) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: value for '%s' parameter must be in range %zd:%zd"),
|
|
|
|
conf->filename, setting, (ssize_t)-SSIZE_MAX - 1, (ssize_t)SSIZE_MAX);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-07-14 10:29:17 +00:00
|
|
|
#endif
|
2016-07-14 10:21:30 +00:00
|
|
|
} else {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected a signed integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-14 10:21:30 +00:00
|
|
|
*value = (ssize_t)cval->l;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConfGetValueLLong:
|
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type, or if the value is outside the
|
|
|
|
* range that can be stored in an 'long long'
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueLLong(virConf *conf,
|
2016-07-15 15:26:58 +00:00
|
|
|
const char *setting,
|
|
|
|
long long *value)
|
2016-07-07 15:52:47 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value long long %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type == VIR_CONF_ULLONG) {
|
2016-07-14 10:21:30 +00:00
|
|
|
if (((unsigned long long)cval->l) > LLONG_MAX) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2016-07-15 15:47:01 +00:00
|
|
|
_("%s: value for '%s' parameter must be in range %lld:%lld"),
|
|
|
|
conf->filename, setting, LLONG_MIN, LLONG_MAX);
|
2016-07-14 10:21:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2016-07-15 15:36:32 +00:00
|
|
|
} else if (cval->type != VIR_CONF_LLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected a signed integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = cval->l;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2016-07-15 15:11:18 +00:00
|
|
|
* virConfGetValueULLong:
|
2016-07-07 15:52:47 +00:00
|
|
|
* @conf: the config object
|
|
|
|
* @setting: the config entry name
|
|
|
|
* @value: pointer to hold integer value
|
|
|
|
*
|
|
|
|
* Get the integer value of the config name @setting, storing
|
|
|
|
* it in @value. If the config entry is not present, then
|
|
|
|
* @value will be unmodified.
|
|
|
|
*
|
|
|
|
* Reports an error if the config entry is set but has
|
|
|
|
* an unexpected type.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the value was present, 0 if missing, -1 on error
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfGetValueULLong(virConf *conf,
|
2016-07-07 15:52:47 +00:00
|
|
|
const char *setting,
|
|
|
|
unsigned long long *value)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfValue *cval = virConfGetValue(conf, setting);
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
VIR_DEBUG("Get value unsigned long long %p %d",
|
|
|
|
cval, cval ? cval->type : VIR_CONF_NONE);
|
|
|
|
|
|
|
|
if (!cval)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-15 15:36:32 +00:00
|
|
|
if (cval->type != VIR_CONF_ULLONG) {
|
2016-07-07 15:52:47 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s: expected an unsigned integer for '%s' parameter"),
|
|
|
|
conf->filename, setting);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-07-14 10:21:30 +00:00
|
|
|
*value = (unsigned long long)cval->l;
|
2016-07-07 15:52:47 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-11-15 19:46:23 +00:00
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfSetValue:
|
2006-11-15 19:46:23 +00:00
|
|
|
* @conf: a configuration file handle
|
2015-08-18 12:38:07 +00:00
|
|
|
* @setting: the name of the entry
|
2006-11-15 19:46:23 +00:00
|
|
|
* @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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfSetValue(virConf *conf,
|
2012-10-17 09:23:12 +00:00
|
|
|
const char *setting,
|
2022-01-14 09:11:42 +00:00
|
|
|
virConfValue **value)
|
2007-03-09 20:47:12 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *cur;
|
|
|
|
virConfEntry *prev = NULL;
|
2006-11-15 19:46:23 +00:00
|
|
|
|
2022-01-14 09:11:42 +00:00
|
|
|
if (!value) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("invalid use of conf API"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*value && (*value)->type == VIR_CONF_STRING && !(*value)->str) {
|
2022-01-14 09:35:17 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("expecting a value for value of type %s"),
|
|
|
|
virConfTypeToString(VIR_CONF_STRING));
|
2022-01-14 09:11:42 +00:00
|
|
|
g_clear_pointer(value, virConfFreeValue);
|
2009-12-14 20:37:54 +00:00
|
|
|
return -1;
|
2015-01-09 13:42:13 +00:00
|
|
|
}
|
2009-12-14 20:37:54 +00:00
|
|
|
|
2006-11-15 19:46:23 +00:00
|
|
|
cur = conf->entries;
|
|
|
|
while (cur != NULL) {
|
2014-12-09 13:48:54 +00:00
|
|
|
if (STREQ_NULLABLE(cur->name, setting))
|
2006-11-15 19:46:23 +00:00
|
|
|
break;
|
|
|
|
prev = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
2007-01-19 20:10:04 +00:00
|
|
|
|
2006-11-15 19:46:23 +00:00
|
|
|
if (!cur) {
|
2020-10-05 17:09:27 +00:00
|
|
|
cur = g_new0(virConfEntry, 1);
|
2006-11-15 19:46:23 +00:00
|
|
|
cur->comment = NULL;
|
2019-10-20 11:49:46 +00:00
|
|
|
cur->name = g_strdup(setting);
|
2022-01-14 09:11:42 +00:00
|
|
|
cur->value = g_steal_pointer(value);
|
2006-11-15 19:46:23 +00:00
|
|
|
if (prev) {
|
2007-01-19 20:10:04 +00:00
|
|
|
cur->next = prev->next;
|
2006-11-15 19:46:23 +00:00
|
|
|
prev->next = cur;
|
|
|
|
} else {
|
2007-01-19 20:10:04 +00:00
|
|
|
cur->next = conf->entries;
|
2006-11-15 19:46:23 +00:00
|
|
|
conf->entries = cur;
|
|
|
|
}
|
|
|
|
} else {
|
2010-05-17 20:38:59 +00:00
|
|
|
virConfFreeValue(cur->value);
|
2022-01-14 09:11:42 +00:00
|
|
|
cur->value = g_steal_pointer(value);
|
2006-11-15 19:46:23 +00:00
|
|
|
}
|
2012-03-22 11:33:35 +00:00
|
|
|
return 0;
|
2006-11-15 19:46:23 +00:00
|
|
|
}
|
|
|
|
|
2014-02-05 14:09:59 +00:00
|
|
|
/**
|
|
|
|
* virConfWalk:
|
|
|
|
* @conf: a configuration file handle
|
|
|
|
* @callback: the function to call to process each entry
|
2015-08-19 02:36:28 +00:00
|
|
|
* @opaque: obscure data passed to callback
|
2014-02-05 14:09:59 +00:00
|
|
|
*
|
|
|
|
* Walk over all entries of the configuration file and run the callback
|
|
|
|
* for each with entry name, value and the obscure data.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, or -1 on failure.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
int virConfWalk(virConf *conf,
|
2015-08-17 12:42:03 +00:00
|
|
|
virConfWalkCallback callback,
|
|
|
|
void *opaque)
|
2014-02-05 14:09:59 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *cur;
|
2014-02-05 14:09:59 +00:00
|
|
|
|
|
|
|
if (!conf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cur = conf->entries;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->name && cur->value &&
|
2018-09-19 08:38:14 +00:00
|
|
|
callback(cur->name, cur->value, opaque) < 0)
|
2014-02-05 14:09:59 +00:00
|
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2006-11-15 19:46:23 +00:00
|
|
|
|
2006-08-29 22:27:07 +00:00
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfWriteFile:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfWriteFile(const char *filename, virConf *conf)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2020-07-03 02:30:20 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *cur;
|
2006-08-29 22:27:07 +00:00
|
|
|
int ret;
|
|
|
|
int fd;
|
2008-04-28 15:14:59 +00:00
|
|
|
char *content;
|
|
|
|
unsigned int use;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
if (conf == NULL)
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
cur = conf->entries;
|
|
|
|
while (cur != NULL) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virConfSaveEntry(&buf, cur);
|
2008-04-10 16:54:54 +00:00
|
|
|
cur = cur->next;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
2006-08-29 22:27:07 +00:00
|
|
|
if (fd < 0) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
|
2008-04-28 15:14:59 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
use = virBufferUse(&buf);
|
|
|
|
content = virBufferContentAndReset(&buf);
|
|
|
|
ret = safewrite(fd, content, use);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(content);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2008-04-28 15:14:59 +00:00
|
|
|
if (ret != (int)use) {
|
2008-09-17 14:11:21 +00:00
|
|
|
virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
|
2008-04-28 15:14:59 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
|
|
|
|
return ret;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-11-17 11:03:25 +00:00
|
|
|
* virConfWriteMem:
|
2006-08-29 22:27:07 +00:00
|
|
|
* @memory: pointer to the memory to store the config file
|
2007-10-19 08:29:13 +00:00
|
|
|
* @len: pointer to the length in bytes of the store, on output the size
|
2006-08-29 22:27:07 +00:00
|
|
|
* @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
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfWriteMem(char *memory, int *len, virConf *conf)
|
2006-08-29 22:27:07 +00:00
|
|
|
{
|
2020-07-03 02:30:20 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfEntry *cur;
|
2008-04-28 15:14:59 +00:00
|
|
|
char *content;
|
|
|
|
unsigned int use;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
|
2012-03-22 11:33:35 +00:00
|
|
|
return -1;
|
2006-08-29 22:27:07 +00:00
|
|
|
|
|
|
|
cur = conf->entries;
|
|
|
|
while (cur != NULL) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virConfSaveEntry(&buf, cur);
|
2007-01-19 20:10:04 +00:00
|
|
|
cur = cur->next;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2008-02-05 19:27:37 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
use = virBufferUse(&buf);
|
|
|
|
content = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
if ((int)use >= *len) {
|
|
|
|
*len = (int)use;
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(content);
|
2008-04-28 15:14:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(memory, content, use);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(content);
|
2008-04-28 15:14:59 +00:00
|
|
|
*len = use;
|
|
|
|
return use;
|
2006-08-29 22:27:07 +00:00
|
|
|
}
|
2015-10-12 14:09:53 +00:00
|
|
|
|
|
|
|
static char *
|
|
|
|
virConfLoadConfigPath(const char *name)
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
if (geteuid() == 0) {
|
2019-10-22 13:26:14 +00:00
|
|
|
path = g_strdup_printf("%s/libvirt/%s", SYSCONFDIR, name);
|
2015-10-12 14:09:53 +00:00
|
|
|
} else {
|
2019-12-19 17:30:33 +00:00
|
|
|
g_autofree char *userdir = virGetUserConfigDirectory();
|
2015-10-12 14:09:53 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
path = g_strdup_printf("%s/%s", userdir, name);
|
2015-10-12 14:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virConfLoadConfig(virConf **conf, const char *name)
|
2015-10-12 14:09:53 +00:00
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*conf = NULL;
|
|
|
|
|
|
|
|
if (!(path = virConfLoadConfigPath(name)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!virFileExists(path)) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("Loading config file '%s'", path);
|
|
|
|
if (!(*conf = virConfReadFile(path, 0)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(path);
|
|
|
|
return ret;
|
|
|
|
}
|