vbox

Place a description here.
git clone git://git.alex.balgavy.eu/reponame.git
Log | Files | Refs | README

commit a085fb9de10fa959884be0b794143056a5f0fa1e
Author: Alex Balgavy <alex@balgavy.eu>
Date:   Sat, 13 Mar 2021 18:29:27 +0100

Initial commit

Diffstat:
A.gitignore | 34++++++++++++++++++++++++++++++++++
AMakefile | 19+++++++++++++++++++
AREADME.md | 12++++++++++++
A_vbox | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Avbox | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avbox.1.man | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 371 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,34 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/macos +# Edit at https://www.toptal.com/developers/gitignore?templates=macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# End of https://www.toptal.com/developers/gitignore/api/macos + diff --git a/Makefile b/Makefile @@ -0,0 +1,19 @@ +prefix=/usr/local +datarootdir=$(prefix)/share +datadir=$(datarootdir) +exec_prefix=$(prefix) +bindir=$(exec_prefix)/bin +mandir=$(datarootdir)/man +man1dir=$(mandir)/man1 + +all: + @echo "Targets: install, uninstall, man" + +install: vbox vbox.1.man + cp vbox $(bindir)/ + cp vbox.1.man $(man1dir)/vbox.1 + @echo "If you want Zsh completion, copy the _vbox file to your Zsh completions directory." + +uninstall: + rm $(bindir)/vbox + rm $(man1dir)/vbox.1 diff --git a/README.md b/README.md @@ -0,0 +1,12 @@ +# Vbox: a wrapper for VBoxManage and other commands +This script aims to make manipulating Virtualbox machines on the command line more user-friendly. + +## Installation +### macOS +Via Homebrew (`brew install thezeroalpha/formulae/vbox`), via the methods below. + +### Other +You have two options: + +* Install using make: run `make install` in the root of this repository +* Install manually: download the repo, then copy the `vbox` script to a directory that's in your `PATH`, copy the manpage, and add the `_vbox` file if you use Zsh and want completions. diff --git a/_vbox b/_vbox @@ -0,0 +1,52 @@ +#compdef vbox +_vboxmachines() { + VBoxManage list vms | egrep -o '^"[^"]+"' 2>/dev/null | sed -e 's|"||g' | while read machine; do + _wanted 'machine' expl 'machine' compadd $machine + done +} +_vbox() { + local -a arguments + arguments=( + 'start:start a VM' + 'stop:stop a VM' + 'open:open a VM, starting it if necessary' + 'pause:pause a VM' + 'suspend:suspend a VM' + 'resume:resume a paused VM' + 'ls:list known VMs' + 'info:get information about a VM' + 'status:get status of a VM' + 'running:list currently running VMs' + 'share:share a local folder' + 'unshare:unshare a local folder' + 'sharetmp:temporarily share a local folder' + 'shared:list shared folders for a VM' + ) + local context state line expl + local -A opt_args + _arguments '*:: :->subcmds' && return 0 + + if (( CURRENT == 1 )); then + _describe -t commands "vbox commands" arguments -V1 + return + fi + + case "$words[1]" in + share|sharetmp) + _arguments \ + ':hostpath:_files -/' \ + :machine:_vboxmachines \ + ':name: :' + ;; + unshare) + _arguments \ + ':hostpath:_files -/' \ + :machine:_vboxmachines + ;; + start|stop|open|status|info|shared|pause|suspend|resume) + _arguments \ + :machine:_vboxmachines + ;; + esac + return 1 +} diff --git a/vbox b/vbox @@ -0,0 +1,184 @@ +#!/bin/sh +die() { + echo "$1" >&2 + exit 1 +} +command -v VBoxManage >/dev/null 2>&1 || die "VBoxManage cannot be found, please install it." +command -v gstat >/dev/null 2>&1 && statcmd="gstat" +start() { + [ $# -eq 1 ] || die "Only one argument: VM name" + VBoxManage startvm "$1" --type headless +} + +stop_vm() { + [ $# -eq 1 ] || die "Only one argument: VM name" + VBoxManage controlvm "$1" acpipowerbutton +} + +open() { + [ $# -eq 1 ] || die "Only one argument: VM name" + VBoxManage startvm "$1" --type separate +} + +pause() { + [ $# -eq 1 ] || die "Only one argument: VM name" + VBoxManage controlvm "$1" pause +} +suspend_vm() { + [ $# -eq 1 ] || die "Only one argument: VM name" + VBoxManage controlvm "$1" savestate +} +resume() { + [ $# -eq 1 ] || die "Only one argument: VM name" + vminfo="$(VBoxManage showvminfo "$1")" + if [ "$(printf '%s' "$vminfo" | awk '/^State/ { print $2 }')" = "saved" ]; then + snapshots="$(printf '%s' "$vminfo" | awk '/^Snapshot folder/ { print $3 }')" + snapfile="$(find "$snapshots" -name "*.sav" -exec "${statcmd:-stat}" -c "%y %n" {} + | sort -r | head -n1 | cut -d " " -f 4-)" + + [ -n "$snapfile" ] \ + && echo "VM suspended, resuming from saved state..." \ + && VBoxManage startvm "$1" --type headless + else + echo "VM paused, resuming..." + VBoxManage controlvm "$1" resume + fi +} +list() { + VBoxManage list vms +} + +running() { + VBoxManage list runningvms +} + +info() { + VBoxManage showvminfo "$1" +} + +status() { + VBoxManage showvminfo "$1" | awk -F' +' '/^State/ { print $2 }' +} + +# share /folder/path vmname /mount/point +share() { + [ $# -eq 3 ] || die "Not enough arguments" + [ -d "$1" ] || die "$1 is not a directory or does not exist" + if ! VBoxManage sharedfolder add "$2" --name "$(basename "$(realpath "$1")")" --hostpath "$(realpath "$1")" --automount --auto-mount-point "$3"; then + echo "Could not add shared folder, machine is probably running." + echo "Stop the machine to add a permanent folder, or use sharetmp to add a transient folder." + fi +} + +unshare() { + [ $# -eq 2 ] || die "Not enough arguments" + [ -d "$1" ] || die "$1 is not a directory or does not exist" + VBoxManage sharedfolder remove "$2" --name "$(basename "$(realpath "$1")")" --transient +} + +sharetmp() { + [ $# -eq 3 ] || die "Not enough arguments" + [ -d "$1" ] || die "$1 is not a directory or does not exist" + VBoxManage sharedfolder add "$2" --name "$(basename "$(realpath "$1")")" --hostpath "$(realpath "$1")" --automount --auto-mount-point "$3" --transient +} + +shared() { + [ $# -eq 1 ] || die "Not enough arguments" + VBoxManage showvminfo "$1" | grep '^Name: .*Host path: ' +} +PARAMS="" +while [ $(($#)) -ne 0 ]; do + case "$1" in + -h|--help) + echo "Usage:" + echo "start vmname start a VM" + echo "stop vmname stop a VM" + echo "open vmname open a VM, starting it if necessary" + echo "list, ls list VMs" + echo "running list running VMs" + echo "share /local/path vmname /mount/point share a local folder" + echo "unshare /local/path vmname unshare a local folder" + echo "sharetmp /local/path vmname /mount/point temporarily share a local folder" + echo "shared vmname list shared folders" + echo "pause vmname pause a running VM" + echo "resume vmname resume a paused VM" + echo "info vmname get information about a VM" + echo "status vmname print a VM's status" + exit 0 + ;; + --) # end arg parsing + shift + break + ;; + -*) # unsupported flags + echo "Unsupported flag $1" >&2 + exit 1 + ;; + *) # preserve positional arguments + PARAMS="$PARAMS $1" + shift + ;; + esac +done +eval set -- "$PARAMS" + +[ $# -ge 1 ] || die "Not enough arguments provided." + +case "$1" in + "start") + shift; + start "$@"; + ;; + "stop") + shift; + stop_vm "$@"; + ;; + "open") + shift; + open "$@"; + ;; + "ls"|"list") + list; + ;; + "running") + running; + ;; + "share") + shift; + share "$@"; + ;; + "unshare") + shift; + unshare "$@"; + ;; + "sharetmp") + shift; + sharetmp "$@"; + ;; + "shared") + shift; + shared "$@"; + ;; + "info") + shift; + info "$@"; + ;; + "status") + shift; + status "$@"; + ;; + "pause") + shift; + pause "$@"; + ;; + "suspend") + shift; + suspend_vm "$@"; + ;; + "resume") + shift; + resume "$@"; + ;; + *) + die "Unsupported command $1"; + ;; +esac diff --git a/vbox.1.man b/vbox.1.man @@ -0,0 +1,70 @@ +.TH VBOX 1 "13 March 2021" +.SH NAME +vbox - Manipulate VirtualBox machines + +.SH SYNOPSIS +\fBvbox\fP [ -h ] +\fIcommand\fP + +.SH DESCRIPTION +\fBvbox\fP lets you manipulate (start, stop, pause, suspend) VirtualBox VMs, and change shared folders. + +.SS Options +.TP +\fB-h\fP +Get help. + +.SS Commands +.TP +\fBstart vm-name\fP +Start the VM \fIvm-name\fP (in headless mode) + +.TP +\fBstop vm-name\fP +Stop the VM \fIvm-name\fP + +.TP +\fBopen vm-name\fP +Open the GUI for the VM \fIvm-name\fP + +.TP +\fBlist\fP, \fBls\fP +List VMs. + +.TP +\fBrunning\fP +List running VMs + +.TP +\fBshare /local/path vm-name /mount/point\fP +Share the local folder \fI/local/path\fP to VM \fIvm-name\fP at guest mountpoint \fI/mount/point\fP + +.TP +\fBunshare /local/path vm-name\fP +Unshare the local folder \fI/local/path\fP from VM \fIvm-name\fP. + +.TP +\fBshared vm-name\fP +List the folders shared with \fIvm-name\fP. + +.TP +\fBpause vm-name\fP +Pause the VM \fIvm-name\fP. + +.TP +\fBresume vm-name\fP +Resume the VM \fIvm-name\fP. + +.TP +\fBinfo vm-name\fP +Get information about the VM \fIvm-name\fP. + +.TP +\fBstatus vm-name\fP +Print the status of the VM \fIvm-name\fP. + +.SH "SEE ALSO" +VBoxManage(1), +.UR https://\:www.virtualbox.org/\:manual/\:ch08.html +VirtualBox VBoxManage documentation +.UE