Skip to content

Manage a VM you started yourself

launch_vm builds its own QEMU command line, which is convenient until you need something it does not offer: a device model it never adds, a bridged network, a specific machine type, or a VM that libvirt or a script already starts for you.

attach_vm covers that case. You start QEMU however you like, and mcqemu manages it through its QMP control socket. It never rewrites your command line and never launches the process; it only connects to what is already there.

The one hard requirement is a QMP unix socket, added with -qmp unix:/path,server=on,wait=off. The server=on part makes QEMU create and listen on the socket, and wait=off stops it from blocking at startup until a client connects.

Two optional additions are worth including, because retrofitting them means restarting the guest:

  • A virtio-serial channel named org.qemu.guest_agent.0 for the guest_* tools.
  • virtio-tablet-pci for absolute pointer positioning, which is what vm_click needs.

A complete example:

Terminal window
qemu-system-x86_64 \
-name legacy \
-machine q35,accel=kvm -cpu host -m 4096 -smp 4 \
-drive file=$HOME/vms/legacy.qcow2,if=virtio,format=qcow2 \
-display none \
-qmp unix:$XDG_RUNTIME_DIR/legacy-qmp.sock,server=on,wait=off \
-chardev socket,id=qga0,path=$XDG_RUNTIME_DIR/legacy-qga.sock,server=on,wait=off \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
-device virtio-tablet-pci \
-daemonize -pidfile $XDG_RUNTIME_DIR/legacy.pid

If the VM is already running without a QMP socket, there is no way to add one without restarting it. QMP is the only channel these tools have.

  1. Register the process:

    attach_vm(name="legacy",
    qmp_socket="/run/user/1000/legacy-qmp.sock",
    qga_socket="/run/user/1000/legacy-qga.sock",
    pid=48213)

    Only name and qmp_socket are required. qga_socket enables the guest_* tools; pid lets liveness checks tell “stopped” apart from “unreachable” without probing the socket.

  2. The call verifies the socket exists, is really a unix socket, and answers a QMP status query before registering anything, then returns the guest’s current status. A failure here means QEMU is not listening where you said.

  3. Confirm it shows up alongside everything else:

    list_vms()

    The entry has source: "attached", which is how the other tools know it was not spawned here.

Names must be unique across the registry. If the name is taken, either pick another or forget_vm the old entry first.

Once attached, almost everything behaves as it does for a launched VM:

  • vm_info, list_vms, pause_vm, resume_vm all work over QMP.
  • vm_screenshot, vm_send_keys and vm_type_text work if the VM has a display device.
  • vm_click needs the tablet device; without it, use vm_mouse_move (see Drive an installer).
  • guest_* tools work if you passed qga_socket and the guest is running qemu-guest-agent.
  • vm_snapshot_* works if the VM’s writable disks are qcow2.
  • stop_vm sends an ACPI power button press over QMP, and with force=true tells QEMU to quit outright.

The exception is vm_serial_read. mcqemu reads the serial log file it set up at launch, and an attached VM’s serial output goes wherever your own command line sent it. The tool reports that rather than guessing. Read your own log file directly, or use vm_screenshot.

sandbox_destroy also refuses attached VMs, along with any VM that sandbox_vm did not create. It deletes disks, and it will only delete overlays it made itself.

forget_vm removes the registry entry. That is all it does.

forget_vm(name="legacy")

It does not stop the VM, does not touch the QEMU process, and never deletes a disk. Afterwards the VM keeps running exactly as before, and mcqemu simply has no record of it. The result reports process_left_running so you know whether you have just stopped tracking a live process.

Use it to hand a VM back to whatever else owns it, to clear a stale entry for a VM that died elsewhere, or to free up a name.

For a VM that this server launched, forget_vm refuses while the process is still alive unless you pass force=true. Forgetting a running spawned VM orphans it: the process stays up holding its disks and ports, and no tool can find it any more. The refusal exists so that only happens on purpose. If you do orphan one, find it with pgrep -af qemu-system and either kill it or attach it again by its socket path.

Re-attaching later is just attach_vm with the same socket paths. Nothing about the running VM changed while it was unregistered.