Skip to content

Instantly share code, notes, and snippets.

@ktprograms
Last active April 1, 2022 10:17
Show Gist options
  • Save ktprograms/f8bad8b7dcc882bc2cb3e000a45dcad8 to your computer and use it in GitHub Desktop.
Save ktprograms/f8bad8b7dcc882bc2cb3e000a45dcad8 to your computer and use it in GitHub Desktop.
Swift program that connects to the QEMU Guest Agent on a localhost TCP socket and runs guest-set-time to re-sync the Guest Time after the Host wakes from sleep.

How to use this

Steps before launching the VM

  1. Open the VM Configuration
  2. Go to the QEMU tab and scroll to the bottom.
  3. Click on the text box with the grey text New...
  4. Paste these two lines into it:
-chardev socket,port=4321,host=127.0.0.1,server,nowait,id=qga0
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
  1. Save the VM Configuration and Start the VM

Steps inside the VM

  1. Install the QEMU Guest Agent. On Debian/Ubuntu based systems run sudo apt install qemu-guest-agent. For other distros, you should be able to find a qemu-guest-agent package.
  2. Start the qemu-ga program. You can either start the qemu-guest-agent service if your distro has it included in the package, otherwise just run qemu-ga -d (which starts the QEMU Guest Agent in the background).

Steps on the Host Mac

  1. Download the UTMSetTimeOnWake.swift file from https://gist.github.com/ktprograms/f8bad8b7dcc882bc2cb3e000a45dcad8
  2. In the Terminal, go to the directory containing the downloaded file.
  3. Run swift UTMSetTimeOnWake.swift
  4. This will run continuously with no output, but when you wake your computer, it will automatically sync the guest time and print the message Successfully re-synced guest time.
import AppKit
import Foundation
let app = NSApplication.shared
func stderrWrite(_ string: String) {
FileHandle.standardError.write(Data(string.utf8))
}
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.didWakeNotification, object: nil, queue: nil) { _ in
let sock = socket(AF_INET, SOCK_STREAM, 0)
var readBuf = [CChar](repeating: 0, count: Int(BUFSIZ))
if sock < 0 {
perror("Error: socket")
app.terminate(self)
}
var sockName = sockaddr_in(sin_len: 0,
sin_family: sa_family_t(AF_INET),
sin_port: in_port_t(UInt16(4321).bigEndian),
sin_addr: in_addr(s_addr: inet_addr("127.0.0.1")),
sin_zero: (0,0,0,0,0,0,0,0))
let connectReturn = withUnsafePointer(to: &sockName) { pointer in
pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { pointer in
connect(sock, pointer, socklen_t(MemoryLayout<sockaddr_in>.size))
}
}
if connectReturn < 0 {
perror("Error: connect")
app.terminate(self)
}
let guestSyncStr = "{\"execute\":\"guest-sync\", \"arguments\":{\"id\":1234}}"
let guestSyncResponse = "{\"return\": 1234}\n"
if write(sock, guestSyncStr, guestSyncStr.count) < 0 {
perror("Error: write guest-sync")
app.terminate(self)
}
if read(sock, &readBuf, Int(BUFSIZ)) < 0 {
perror("Error: read guest-sync")
app.terminate(self)
}
readBuf.withUnsafeBufferPointer { pointer in
let readStr = String(cString: pointer.baseAddress!)
if readStr != guestSyncResponse {
stderrWrite("Bad guest-sync response. Response: \(readStr)\n")
app.terminate(self)
}
}
// Clear readBuf back to zero
readBuf = readBuf.map { _ in 0 }
let guestSetTimeStr = "{\"execute\":\"guest-set-time\"}"
let guestSetTimeResponse = "{\"return\": {}}\n"
if write(sock, guestSetTimeStr, guestSetTimeStr.count) < 0 {
perror("Error: write guest-set-time")
app.terminate(self)
}
if read(sock, &readBuf, Int(BUFSIZ)) < 0 {
perror("Error: read guest-set-time")
app.terminate(self)
}
readBuf.withUnsafeBufferPointer { pointer in
let readStr = String(cString: pointer.baseAddress!)
if readStr != guestSetTimeResponse {
stderrWrite("Bad guest-set-time response. Response: \(readStr)\n")
app.terminate(self)
}
}
if close(sock) < 0 {
perror("Error: close")
app.terminate(self)
}
print("Successfully re-synced guest time")
}
}
}
let delegate = AppDelegate()
app.delegate = delegate
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment