#!/bin/bash
#  
#  runvdr extreme
#
#  configurable vdr launcher script
#
#      by Udo Richter <udo_richter(a)gmx.de>
#      http://www.richter-udo.de/vdr/scripts.html#runvdr
#

RUNVDRCONF=/etc/runvdr.conf


# Some unix commands being used:

PGREP="pgrep"
PS="ps"
GETOPT="getopt"
KILL="kill"
SLEEP="sleep"
CHVT="chvt"
DATE="date"
SETTERM="setterm"

# Options summary and conf file entries of runvdr:
#
# -C # --runvdr-conf=#   RUNVDRCONF       location of runvdr config file
# --                     ADDPARAM         Additional parameters to pass to VDR
# --pluginsetup-conf=#   PLUGINSETUPCONF  location of plugin-setup-runvdr.conf
# --vdr=#                VDRPRG           location and name of the vdr binary
# --switchterminal=#     SWITCHTERMINAL   console terminal to switch to
# --runvdr-pid=#         RUNVDRPID        location of runvdr.pid file
# --dvb-load=#           DVBLOAD          command to load DVB drivers
# --dvb-unload=#         DVBUNLOAD        command to unload DVB drivers
# --wrapper=#            WRAPPER          wrapper command for calling vdr
# --terminate[=#]        TERMINATE        Terminate runvdr by pid
# --wait[=#]             WAIT             Wait # seconds for --terminate to finish
# --restart[=#]          RESTART          Send restart signal by pid
# --dvb-restart[=#]      DVBRESTART       Send dvb-restart signal by pid
# --term-timeout=#       TERMTIMEOUT      Timeout for VDR to react on SIGTERM
# --kill-timeout=#       KILLTIMEOUT      Timeout for VDR to react on SIGKILL
# --language=#           LANGUAGE         Locale to set for VDR
# -V --version           VERSION          print version information and exit
# -h --help              HELP             print this help and exit
#
# Supported options of VDR 
#                     
#  -a #  --audio #    AUDIO            send Dolby Digital audio to stdin of command #
#  -c #  --config #   CONFIGDIR        read config files from DIR
#  -d    --daemon     DAEMON           run in daemon mode
#  -D #  --device #   DVBDEVICE        use only the given DVB device (NUM = 0, 1, 2...)
#  -E #  --epgfile #  EPGFILE          write the EPG data into the given FILE. - to disable.
#  -g #  --grab #     GRAB             write images from the SVDRP command GRAB into the given DIR;
#  -L #  --lib #      LIBDIR           search for plugins in DIR (default is %s)
#        --lirc #?    LIRC             use a LIRC remote control device, attached to PATH
#  -l #  --log #      LOGLEVEL         set log level (default: 3)
#  -m    --mute       MUTE             mute audio of the primary DVB device at startup
#        --no-kbd     NOKBD            don't use the keyboard as an input device
#  -P #  --plugin #   PLUGINS          load a plugin defined by the given options
#  -p #  --port #     SVDRPPORT        use PORT for SVDRP 
#        --rcu #?     RCU              use a remote control device, attached to PATH
#  -r #  --record #   RECORDCMD        call CMD before and after a recording
#  -s #  --shutdown # SHUTDOWN         call CMD to shutdown the computer
#  -t #  --terminal # TERMINAL         controlling tty
#  -u #  --user #     USER             run as user USER; only applicable if started as root
#  -v    --vfat       VFAT             encode special characters in recording names
#  -v #  --video #    VIDEODIR         use DIR as video directory
#  -w #  --watchdog # WATCHDOG         activate the watchdog timer with a timeout of SEC


which $PGREP     >- || { echo missing $PGREP... >2 ;   exit 1 ; }
which $PS        >- || { echo missing $PS... >2 ;      exit 1 ; }
which $GETOPT    >- || { echo missing $GETOPT... >2 ;  exit 1 ; }
which $KILL      >- || { echo missing $KILL... >2 ;    exit 1 ; }
which $SLEEP     >- || { echo missing $SLEEP... >2 ;   exit 1 ; }
which $CHVT      >- || { echo missing $CHVT... >2 ;    exit 1 ; }
which $DATE      >- || { echo missing $DATE... >2 ;    exit 1 ; }
which $SETTERM   >- || { echo missing $SETTERM... >2 ; exit 1 ; }



