commit 200c83b29ddceaa4be045cafaff306620004c42b
Author: Daniel P. Berrange <berrange@redhat.com>
Date:   Tue Feb 2 18:07:12 2010 +0000

    Support variable clock offset mode in QEMU
    
    This allows QEMU guests to be started with an arbitrary clock
    offset
    
    The test case can't actually be enabled, since QEMU argv expects
    an absolute timestring, and this will obviously change every
    time the test runs :-( Hopefully QEMU will allow a relative
    time offset in the future.
    
    * src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Use the -rtc arg
      if available to support variable clock offset mode
    * tests/qemuhelptest.c: Add QEMUD_CMD_FLAG_RTC for qemu 0.12.1
    * qemuxml2argvdata/qemuxml2argv-clock-variable.args,
      qemuxml2argvdata/qemuxml2argv-clock-variable.xml,
      qemuxml2argvtest.c: Test case, except we can't actually enable
      it yet.

Index: libvirt-0.7.6/src/qemu/qemu_conf.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_conf.c
+++ libvirt-0.7.6/src/qemu/qemu_conf.c
@@ -1159,6 +1159,9 @@ static unsigned int qemudComputeCmdFlags
         flags |= QEMUD_CMD_FLAG_BALLOON;
     if (strstr(help, "-device"))
         flags |= QEMUD_CMD_FLAG_DEVICE;
+    /* The trailing ' ' is important to avoid a bogus match */
+    if (strstr(help, "-rtc "))
+        flags |= QEMUD_CMD_FLAG_RTC;
     /* Keep disabled till we're actually ready to turn on netdev mode
      * The plan is todo it in 0.13.0 QEMU, but lets wait & see... */
 #if 0
@@ -2950,6 +2953,56 @@ error:
 }
 
 
+static char *
+qemuBuildClockArgStr(virDomainClockDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    switch (def->offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        virBufferAddLit(&buf, "base=utc");
+        break;
+
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+        virBufferAddLit(&buf, "base=localtime");
+        break;
+
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
+        time_t now = time(NULL);
+        struct tm nowbits;
+
+        now += def->data.adjustment;
+        gmtime_r(&now, &nowbits);
+
+        virBufferVSprintf(&buf, "base=%d-%d-%dT%d:%d:%d",
+                          nowbits.tm_year + 1900,
+                          nowbits.tm_mon,
+                          nowbits.tm_mday,
+                          nowbits.tm_hour,
+                          nowbits.tm_min,
+                          nowbits.tm_sec);
+    }   break;
+
+    default:
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("unsupported clock offset '%s'"),
+                        virDomainClockOffsetTypeToString(def->offset));
+        goto error;
+    }
+
+    if (virBufferError(&buf)) {
+        virReportOOMError(NULL);
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
 static int
 qemuBuildCpuArgStr(virConnectPtr conn,
                    const struct qemud_driver *driver,
@@ -3380,13 +3433,28 @@ int qemudBuildCommandLine(virConnectPtr
         }
     }
 
-    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
-        ADD_ARG_LIT("-localtime");
-    else if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
-                        _("unsupported clock offset '%s'"),
-                        virDomainClockOffsetTypeToString(def->clock.offset));
-        goto error;
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC) {
+        const char *rtcopt;
+        ADD_ARG_LIT("-rtc");
+        if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
+            goto error;
+        ADD_ARG(rtcopt);
+    } else {
+        switch (def->clock.offset) {
+        case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+            ADD_ARG_LIT("-localtime");
+            break;
+
+        case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+            /* Nothing, its the default */
+            break;
+
+        default:
+            qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("unsupported clock offset '%s'"),
+                            virDomainClockOffsetTypeToString(def->clock.offset));
+            goto error;
+        }
     }
 
     if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
Index: libvirt-0.7.6/src/qemu/qemu_conf.h
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_conf.h
+++ libvirt-0.7.6/src/qemu/qemu_conf.h
@@ -83,6 +83,7 @@ enum qemud_cmd_flags {
     QEMUD_CMD_FLAG_SDL           = (1 << 27), /* Is the new -sdl arg available */
     QEMUD_CMD_FLAG_SMP_TOPOLOGY  = (1 << 28), /* Is sockets=s,cores=c,threads=t available for -smp? */
     QEMUD_CMD_FLAG_NETDEV        = (1 << 29), /* The -netdev flag & netdev_add/remove monitor commands */
+    QEMUD_CMD_FLAG_RTC           = (1 << 30), /* The -rtc flag for clock options */
 };
 
 /* Main driver state */
Index: libvirt-0.7.6/tests/qemuhelptest.c
===================================================================
--- libvirt-0.7.6.orig/tests/qemuhelptest.c
+++ libvirt-0.7.6/tests/qemuhelptest.c
@@ -224,7 +224,8 @@ mymain(int argc, char **argv)
             QEMUD_CMD_FLAG_CHARDEV |
             QEMUD_CMD_FLAG_BALLOON |
             QEMUD_CMD_FLAG_DEVICE |
-            QEMUD_CMD_FLAG_SMP_TOPOLOGY,
+            QEMUD_CMD_FLAG_SMP_TOPOLOGY |
+            QEMUD_CMD_FLAG_RTC,
             12001, 0,  0);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
Index: libvirt-0.7.6/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.args
===================================================================
--- /dev/null
+++ libvirt-0.7.6/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.args
@@ -0,0 +1 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -rtc base=2010-2-2T18:22:10 -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
Index: libvirt-0.7.6/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
===================================================================
--- /dev/null
+++ libvirt-0.7.6/tests/qemuxml2argvdata/qemuxml2argv-clock-variable.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='variable' adjustment='123456'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+  </devices>
+</domain>
Index: libvirt-0.7.6/tests/qemuxml2argvtest.c
===================================================================
--- libvirt-0.7.6.orig/tests/qemuxml2argvtest.c
+++ libvirt-0.7.6/tests/qemuxml2argvtest.c
@@ -218,6 +218,10 @@ mymain(int argc, char **argv)
     DO_TEST("bootloader", QEMUD_CMD_FLAG_DOMID);
     DO_TEST("clock-utc", 0);
     DO_TEST("clock-localtime", 0);
+    /*
+     * Can't be enabled since the absolute timestamp changes every time
+    DO_TEST("clock-variable", QEMUD_CMD_FLAG_RTC);
+    */
     DO_TEST("hugepages", QEMUD_CMD_FLAG_MEM_PATH);
     DO_TEST("disk-cdrom", 0);
     DO_TEST("disk-cdrom-empty", QEMUD_CMD_FLAG_DRIVE);
