keycodes argument to virDomainSendKey() is architecture specific
Hi,
There seems to be an issue related to (d *Domain) SendKey
. I'm trying to send a keycode combination to a VM, but the combination is not sent as expected. For my program to work, all three keys need to be pressed simultaneously.
Basic info:
- Using libvirt-go v7.3.0+incompatible
- with Go 1.14.15
- on Linux 5.11 x86_64
Here is my call that does not work:
var keys = []uint{KEY_LEFTCTRL, KEY_LEFTALT, KEY_F1}
dom.SendKey(uint(rawLibvirt.KEYCODE_SET_LINUX), 100, keys, 0)
In contrast, a manual call with virsh does work:
virsh send-key vm KEY_LEFTCTRL KEY_LEFTALT KEY_F1
I checked how the elements of keys
are layed out in memory:
log.Printf("%p\n", unsafe.Pointer(&keys[0]))
log.Printf("%p\n", unsafe.Pointer(&keys[1]))
This gives me 0xb8efa0
and 0xb8efa8
, meaning one uint
is 8 bytes, fair so far.
Now, the Go bindings pass keys
to the C library as follows:
func (d *Domain) SendKey(codeset, holdtime uint, keycodes []uint, flags uint32) error {
...
result := C.virDomainSendKeyWrapper(d.ptr, C.uint(codeset), C.uint(holdtime), (*C.uint)(unsafe.Pointer(&keycodes[0])), C.int(len(keycodes)), C.uint(flags), &err)
...
}
In short, it (correctly) passes the pointer 0xb8efa0
and a length of 3, with the intention to include all three elements at the addresses 0xb8efa0
, 0xb8efa8
, and 0xb8efb0
.
However, the C library expects an unsigned int *
as pointer. On my system, an unsigned int
is 4 bytes, not 8. I used this little C program to confirm that:
#include <stdio.h>
int main() {
unsigned int foo = 0;
printf("%d\n", sizeof(foo));
}
Let's compile and run it:
gcc main.c && ./a.out
This outputs 4
. This means the C library will read the three keycodes from 0xb8efa0
, 0xb8efa4
, and 0xb8efa8
.
Simply extending my keys
to include trailing dummy elements "fixes" the issue.
var keys = []uint{KEY_LEFTCTRL, KEY_LEFTALT, KEY_F1, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED}
dom.SendKey(uint(rawLibvirt.KEYCODE_SET_LINUX), 100, keys, 0)
This way, the Go bindings will pass the C library a length of 6, meaning it will read 0xb8efa0
, 0xb8efa4
, 0xb8efa8
, 0xb8efac
, 0xb8efb0
, 0xb8efb4
. This includes all addresses the Go bindings intended to pass: 0xb8efa0
, 0xb8efa8
, 0xb8efb0
.