function ParseCommandLine_Step1() {
    # Parse command line, step 1
    # Stores pre-processed options in $OPTIONS
    # evaluates -C and --runvdr-conf only

    SHORTOPT="a:c:C:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:"
    LONGOPT="runvdr-conf:,pluginsetup-conf:,vdr:,switchterminal:,\
        runvdr-pid:,dvb-load:,dvb-unload:,language:,wrapper:,\
        term-timeout:,kill-timeout:,terminate::,restart::,dvb-restart::,\
        wait::,audio:,config:,daemon,device:,epgfile:,grab:,help,lib:,lirc::,\
        log:,mute,no-kbd,plugin:,port:,rcu::,record:,shutdown:,\
        terminal:,user:,version,vfat,video:,watchdog:"
    

    # prepare all optios for later processing
    OPTIONS=`$GETOPT -o "$SHORTOPT" --long "$LONGOPT" -n "$0" -- "$@"` || exit 1
        
    # evaluate only -C and --runvdr-conf
    EARLYOPTIONS=`$GETOPT -q -o "C:" --long "runvdr-conf:" -n "$0" -- "$@"` 
    
    eval set -- "$EARLYOPTIONS"
    
    while true ; do case "$1" in
        -C|--runvdr-conf)
            RUNVDRCONF="$2"
            shift 2
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "Internal error!" >2
            exit 1
            ;;
    esac ; done
}

function Clean() {
    # Clean all config variables
    ADDPARAM=
    PLUGINSETUPCONF=
    VDRPRG=
    SWITCHTERMINAL=
    RUNVDRPID=
    DVBLOAD=
    DVBUNLOAD=
    LANGUAGE=
    WRAPPER=
    TERMTIMEOUT=
    KILLTIMEOUT=
    TERMINATE=
    RESTART=
    DVBRESTART=
    WAIT=0
    HELP=
    VERSION=

    AUDIO=
    CONFIGDIR=
    DAEMON=
    DVBDEVICE=()
    EPGFILE=
    GRAB=
    LIBDIR=
    LIRC=
    LOGLEVEL=
    MUTE=
    NOKBD=
    PLUGINS=()
    SVDRPPORT=
    RECORDCMD=
    RCU=
    SHUTDOWN=
    TERMINAL=
    VDRUSER=
    VFAT=
    VIDEODIR=
    WATCHDOG=
}


