From 302bca7e5c430fc4a3ebf619b5e15a0d8690662a Mon Sep 17 00:00:00 2001 From: Udo Richter Date: Sun, 8 Oct 2006 00:00:00 +0200 Subject: Version 0.1.0 * Initial revision. --- runvdr | 705 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 705 insertions(+) create mode 100755 runvdr (limited to 'runvdr') diff --git a/runvdr b/runvdr new file mode 100755 index 0000000..b186a38 --- /dev/null +++ b/runvdr @@ -0,0 +1,705 @@ +#!/bin/bash +# +# runvdr extreme +# +# configurable vdr launcher script +# +# by Udo Richter +# 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 <&- 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>&- + -- cgit v1.2.3