Virtualbox has the ability to issue a command to a running vm:

vboxmanage controlvm NameOfRunningVM acpipowerbutton

However this command returns immediately which results in non-graceful shutdown for my situation.

The situation: I plan on using this in an /etc/init.d script. This would allow for graceful shutdown of all the running VMs. Currently when I issue the vboxmanage controlvm NameOfRunningVM acpipowerbutton command the shutdown gets cutoff because the command doesn't wait for the VM to shutdown.

I need a Bash script that takes as input the name of the Virtualbox machine and a timeout in seconds then waits for the VM to return to "poweroff" state or the timeout occurs?

I'm not sure what is the best way to go about doing this.

I was thinking of checking the state of the VM with the following command:

[user@machine ~]$ vboxmanage list runningvms
"VirtualMachineName" {65c93f1f-4508-4119-b07d-ce9e89b23b8e}

The bash script would maybe be polling for a list of running VMs. Once the machine name stops being listed, the VM would be considered finished.

  • I'm not sure I understand. If the command returns immediately, what would the BASH script be waiting for? – terdon Feb 7 '13 at 17:44
  • Could you ping the VM(s), and wait for that to fail before allowing the host to shut down? (You might want to allow a few seconds after ping failure for the VM to completely shut down.) Or is there some command specific to Virtualbox that would let you query the status of a VM? – Scott Feb 7 '13 at 20:33
  • Polling is probably the best you can do. The problem is the command you're running is simulating pushing the power button on the machine. Different OSes handle this action differently. Ubuntu Desktop for example gives you a dialog asking you what you'd like to do. Others don't handle it at all so VirtualBox can't know if the system is actually shutting down. The other power down options (PowerOff or SaveState) are controlled completely by VirtualBox and will wait until the action is completed. – heavyd Feb 11 '13 at 17:52

Using polling, it could be done like this:

echo "Waiting for machine $MACHINE to poweroff..."

until $(VBoxManage showvminfo --machinereadable $MACHINE | grep -q ^VMState=.poweroff.)
  sleep 1

same idea as @larstobi, but less fuss by offloading poll to watch command:

$ vboxmanage list vms
"guest" {fubar-rabuf-bufu}
$ vboxmanage showvminfo guest | grep -i state
State:           running (since 2020-08-05T02:37:13.784000000)
$ printf '( watch -te  -- "! vboxmanage showvminfo guest | grep -i poweroff" >&- & wait )' | time -p bash
Command terminated by signal 2
real 5.05
user 0.00
sys 0.00

The -e flag causes exit on non-zero result of command, while -t turns off annoying headers; we close stdout for watch, since the purpose is to block and we run in fork, while technically blocking with wait which is interruptible.

I am passing the command string to time -p bash, so that I can easily attach time for the purposes of this demonstration, but in practice, you could just do:

$ ( watch -te  -- "! expression" >&- & wait )

Disclaimer: none of this is really tested

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.