# Helper functions
function AddPluginString() {
    # add $1 as plugin
    if [ "$1" == "-" ] ; then
        PLUGINS=()
    else
        PLUGINS[${#PLUGINS[*]}]="$*"
    fi
}
function AddPlugin() {
    # add $* as plugin, do shell quoting

    local plugin=""
    while [ $# -gt 0 ] ; do
        # regexp magic
        # quote '\' to '\\'
        local par="$1"
        par="${par//'\'/\\\\}"
        # work around bash bug: double quoted '\'
        par="${par//'\\'/\\\\}"
        # quote '"' to '\"'
        par="${par//\"/\\\"}"
        # check if this splits into words
        local -a arr=($par)
        # if yes, wrap in quotes
        [ ${#arr[*]} -ne 1 ] && par="\"$par\""
        # add to plugin string      
        if [ -n "$plugin" ] ; then plugin="$plugin $par" ; else plugin="$par" ; fi
        # next, please
        shift
    done
    AddPluginString "$plugin"
}
function AddDevice() {
    if [ "$1" == "-" ] ; then
        DVBDEVICE=()
    else
        DVBDEVICE[${#DVBDEVICE[*]}]="$*";
    fi
}


function LoadConfFile() {

    # Load configuration file
    
    if [ -r $RUNVDRCONF ] ; then
        . $RUNVDRCONF || exit 1
    else
        echo "runvdr: $RUNVDRCONF not found." >&2
    fi

    # Transform some defaults, so empty parameters can have a 
    # non-default meaning
    [ -z "$LIRC" ] && LIRC=0
    [ -z "$RCU"  ] && RCU=0
    [ -z "$TERMINATE" ] && TERMINATE=0
    [ -z "$RESTART" ] && RESTART=0
    [ -z "$DVBRESTART" ] && DVBRESTART=0

    return 0
}


function ParseCommandLine_Step2() {
    # Parse command line, step 2
    # Process all options in $OPTIONS, override
    # all options that are set by now
    
    eval set -- "$OPTIONS"
    
    while true ; do case "$1" in
        -C|--runvdr-conf)                    shift 2;;
           --pluginsetup-conf) PLUGINSETUPCONF="$2"; shift 2;;
           --vdr)          VDRPRG="$2";      shift 2;;
           --switchterminal) SWITCHTERMINAL="$2"; shift 2;;
           --runvdr-pid)   RUNVDRPID="$2";   shift 2;;
           --dvb-load)     DVBLOAD="$2";     shift 2;;
           --dvb-unload)   DVBUNLOAD="$2";   shift 2;;
           --language)     LANGUAGE="$2";    shift 2;;
           --wrapper)      WRAPPER="$2";     shift 2;;
           --term-timeout) TERMTIMEOUT="$2"; shift 2;;
           --kill-timeout) KILLTIMEOUT="$2"; shift 2;;
           --terminate)    TERMINATE="$2";   shift 2;;
           --wait)         WAIT="$2";        shift 2;;
           --restart)      RESTART="$2";     shift 2;;
           --dvb-restart)  DVBRESTART="$2";  shift 2;;
        -h|--help)         HELP=1;           shift  ;;
        -V|--version)      VERSION=1;        shift  ;;

        
        -a|--audio)        AUDIO="$2";     shift 2;;
        -c|--config)       CONFIGDIR="$2"; shift 2;;
        -d|--daemon)       DAEMON=1;       shift  ;;
        -D|--device)       AddDevice "$2"; shift 2;;
        -E|--epgfile)      EPGFILE="$2";   shift 2;;
        -g|--grab)         GRAB="1";       shift  ;;
        -l|--log)          LOGLEVEL="$2";  shift 2;;
        -L|--lib)          LIBDIR="$2";    shift 2;;
           --lirc)         LIRC="$2";      shift 2;;
        -m|--mute)         MUTE=1;         shift  ;;
           --no-kbd)       NOKBD=1;        shift  ;;
        -p|--port)         SVDRPPORT="$2"; shift 2;;
        -P|--plugin)       AddPluginString "$2"; shift 2;;
           --rcu)          RCU="$2";       shift 2;;
        -r|--record)       RECORDCMD="$2"; shift 2;;
        -s|--shutdown)     SHUTDOWN="$2";  shift 2;;
        -t|--terminal)     TERMINAL="$2";  shift 2;;
        -u|--user)         USER="$2";      shift 2;;
        -v|--video)        VIDEODIR="$2";  shift 2;;
           --vfat)         VFAT=1;         shift  ;;
        -w|--watchdog)     WATCHDOG="$2";  shift 2;;

            
        --)
            shift
            break
            ;;
        *)
            echo "Internal error!" >2
            exit 1
            ;;
    esac ; done
    
    # Add all remaining options directly to additional params
    
    if [ -n "$1" ] ; then
        [ -n "$ADDPARAM" ] && ADDPARAM="$ADDPARAM "
        ADDPARAM="$ADDPARAM$@"
    fi
    
    return 0
}



