Bringing this question straight from here.

I am running archlinux and I have a VM running often on it along with the system. Most of the time actually.

My goal is to produce the following behaviour:

  • A shutdown / poweroff / reboot / halt signal is sent to the system
  • No action other then trying to shut down the virtual machines gracefully
  • If the VMs are shut down gracefully after X seconds, proceeds with shutting down the host system too.
  • If not, execute a different command

Just give me a good idea on what to work on, because I don't even know from where to begin. I guess there is a call to the kernel that can be looked at.

Let me know.

My current code

At the moment I am using these scripts to gracefully shutdown my kvm virtual machines, and it works! But only as long as my user launches a shutdown or a reboot using his shell. Any other case wouldn't work.

These alias:

alias sudocheck="/bin/bash /home/damiano/.script/sudocheck"
alias sudo="sudocheck "

Are triggering this function:


# This script checks for what is being passed to sudo.
# If the command passed is poweroff or reboot, it
# launches a custom script instead, that also looks
# fur currently running virtual machines and shuts them.

sudocheck() {
    if [ $1 == "poweroff" ] || [ $1 == "reboot" ]; then
        eval "sudo /home/damiano/.script/graceful $@"
        eval "sudo $@"
sudocheck $@

That launches this script if needed:

## if virsh finds VMs running
virsh -c qemu:///system list | awk '{ print $3}' | \
if grep running > /dev/null ; then
    virsh -c qemu:///system list --all | grep running | awk '{print "-c qemu:///system shutdown "$2}' | \
## shuts them dow gracefully
    xargs -L1 virsh
## wait 30 seconds for them to go down
    until (( i >= 30 || e == 1 )) ; do
## check every second for their status
        virsh -c qemu:///system list --all | awk '{ print $3}' | \
        if grep -E '(running|shutdown)' > /dev/null ; then
## keep waiting if still running
            if (( i <= 30 )) ; then
                sleep 1 && let i++ && echo $i
                e=1 && notify-send 'Shutdown has been canceled' 'Please check the status of your virtual machines: seems like even though a stop signal has been sent, some are still running.' --urgency=critical
## if no machine is running anymore, original power command can be executed
            e=1 && eval $@

Systemd Unit

I also made the following draft, to manage the execution of my VM:

[email protected]

Description=This service manages the execution of the %i virtual machine

ExecStartPre=virsh -c qemu:///system
ExecStart=virsh start %i
ExecStop=virsh -c qemu:///system
ExecStop=virsh shutdown %i 


But how can I tell the system to don't shut down the desktop environment, to stay as it is UNTIL the VM has been successfully shut down? Because if the system can't shut down the vm, I want to do it while still in my DE. I don't want the computer to begin stopping all the services and remain hung until it just forces the shut down.

  • Does running virsh shutdown domainname from the host do what you need? Commented Mar 14, 2020 at 2:29
  • No, it just shuts down my virtual machine. I want to script a graceful shutdown for the entire system. So that all the vm's get shut down along with the host. Commented Mar 14, 2020 at 4:10
  • May be using the full path of virsh is more secure. Commented Oct 22, 2020 at 9:47
  • Maybe define a custom script that starts and stops your virtual machines that has graphical.target as a dependency? That is, tell systemd that your script must be stopped before graphical.target can be stopped and then put commands to gracefully stop your virtual machines in your custom script ExecStop. Commented Dec 14, 2023 at 10:03

2 Answers 2


Strange way for controlling VM. Good way -- use systemd for automatic start and stop VM. For example:

/etc/systemd/system/[email protected]

Description=QEMU virtual machine

Environment="type=system-x86_64" "haltcmd=kill -INT $MAINPID"
ExecStart=/usr/bin/qemu-${type} -name %i -nographic $args
ExecStop=/bin/sh -c ${haltcmd}


... And, of course config(s) for run VM's:



args="-enable-kvm -m 512 -hda /dev/vg0/vm1 -net nic,macaddr=DE:AD:BE:EF:E0:00 \
 -net tap,ifname=tap0 -serial telnet:localhost:7000,server,nowait,nodelay \
 -monitor telnet:localhost:7100,server,nowait,nodelay -vnc :0"

haltcmd="echo 'system_powerdown' | nc localhost 7100" # or netcat/ncat

# You can use other ways to shut down your VM correctly
#haltcmd="ssh powermanager@vm1 sudo poweroff"

...and another VM config:


args="-enable-kvm -m 512 -hda /srv/kvm/vm2.img -net nic,macaddr=DE:AD:BE:EF:E0:01 \
 -net tap,ifname=tap1 -serial telnet:localhost:7001,server,nowait,nodelay \
 -monitor telnet:localhost:7101,server,nowait,nodelay -vnc :1"

haltcmd="echo 'system_powerdown' | nc localhost 7101"

Et cetera. Thanks ArchWiki contributors for this article.

  • This is useful only to get the machine shut down, if they can be shut down in - say - 30 seconds. But the systemd unit you posted will try to shut down the machine while the rest of the system is being shut down, and, after 30 seconds it will shut it down forcefully which is not what I want. I want that when a shutdown signal gets launched everything stays as it is, the VMs are shut down and: if successful then the system proceeds to shut down the rest of the system as usual, else -> another command. Commented Mar 15, 2020 at 3:25
  • The virtual machine ? do you use something cfengine, puppet or chef to manage it ? Could you have something in policy which if something is true for the host propagates a shutdown action to the virtual machines ? In the case of cfengine : the hub can initiate a policy check with special variables set -> special variable set ? create a marker file and at end of policy shutdown the VM. Commented Mar 15, 2020 at 13:44
  • Hello Stefan, thanks for your comment. No I just use virt-manager and virsh Commented Mar 16, 2020 at 12:28

The draft by the original post and @Oxyd's answer are useful when you need to control each Virtual Machines individually.

However if it's desired to shutdown/start all the VMs one could use the libvirt guests as mentioned on Libvirt docs.

  • Edit the file /etc/conf.d/libvirt-guests, or /etc/sysconfig/libvirt-guests for CentOS, then set ON_SHUTDOWN=shutdown and SHUTDOWN_TIMEOUT=0
  • I think one also needs to activate the libvirt-guests service, for example systemctl enable libvirt-guests and systemctl start libvirt-guests

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .