This introduces a third option for clock offset synchronization,
that allows an arbitrary / variable adjustment to be set. In
essence the XML contains the time delta in seconds, relative to
UTC.
<clock offset='variable' adjustment='123465'/>
The difference from 'utc' mode, is that management apps should
track adjustments and preserve them at next reboot.
* docs/schemas/domain.rng: Schema for new clock mode
* src/conf/domain_conf.c, src/conf/domain_conf.h: Parse
new clock time delta
* src/libvirt_private.syms, src/util/xml.c, src/util/xml.h: Add
virXPathLongLong() method
---
docs/schemas/domain.rng | 25 +++++++++++++++++---
src/conf/domain_conf.c | 18 +++++++++++++-
src/conf/domain_conf.h | 5 ++++
src/libvirt_private.syms | 1 +
src/util/xml.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/xml.h | 5 +++-
6 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 1ff0944..d295bfe 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -297,12 +297,24 @@
<define name="clock">
<optional>
<element name="clock">
- <attribute name="offset">
- <choice>
+ <choice>
+ <attribute name="offset">
<value>localtime</value>
+ </attribute>
+ <attribute name="offset">
<value>utc</value>
- </choice>
- </attribute>
+ </attribute>
+ <group>
+ <attribute name="offset">
+ <value>variable</value>
+ </attribute>
+ <optional>
+ <attribute name="adjustment">
+ <ref name="timeDelta"/>
+ </attribute>
+ </optional>
+ </group>
+ </choice>
<empty/>
</element>
</optional>
@@ -1567,4 +1579,9 @@
<param name='pattern'>[a-zA-Z0-9\-_]+</param>
</data>
</define>
+ <define name="timeDelta">
+ <data type="string">
+ <param name="pattern">(-|\+)?[0-9]+</param>
+ </data>
+ </define>
</grammar>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f86b4eb..49d5d19 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -231,7 +231,8 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap,
VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
- "localtime");
+ "localtime",
+ "variable");
#define virDomainReportError(code, fmt...) \
virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__, \
@@ -3492,6 +3493,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
} else {
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
}
+ switch (def->clock.offset) {
+ case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+ if (virXPathLongLong("./clock/@adjustment", ctxt,
+ &def->clock.adjustment) < 0)
+ def->clock.adjustment = 0;
+ break;
+ }
def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
def->os.bootloaderArgs = virXPathString("string(./bootloader_args)",
ctxt);
@@ -5399,8 +5407,14 @@ char *virDomainDefFormat(virDomainDefPtr def,
if (virCPUDefFormatBuf(&buf, def->cpu, " ", 0) < 0)
goto cleanup;
- virBufferVSprintf(&buf, " <clock offset='%s'/>\n",
+ virBufferVSprintf(&buf, " <clock offset='%s'",
virDomainClockOffsetTypeToString(def->clock.offset));
+ switch (def->clock.offset) {
+ case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+ virBufferVSprintf(&buf, " adjustment='%lld'",
def->clock.adjustment);
+ break;
+ }
+ virBufferAddLit(&buf, "/>\n");
if (virDomainLifecycleDefFormat(&buf, def->onPoweroff,
"on_poweroff") < 0)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index fbbe683..f5fe016 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -612,6 +612,7 @@ struct _virSecurityLabelDef {
enum virDomainClockOffsetType {
VIR_DOMAIN_CLOCK_OFFSET_UTC = 0,
VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME = 1,
+ VIR_DOMAIN_CLOCK_OFFSET_VARIABLE = 2,
VIR_DOMAIN_CLOCK_OFFSET_LAST,
};
@@ -620,6 +621,10 @@ typedef struct _virDomainClockDef virDomainClockDef;
typedef virDomainClockDef *virDomainClockDefPtr;
struct _virDomainClockDef {
int offset;
+
+ /* Adjustment in seconds, relative to UTC, when
+ * offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE */
+ long long adjustment;
};
#define VIR_DOMAIN_CPUMASK_LEN 1024
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1af34bd..41bde8e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -629,6 +629,7 @@ virXPathStringLimit;
virXPathBoolean;
virXPathNumber;
virXPathULong;
+virXPathLongLong;
virXPathULongLong;
virXPathLongHex;
virXPathULongHex;
diff --git a/src/util/xml.c b/src/util/xml.c
index 46ea9aa..14c8345 100644
--- a/src/util/xml.c
+++ b/src/util/xml.c
@@ -364,6 +364,60 @@ virXPathULongLong(const char *xpath,
return (ret);
}
+/**
+ * virXPathULongLong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathLongLong(const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long long *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to
virXPathLongLong()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ ctxt->node = relnode;
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ unsigned long long val;
+
+ val = strtoll((const char *) obj->stringval, &conv, 10);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ *value = (long long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ return (ret);
+}
+
char *
virXMLPropString(xmlNodePtr node,
const char *name)
diff --git a/src/util/xml.h b/src/util/xml.h
index 246672d..af721bb 100644
--- a/src/util/xml.h
+++ b/src/util/xml.h
@@ -30,7 +30,10 @@ int virXPathULong(const char *xpath,
int virXPathULongLong(const char *xpath,
xmlXPathContextPtr ctxt,
unsigned long long *value);
-int virXPathLongHex(const char *xpath,
+int virXPathLongLong(const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long long *value);
+int virXPathLongHex (const char *xpath,
xmlXPathContextPtr ctxt,
long *value);
int virXPathULongHex(const char *xpath,
--
1.6.6