basiliskiivm/basiliskiivm

458 lines
9.8 KiB
Bash
Executable File

#!/bin/bash
#
# basiliskiivm - Package BasiliskII emulator settings & disk images
# into a single '.basiliskiivm' directory and run
# from there.
#
# CHANGE LOG:
#
# v0.1 2016-12-08 - Morgan T. Aldridge <morgant@makkintosshu.com>
# Initial version.
#
# LICENSE:
#
# Copyright (c) 2016, Morgan T. Aldridge. All rights reserved.
#
# info
tool="$(basename "$0")"
version="0.1"
copyright="Copyright (c) 2016 Morgan Aldridge"
# global variables
BASILISKII_BINARY="${BASILISKII_BINARY:=BasiliskII}"
BASILISKII_VMS_PATH="${BASILISKII_VMS_PATH:="${HOME}/Documents/BasiliskII"}"
BASILISKII_SNAPSHOT_COMPRESSION="${BASILISKII_SNAPSHOT_COMPRESSION:=gzip}"
basiliskii_prefs_file=".basilisk_ii_prefs"
basiliskii_pid_file=".basiliskii.pid"
function in_array() {
local found=false
local value="$1"
shift
if [ -z "$value" ]; then $found; fi
if [ ${#@} -lt 1 ]; then $found; fi
for array_value in "$@"; do
if [ "$value" = "$array_value" ]; then found=true; fi
done
$found
}
function usage() {
echo "Usage: ${tool} [options] <command>"
echo
echo "Options:"
echo " -h, --help : print these usage instructions"
echo " -V, --version : print version information"
echo
echo "Commands:"
echo " info : print basic configuration info for a .BasiliskIIVM"
echo " list [<path>] : list all .BasiliskIIVM in path (or none for default directory"
echo " package : package the current BasiliskII configuration into a .BasiliskIIVM"
echo " snapshot <vm> : create a snapshot of the current state of disks in the .BasiliskIIVM"
echo " snapshots <vm>: list all snapshots in a .BasiliskIIVM"
echo " start <vm> : start a BasiliskII instance from a .BasiliskIIVM"
echo " status <vm> : get the status of a .BasiliskIIVM"
echo " stop <vm> : stop a running .BasiliskIIVM"
echo
}
function version() {
echo "${tool} v${version} ${copyright}"
}
function vm_pkg_name() {
local success=false
local vm="$(basename "$1")"
if [[ "$vm" =~ ^(.+)\.[Bb]asilisk[Ii]{2}[Vv][Mm]$ ]]; then
echo "${BASH_REMATCH[1]}"
success=true
fi
$success
}
function vm_pkg_config_file() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local prefs_file="${1}/${basiliskii_prefs_file}"
if [ -f "$prefs_file" ]; then
echo "$prefs_file"
sucess=true
fi
fi
$success
}
function vm_pkg_config_parse() {
local success=false
local vm_path="$1"
shift
local vm="$(vm_pkg_name "$vm_path")"
if [ -n "$vm" ]; then
local config="$(vm_pkg_config_file "$vm_path")"
if [ -z "$config" ]; then
echo "Error! The '$vm' BasiliskII VM's config file couldn't be found."
else
while IFS= read -r line; do
if [ -n "$line" ]; then
if [[ "$line" =~ ^([A-Za-z0-9]+)\ (.+)$ ]]; then
if in_array "${BASH_REMATCH[1]}" "$@"; then
echo "$line"
fi
fi
fi
done < "$config"
success=true
fi
fi
$success
}
function vm_pkg_disks() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local disk_paths=()
while IFS= read -r line; do
if [[ "$line" =~ ^disk\ (.+)$ ]]; then
# if [ ! -f "${BASH_REMATCH[1]}" ]; then
# echo "Warning: '${vm}' VM disk '${BASH_REMATCH[1]}' does not exist!"
# fi
disk_paths+=("${BASH_REMATCH[1]}")
fi
done <<< "$(vm_pkg_config_parse "$1" disk)"
for disk in "${disk_paths[@]}"; do
echo "$(basename "$disk")"
success=true
done
fi
$success
}
function vm_is_running() {
local running=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local pid_path="${1}/${basiliskii_pid_file}"
if [ -f "$pid_path" ]; then
if ps -p "$(cat "$pid_path")" > /dev/null 2>&1; then
running=true
fi
fi
fi
$running
}
function vm_create_pid_file() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local pid_path="${1}/${basiliskii_pid_file}"
# create the pid file
if ! echo "$2" > "$pid_path"; then
echo "ERROR! Unable to create the '$vm' BasiliskII VM PID file '$pid_path'."
else
success=true
fi
fi
$success
}
function vm_delete_pid_file() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local pid_path="${1}/${basiliskii_pid_file}"
if [ ! -f "$pid_path" ]; then
echo "ERROR! The '$vm' BasiliskII VM PID file '$pid_path' doesn't exist, so cannot delete it."
else
if ! rm "$pid_path"; then
echo "ERROR! Unable to delete the '$vm' BasiliskII VM PID file '$pid_path'."
else
success=true
fi
fi
fi
$success
}
function vm_create_package() {
success=false
echo "ERROR! This functionality isn't implemented yet."
$success
}
function vm_info() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local rom_path=""
local shared_path=""
local disk_paths=()
local screen_size=""
local ram_size=0
while IFS= read -r line; do
if [[ "$line" =~ ^([A-Za-z0-9]+)\ (.+)$ ]]; then
case "${BASH_REMATCH[1]}" in
"extfs")
shared_path="${BASH_REMATCH[2]}"
;;
"rom")
rom_path="${BASH_REMATCH[2]}"
;;
"ramsize")
ram_size=$(( ${BASH_REMATCH[2]} / 1024 / 1024 ))
;;
"disk")
disk_paths+=("${BASH_REMATCH[2]}")
;;
"screen")
if [[ "${BASH_REMATCH[2]}" =~ ^([A-Za-z]+)/([0-9]+)/([0-9]+)$ ]]; then
screen_size="${BASH_REMATCH[2]}x${BASH_REMATCH[3]}"
fi
;;
esac
fi
done <<< "$(vm_pkg_config_parse "$1" disk extfs screen rom ramsize)"
echo "$(basename "$1"):"
echo
echo "Path: $(dirname "$1")"
echo "ROM: $(basename "${rom_path}")"
echo "RAM: ${ram_size}MB"
echo "Resolution: ${screen_size}"
echo "Shared Folder: ${shared_path}"
echo "Disks:"
for disk in "${disk_paths[@]}"; do
echo " $(basename "$disk")"
done
success=true
fi
$success
}
function vm_status() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
echo -n "'$vm': "
if vm_is_running "$1"; then
echo "Running"
else
echo "Stopped"
fi
success=true
fi
$success
}
function vm_start() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
if vm_is_running "$1"; then
echo "Error! The '$vm' BasiliskII VM is already running."
else
local config="$(vm_pkg_config_file "$1")"
if [ -z "$config" ]; then
echo "Error! The '$vm' BasiliskII VM's config file couldn't be found."
else
echo "Starting the '$vm' BasiliskII VM..."
"$BASILISKII_BINARY" --config "$config" >/dev/null &
local pid="$!"
if [ -z "$pid" -a "$pid" -lt 1 ]; then
echo "ERROR! The '$vm' BasiliskII VM didn't start correctly."
elif vm_create_pid_file "$1" "$pid"; then
success=true
fi
fi
fi
fi
$success
}
function vm_stop() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
if ! vm_is_running "$1"; then
echo "Error! The '$vm' BasiliskII VM is not running."
else
echo "Warning! It is not safe to stop the '$vm' BasiliskII VM while it is running."
echo "Please choose Special > Shutdown from within the BasiliskII VM instance to shut it down."
fi
fi
$success
}
function vm_pkg_snapshots() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
local snapshots_path="${1}/Snapshots"
if [ -d "$snapshots_path" ]; then
while IFS= read -r line; do
echo "$(basename "$line")"
done <<< "$(find "$snapshots_path" -type d -mindepth 1 -maxdepth 1)"
fi
success=true
fi
$success
}
function vm_pkg_create_snapshot() {
local success=false
local vm="$(vm_pkg_name "$1")"
if [ -n "$vm" ]; then
if vm_is_running "$1"; then
echo "Error! You cannot create a snapshot while the '${vm}' BasiliskII VM is running. Please stop it and try again."
return 1
fi
local snapshots_path="${1}/Snapshots"
if [ ! -d "$snapshots_path" ]; then
if ! mkdir "$snapshots_path"; then
echo "Error! Unable to create snapshots directory '${snapshots_path}'."
return 1
fi
fi
local timestamp="$(date +%Y%m%d-%H%M%S)"
local snapshot="${snapshots_path}/${timestamp}"
if ! mkdir "$snapshot"; then
echo "Error! Unable to create snapshot directory '${snapshot}'."
else
local disks_copy_success=true
while IFS= read -r disk; do
local src_disk="${1}/${disk}"
local dst_disk="${snapshot}/${disk}"
local copy_success=true
case "$BASILISKII_SNAPSHOT_COMPRESSION" in
"gzip")
dst_disk="${dst_disk}.gz"
if ! gzip -k -c "$src_disk" > "$dst_disk"; then
copy_success=false
fi
;;
*)
if ! cp "$src_disk" "$dst_disk"; then
copy_success=false
fi
;;
esac
if ! $copy_success; then
echo "Error! Unable to copy disk '${src_disk}' to '${dst_disk}'."
disks_copy_success=false
fi
done <<< "$(vm_pkg_disks "$1")"
if $disks_copy_success; then
echo "Created '${timestamp}' snapshot of '${vm}' BasiliskII VM."
success=true
else
echo "Error! Unable to create '${timestamp}' snapshot of '${vm}' BasiliskII VM."
fi
fi
fi
$success
}
function list_vms() {
success=false
local vms_path="$1"
if [ -z "$vms_path" ]; then
vms_path="$BASILISKII_VMS_PATH"
fi
while IFS= read -r line; do
echo "$(basename "$line")"
done <<< "$(find "$vms_path" -iname "*.BasiliskIIVM")"
success=true
$success
}
function main() {
case "$1" in
"-h" | "--help")
usage
exit 0
;;
"-V" | "--version")
version
exit 0
;;
"info")
shift
vm_info "$1"
;;
"list")
shift
list_vms "$1"
;;
"snapshot")
shift
vm_pkg_create_snapshot "$1"
;;
"snapshots")
shift
vm_pkg_snapshots "$1"
;;
"start")
shift
vm_start "$1"
;;
"status")
shift
vm_status "$1"
;;
"stop")
shift
vm_stop "$1"
;;
"package")
shift
vm_create_package "$1"
;;
*)
echo "ERROR! Unknown option '$1'. Exiting"
exit 1
;;
esac
}
main "$@"