commit b9e2967a5ecbad6fd5d62e6e7a951cb4b50426a6
Author: Daniel P. Berrange <berrange@redhat.com>
Date:   Tue Feb 2 17:49:09 2010 +0000

    Add new clock mode allowing variable adjustments
    
    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

Index: libvirt-0.7.6/docs/schemas/domain.rng
===================================================================
--- libvirt-0.7.6.orig/docs/schemas/domain.rng
+++ libvirt-0.7.6/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>
@@ -1549,4 +1561,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>
Index: libvirt-0.7.6/src/conf/domain_conf.c
===================================================================
--- libvirt-0.7.6.orig/src/conf/domain_conf.c
+++ libvirt-0.7.6/src/conf/domain_conf.c
@@ -233,7 +233,8 @@ VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOM
 
 VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
               "utc",
-              "localtime");
+              "localtime",
+              "variable");
 
 #define virDomainReportError(conn, code, fmt...)                           \
         virReportErrorHelper(conn, VIR_FROM_DOMAIN, code, __FILE__,        \
@@ -3506,6 +3507,13 @@ static virDomainDefPtr virDomainDefParse
     } else {
         def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
     }
+    switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+        if (virXPathLongLong(conn, "number(./clock/@adjustment)", ctxt,
+                             &def->clock.adjustment) < 0)
+            def->clock.adjustment = 0;
+        break;
+    }
 
     def->os.bootloader = virXPathString(conn, "string(./bootloader)", ctxt);
     def->os.bootloaderArgs = virXPathString(conn, "string(./bootloader_args)", ctxt);
@@ -5548,8 +5556,14 @@ char *virDomainDefFormat(virConnectPtr c
     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));
+    switch (def->clock.offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
+        virBufferVSprintf(&buf, " adjustment='%lld'", def->clock.adjustment);
+        break;
+    }
+    virBufferAddLit(&buf, "/>\n");
 
     if (virDomainLifecycleDefFormat(conn, &buf, def->onPoweroff,
                                     "on_poweroff",
Index: libvirt-0.7.6/src/conf/domain_conf.h
===================================================================
--- libvirt-0.7.6.orig/src/conf/domain_conf.h
+++ libvirt-0.7.6/src/conf/domain_conf.h
@@ -608,6 +608,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,
 };
@@ -616,6 +617,10 @@ typedef struct _virDomainClockDef virDom
 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
Index: libvirt-0.7.6/src/libvirt_private.syms
===================================================================
--- libvirt-0.7.6.orig/src/libvirt_private.syms
+++ libvirt-0.7.6/src/libvirt_private.syms
@@ -638,6 +638,7 @@ virXPathStringLimit;
 virXPathBoolean;
 virXPathNumber;
 virXPathULong;
+virXPathLongLong;
 virXPathULongLong;
 virXPathLongHex;
 virXPathULongHex;
Index: libvirt-0.7.6/src/util/xml.c
===================================================================
--- libvirt-0.7.6.orig/src/util/xml.c
+++ libvirt-0.7.6/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)
Index: libvirt-0.7.6/src/util/xml.h
===================================================================
--- libvirt-0.7.6.orig/src/util/xml.h
+++ libvirt-0.7.6/src/util/xml.h
@@ -37,6 +37,10 @@ int	        virXPathULongLong(virConnect
                                  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,
