#!/bin/bash
# $Id: vmware-ws-ctl,v 1.13 2019/04/15 01:21:23 friedman Exp $

apush() { eval "$1=(\"\${$1[@]}\" \"\${@:2}\")"; }

anreverse()
{
    eval set "$1" "\"\${$1[@]}\""
    eval unset "$1"
    while [ $# -gt 1 ]; do
        eval "$1=(\"$2\" \"\${$1[@]}\")"
        set "$1" "${@:3}"
    done
}

docmd()
{
  echo + "$@" 1>&2
  "$@"
}

system()
{
    local action=$1

    case ${EUID-${UID-`id -u`}} in
        0 ) : ;;
        * ) exec sudo "$0" system "$action" || exit $? ;;
    esac

    declare -a svcs=( vmware vmamqpd )
    if lsusb > /dev/null 2>&1; then
        apush svcs vmware-USBArbitrator
    fi
    apush svcs vmware-workstation-server vmware-wsx-server

    case $action in
        stop ) anreverse svcs ;;
    esac

    for svc in "${svcs[@]}" ; do
        test -f /etc/rc.d/init.d/$svc ||
            test -f /etc/init.d/$svc  ||
            continue
        docmd systemctl "$action" $svc.service
    done
    exit $?
}

move_home()
{
    case $HOME in
        */etc/misc ) : ;;
        * ) HOME=$HOME/etc/misc ;;
    esac
    export HOME
}

set_vmguest_vmx()
{
    local os=$1
    local vmroot=${VMROOT-/export/vm/vmware}
    local vmdir arch

    case $os in
        f[1-9][0-9] | f[1-9][0-9]-* ) os=fedora${os#f} ;;
    esac

    case $os in
        *-x64 ) arch=x86_64- os=${os%-x64} ;;
        *-x86 ) arch=x86-    os=${os%-x86} ;;
    esac

    vmx=
    for vmdir in "$vmroot/$os" "$vmroot/$arch"*"$os"* ; do
        for f in "$vmdir"/*.vmx ; do
            if [ -f "$f" ]; then
                case $vmx in
                   '' ) vmx=$f
                        case $f in
                            */$os/*.vmx ) break 2 ;;
                        esac ;;
                    * ) # If the next match is a proper superstring of the
                        # previous match, then the previous match is
                        # unambiguous because we have to have some way of
                        # selecting that string exactly.
                        case ${f%/*} in ${vmx%/*}* ) break ;; esac

                        # But if they do not share a common prefix string,
                        # they are ambiguous (e.g. x86 vs. x86_64).
                        exec 1>&2
                        echo "$progname: \"$1\": ambiguous vm name:"
                        for f in "$vmroot/$arch"*"$os"*/*.vmx ; do
                            f=${f#$vmroot/}
                            f=${f%%/*}
                            echo "$progname:		$f"
                        done
                        exit 1
                        ;;
                esac
            fi
        done
    done

    case $vmx in
        '' ) echo "$progname: \"$1\": no match" 1>&2
             exit 1 ;;
    esac
}

vmcmd()
{
    local vmguest=$1
    local     cmd=$2
    shift; shift

    set_vmguest_vmx "$vmguest"
    move_home
    cd "${vmx%/*}" || exit $?

    docmd vmrun "$cmd" "$vmx" "$@"
}

dovnc()
{
    local vmguest=$1
    shift

    set_vmguest_vmx "$vmguest"
    local port=`sed -ne '/RemoteDisplay.vnc.port *= *"\([0-9]*\)".*/s//\1/p' "$vmx"`

    case $port in
        '' ) echo "$progname: no vnc port in $vmx" 1>&2
             exit 1 ;;
    esac

    local host
    case $DISPLAY in
        :* | localhost*:* ) : ;;
        *  ) host=${VMWARE_WS_CTL_HOSTNAME-${HOSTNAME-`uname -n`}} ;;
    esac

    docmd ${VMWARE_WS_CTL_VNC_CLIENT-vnc} "$@" $host:$port
}

main()
{
    progname=${0##*/}

    case $# in
        0|1 ) exec 1>&2
            echo "Usage:"
            echo "	$progname system [start|stop]"
            echo "	$progname vmguest start   {gui|*nogui*}"
            echo "	$progname vmguest stop    {hard|*soft*}"
            echo "	$progname vmguest suspend {hard|*soft*}"
            echo "	$progname vmguest reset   {hard|*soft*}"
            echo "	$progname vmguest [any other vmrun command]"
            echo
            echo "	$progname vmguest vnc  [connects to vnc port]"
            echo
            echo "Asterisked flags are the default."
            echo "Vmguest can be any unambiguous abbreviation."
            echo "Appending -x86 or -x64 will resolve arch differences."
            echo "Fedora systems can be abbreviated f14 -> fedora14"
            exit 1 ;;
    esac

    local vmguest=$1
    local     cmd=$2
    shift; shift

    case $vmguest in
        system ) "$vmguest" "$cmd" ;;
    esac

    case $cmd in
        start   ) vmcmd "$vmguest" "$cmd" ${1-nogui} "$@" ;;
        stop    ) vmcmd "$vmguest" "$cmd" ${1-soft}  "$@" ;;
        suspend ) vmcmd "$vmguest" "$cmd" ${1-hard}  "$@" ;;
        reset   ) vmcmd "$vmguest" "$cmd" ${1-soft}  "$@" ;;
        vnc     ) dovnc "$vmguest"                   "$@" ;;
        *       ) vmcmd "$vmguest" "$cmd"            "$@" ;;
    esac
}

main "$@"

# eof
