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 | 14 ++++++++++- src/conf/domain_conf.h | 5 ++++ src/libvirt_private.syms | 1 + src/util/xml.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/xml.h | 4 +++ 6 files changed, 98 insertions(+), 6 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index bb6d00d..5c48a8b 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> @@ -1526,4 +1538,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 1daf6f4..0c502b9 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -224,7 +224,8 @@ VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST, VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST, "utc", - "localtime"); + "localtime", + "variable"); #define virDomainReportError(conn, code, fmt...) \ @@ -3479,6 +3480,11 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, } else { def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; } + if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) { + if (virXPathLongLong(conn, "./clock/@adjustment", ctxt, + &def->clock.adjustment) < 0) + def->clock.adjustment = 0; + } def->os.bootloader = virXPathString(conn, "string(./bootloader)", ctxt); def->os.bootloaderArgs = virXPathString(conn, "string(./bootloader_args)", ctxt); @@ -5419,8 +5425,12 @@ char *virDomainDefFormat(virConnectPtr conn, if (virCPUDefFormatBuf(conn, &buf, def->cpu, " ", 0) < 0) goto cleanup; - virBufferVSprintf(&buf, " <clock offset='%s'/>\n", + virBufferVSprintf(&buf, " <clock offset='%s'", virDomainClockOffsetTypeToString(def->clock.offset)); + if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE) { + virBufferVSprintf(&buf, " adjustment='%lld'", def->clock.adjustment); + } + virBufferAddLit(&buf, "/>\n"); if (virDomainLifecycleDefFormat(conn, &buf, def->onPoweroff, "on_poweroff") < 0) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 5653b18..4df28e5 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -597,6 +597,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, }; @@ -605,6 +606,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 e882ae4..39b7c45 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -625,6 +625,7 @@ virXPathStringLimit; virXPathBoolean; virXPathNumber; virXPathULong; +virXPathLongLong; virXPathULongLong; virXPathLongHex; virXPathULongHex; diff --git a/src/util/xml.c b/src/util/xml.c index 4fa443d..52786d0 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -374,6 +374,61 @@ virXPathULongLong(virConnectPtr conn, 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(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + long long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virXMLError(conn, 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 cddd42b..80d6da1 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -37,6 +37,10 @@ int virXPathULongLong(virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long long *value); +int virXPathLongLong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + long long *value); int virXPathLongHex (virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, -- 1.6.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list