function OnlineHelp() {
    cat <<END-OF-HELP
Usage: $0 [OPTIONS] 

runvdr Options:
-C #, --runvdr-conf=# location of runvdr config file
--pluginsetup-conf=#  location of plugin-setup-runvdr.conf
--vdr=#               location and name of the vdr binary
--switchterminal=#    console terminal number to switch to
--runvdr-pid=#        location of runvdr.pid file
--dvb-load=#          command to load DVB drivers
--dvb-unload=#        command to unload DVB drivers
--wrapper=#           wrapper command for calling vdr
--language=#          Locale to set for VDR
--terminate[=#]       Terminate runvdr by pid
--wait[=#]            Wait # seconds for --terminate to finish
--restart[=#]         Send restart signal by pid
--dvb-restart[=#]     Send dvb-restart signal by pid
--term-timeout=#      Timeout for VDR to react on SIGTERM
--kill-timeout=#      Timeout for VDR to react on SIGKILL

-V, --version         print version information and exit
-h, --help            print this help and exit

Parsed VDR options:
-a # --audio=#    send Dolby Digital audio to stdin of command CMD
-c # --config=#   read config files from DIR
-d   --daemon     run in daemon mode
-D # --device=#   use only the given DVB device (NUM = 0, 1, 2...)
                  Use '-' to override devices from config file
-E # --epgfile=#  write the EPG data into the given FILE. - to disable.
-g # --grab=#     write images from the SVDRP command GRAB into the given DIR
-L # --lib=#      search for plugins in DIR
     --lirc[=#]   use a LIRC remote control device, attached to PATH
-l # --log=#      set log level
-m   --mute       mute audio of the primary DVB device at startup
     --no-kbd     don't use the keyboard as an input device
-P # --plugin=#   load a plugin defined by the given options
                  Use '-' to ignore plugins from config file
-p # --port=#     use PORT for SVDRP
     --rcu[=#]    use a remote control device, attached to PATH
-r # --record=#   call CMD before and after a recording
-s # --shutdown=# call CMD to shutdown the computer
-t # --terminal=# controlling tty
-u # --user=#     run as user USER; only applicable if started as root
     --vfat       encode special characters in recording names
-v # --video=#    use DIR as video directory
-w # --watchdog=# activate the watchdog timer with a timeout of SEC

All runvdr parameters after '--' will be passed to VDR without modification
END-OF-HELP
}

function BuildCommand() {
    # Based on all options, build command line in $VDRCMD

    # complete command with path
    VDRPRG=`which "$VDRPRG"`
    if [ -z "$VDRPRG" ] ; then
        echo "VDR command binary not found."
        exit 1
    fi
    
    # Build up command line:
    VDRCMD="$VDRPRG"
    [ -n "$ADDPARAM"  ] && VDRCMD="$VDRCMD $ADDPARAM"
    [ -n "$WRAPPER"   ] && VDRCMD="$WRAPPER $VDRCMD"

    [ -n "$AUDIO"     ] && VDRCMD="$VDRCMD -a \"$AUDIO\""
    [ -n "$CONFIGDIR" ] && VDRCMD="$VDRCMD -c \"$CONFIGDIR\""
    [ -n "$DAEMON"    ] && VDRCMD="$VDRCMD -d"

    for ((i=0;i<${#DVBDEVICE[*]};i++)) ; do 
        [ -n "${DVBDEVICE[i]}" ] && VDRCMD="$VDRCMD -D ${DVBDEVICE[i]}"
    done

    [ -n "$EPGFILE"   ] && VDRCMD="$VDRCMD -E \"$EPGFILE\""
    [ -n "$GRAB"      ] && VDRCMD="$VDRCMD -g"
    [ -n "$LOGLEVEL"  ] && VDRCMD="$VDRCMD -l $LOGLEVEL"
    [ -n "$LIBDIR"    ] && VDRCMD="$VDRCMD -L $LIBDIR"
    case "$LIRC" in
        1|"") VDRCMD="$VDRCMD --lirc";;
        0) ;;
        *) VDRCMD="$VDRCMD --lirc=\"$LIRC\"";;
    esac
    [ -n "$MUTE"      ] && VDRCMD="$VDRCMD -m"
    [ -n "$NOKBD"     ] && VDRCMD="$VDRCMD --no-kbd"
    [ -n "$SVDRPPORT" ] && VDRCMD="$VDRCMD -p $SVDRPPORT"

    for ((i=0;i<${#PLUGINS[*]};i++)) ; do
        p="${PLUGINS[i]}"
        if [ -n "$p" ] ; then
            # do some shell quoting
            p="${p//'\'/\\\\}"
            p="${p//'\\'/\\\\}"
            p="${p//\"/\\\"}"
            p="${p//\$/\\\$}"
            p="${p//\`/\\\`}"
            VDRCMD="$VDRCMD -P \"$p\""
        fi
    done

    if [ -n "$PLUGINSETUPCONF" ] ; then
        ALL_PLUGINS=`< $PLUGINSETUPCONF`
        VDRCMD="$VDRCMD $ALL_PLUGINS"
    fi

    [ -n "$RECORDCMD" ] && VDRCMD="$VDRCMD -r \"$RECORDCMD\""
    case "$RCU" in
        1|"") VDRCMD="$VDRCMD --rcu";;
        0) ;;
        *) VDRCMD="$VDRCMD --rcu=\"$RCU\"";;
    esac
    [ -n "$SHUTDOWN"  ] && VDRCMD="$VDRCMD -s \"$SHUTDOWN\""
    [ -n "$TERMINAL"  ] && VDRCMD="$VDRCMD -t \"$TERMINAL\""
    [ -n "$VDRUSER"   ] && VDRCMD="$VDRCMD -u \"$VDRUSER\""
    [ -n "$VFAT"      ] && VDRCMD="$VDRCMD -v"
    [ -n "$VIDEODIR"  ] && VDRCMD="$VDRCMD -v \"$VIDEODIR\""
    [ -n "$WATCHDOG"  ] && VDRCMD="$VDRCMD -w $WATCHDOG"


    [ -z "$TERMTIMEOUT" ] && TERMTIMEOUT=20
    [ -z "$KILLTIMEOUT" ] && KILLTIMEOUT=5

    return 0
}

function GetChilds() {
    # Get PIDs of all forked childs of PID=$1, binary executable=$2
    # Returns list of PIDs in childlist
  
    child="$1"
    childlist=($child)
    IFSBACKUP="$IFS"
    for ((i=0;i<10;i++)) do
        len=${#childlist[*]}
        IFS=","
        child=`{ echo "$child" ; $PGREP -f "^$2 " -P "${childlist[*]}" ; } | sort -u`
        IFS="$IFSBACKUP"
        childlist=($child)

        [ "$len" -eq "${#childlist[*]}" ] && break
    done
}

function WaitKill() {
    # Terminates/Kills process $1, binary $2, timeout1 $3, timeout2 $4
    
    GetChilds "$1" "$2"

    echo -n "Sending ${#childlist[*]} processes the TERM signal."
    $KILL -TERM ${childlist[*]} >&- 2>&-

    for ((i=0;i<$3;i++)) ; do
        $PS ${childlist[*]} >&- 2>&- || { echo terminated. ; return ; }
        
        echo -n .
        $SLEEP 1
    done
    echo

    echo -n "Sending ${#childlist[*]} processes the KILL signal."
    $KILL -KILL ${childlist[*]} >&- 2>&-
    
    for ((i=0;i<$4;i++)) ; do
        $PS ${childlist[*]} >&- 2>&- || { echo terminated. ; return ; }
        echo -n .
        $SLEEP 1
    done
    echo failed.
}



#### ---------------
####   Main script
#### ---------------


# Parse command line, step 1
ParseCommandLine_Step1 "$@" || exit 1

# Clean variables
Clean

# Load and process all configuration
LoadConfFile || exit 1

# Process command line
ParseCommandLine_Step2 || exit 1


if [ -n "$HELP" ] ; then
    OnlineHelp
    exit 0
fi

if [ -n "$VERSION" ] ; then
    echo "runvdr version 0.1.0"
    exit 0
fi

# Get old runvdr pid and move it to options
if [ -n "$RUNVDRPID" ] ; then
    OLDRUNVDRPID=""
    [ -r "$RUNVDRPID" ] && OLDRUNVDRPID=`<$RUNVDRPID`

    [ -z "$TERMINATE"  ] && TERMINATE="$OLDRUNVDRPID"
    [ -z "$RESTART"    ] && RESTART="$OLDRUNVDRPID"
    [ -z "$DVBRESTART" ] && DVBRESTART="$OLDRUNVDRPID"
fi

if [ "$TERMINATE" != "0" ] ; then
    if [ -n "$TERMINATE" ] ; then
        echo -n "Terminating runvdr (PID=$TERMINATE)"
        $KILL -TERM $TERMINATE
        while [ -z "$WAIT" ] || [ "$WAIT" -gt 0 ] ; do
            $PS $TERMINATE >&- || { echo done ; break ; }
            echo -n "."
            $SLEEP 1
            [ -n "$WAIT" ] && let WAIT=WAIT-1
        done

        echo ""
    else
        echo "No runvdr process to terminate."
    fi
    exit 0
fi

if [ "$RESTART" != "0" ] ; then
    if [ -n "$RESTART" ] ; then
       echo -n "Restarting runvdr (PID=$RESTART)..."
       $KILL -USR1 $RESTART
       echo ""
    else
        echo "No runvdr process to restart."
    fi
    exit 0
fi

if [ "$DVBRESTART" != "0" ] ; then
    if [ -n "$DVBRESTART" ] ; then
        echo -n "DVB-restarting runvdr (PID=$DVBRESTART)..."
        $KILL -USR2 $DVBRESTART
        echo ""
    else
        echo "No runvdr process to dvb-restart."
    fi
    exit 0
fi


# Build up VDR command
BuildCommand || exit 1


# Switch front console

[ -n "$SWITCHTERMINAL" ] && $CHVT $SWITCHTERMINAL

if [ -n "$LANGUAGE" ] ; then
    LANG="$LANGUAGE"
    export LANG
fi

# Remember PID of this process

[ -n "$RUNVDRPID" ] && echo $$ > $RUNVDRPID


# Prepare terminal redirection
if [ -n "$TERMINAL" ] ; then
    exec 1>"$TERMINAL"
    exec 2>"$TERMINAL"
fi


# Load driver if it hasn't been loaded already:
$DVBLOAD

# Count how often VDR terminated very quickly
SHORTRUNTIMES=0

while (true) do 
    echo -n "Starting VDR at " ; $DATE

    # Trap some signals sent to this script
    trap "SIG=HUP" SIGHUP
    trap "SIG=INT" SIGINT
    trap "SIG=QUIT" SIGQUIT
    trap "SIG=TERM" SIGTERM
    trap "SIG=USR1" SIGUSR1
    trap "SIG=USR2" SIGUSR2

    # clean up signal variable
    SIG=
    
    # Remember start time
    STARTTIME=`$DATE +%s`

    echo "$VDRCMD"

    # Run VDR
    eval "$VDRCMD &"
    
    # Remember PID of VDR process
    PID=$!
    
    # Wait for VDR to end or signal to arrive
    wait $PID
    
    # Remember return value of VDR
    RET=$?
    
    # Remember stop time
    STOPTIME=`$DATE +%s`
    # Count if time is less than 10 seconds,
    # forget otherwise
    if [ $((STOPTIME-STARTTIME)) -le 10 ] ; then
        SHORTRUNTIMES=$((SHORTRUNTIMES+1))
        echo "VDR died within 10 seconds, this happened $SHORTRUNTIMES time(s)."
    else
        SHORTRUNTIMES=0
    fi
    
    # Reset terminal status
    [ -n "$TERMINAL" ] && $SETTERM -initialize
    
    case "$SIG" in
      HUP | INT | QUIT | TERM)
        echo -n "Terminating by request at " ; $DATE

        # Kill remaining VDR traces
        WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT
    
        # and exit
        break
        ;;
      USR1)
        echo -n "Restarting VDR by request at " ; $DATE

        # Kill remaining VDR traces
        WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT
    
        # and loop
        ;;
      USR2)
        echo -n "Restarting VDR and DVB by request at " ; $DATE

        # Kill remaining VDR traces
        WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT
    
        # reload DVB stuff
        $DVBUNLOAD
        $DVBLOAD
        ;;
      *)  # Non-signal termination
        if [ $RET -eq 0 -o $RET -eq 2 ] ; then 
            echo -n "Terminating by error level $RET at " ; $DATE

            # Kill remaining VDR traces
            WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT
    
            # and exit
            break
        fi
        if [ $SHORTRUNTIMES -ge 5 ] ; then
            echo -n "Terminating because VDR died 5 times in a row quickly at " ; $DATE

            # Kill remaining VDR traces
            WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT
    
            # and exit
            break;
        fi
        echo -n "Restarting VDR and DVB by error level $RET at " ; $DATE

        # Kill remaining VDR traces
        WaitKill $PID $VDRPRG $TERMTIMEOUT $KILLTIMEOUT

        # reload DVB
        $DVBUNLOAD
        $DVBLOAD

        # and loop
        ;;
    esac
    
    # reload configuration
    Clean
    LoadConfFile || exit 1
    ParseCommandLine_Step2 || exit 1
    BuildCommand || exit 1

    # Catch remaining in-between signals
    case "$SIG" in
      HUP | INT | QUIT | TERM)
        break
        ;;
    esac
done

# Clean up PID file
[ -n "$RUNVDRPID" ] && rm $RUNVDRPID >&- 2>&-