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@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to