Files
utilities/obsolete/shellbox

396 lines
9.7 KiB
Bash
Executable File

#!/bin/bash
# chkconfig: 2345 98 2
# description: shellbox service for spawning programs
HOME=/root
. /etc/profile
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
if [ -f /usr/local/bin/getIocBootEnv ]
then
. /usr/local/bin/getIocBootEnv
#echo ""
#echo "shellbox: IOC=$IOC"
#echo "shellbox: FACILITY=$FACILITY"
#echo "shellbox: ROOTFSSERVERIP=$ROOTFSSERVERIP"
#echo "shellbox: BOOTPC=$BOOTPC"
#echo "shellbox: CMDLINE_HOST=$CMDLINE_HOST"
#echo "shellbox: CMDLINE_ETH=$CMDLINE_ETH"
#echo "shellbox: BOOTIF_BCAST=$BOOTIF_BCAST"
#echo "shellbox: BOOTIF_IP=$BOOTIF_IP"
#echo ""
fi
if [ "$IOC" == "" ]
then
HOSTNAME=$(hostname -s)
else
HOSTNAME=$IOC
fi
export HOSTNAME
fail () {
echo $@ >&2
exit 1
}
options="-k ^X --killsig 15 -x ^D -i ^C --allow -c"
prog=shellbox
conf=/etc/shellbox.conf
logdir=/var/log/$prog
shells=/var/run/$prog
# color only if printing to terminal
declare -A COLOR
if [ -t 1 ]
then
COLOR[RUNNING]=
COLOR[STOPPED]=$'\033[46;30m'
COLOR[DISABLED]=$'\033[47;38;5;8m'
COLOR[OBSOLETE]=$'\033[48;5;8;37m'
COLOR[MODIFIED]=$'\033[43;30m'
COLOR[DEAD]=$'\033[41;37m'
COLOR[NORMAL]=$'\033[0;39m'
COLOR[HEADER]=$'\033[0;1;4m'
fi
echo_failure () {
echo " [failed]"
}
checkpid () {
[ -d /proc/$* ]
}
launch () {
[ -f /ioc/${HOSTNAME}/DoNotStartEpics ] && fail "Not starting EPICS because /ioc/${HOSTNAME}/DoNotStartEpics exists"
if [ "$1" = "-reload" ]
then
reload=YES
shift
fi
[ -d /var/run/procServ ] || mkdir -pm 755 /var/run/procServ
[ -z "$logdir" -o -d "$logdir" ] || mkdir -pm 755 "$logdir"
temp=$(mktemp -p $(dirname $shells)) || fail "can't create temporary file"
# delete entries for dead shell that we are going to restart
if [ -f $shells ]
then
while read -r PID PORT LINE
do
if ! checkpid $PID
then
[ -z "$*" ] && continue
for p in "$@"; do [ "$p" = "$PORT" ] && continue 2; done
fi
# keep all other shell entries (dead or running)
echo "$PID $PORT $LINE" >> $temp
_PID[$PORT]=$PID
_LINE[$PORT]="$LINE"
done < $shells
fi
# add entries for shells we start
while read -r PORT USER DIR COMMAND
do
# ignore empty lines and comments
[ "${PORT%#*}" ] && STATUS=STOPPED || STATUS=DISABLED
PORT="${PORT#\#}"
test "$PORT" -ge 0 2>/dev/null || continue
# skip if line does not match given port number
if [ "$*" ]
then
for p in "$@" end; do [ "$p" = "$PORT" ] && break; done
[ $p = end ] && continue
fi
if [ $STATUS = DISABLED ]
then
echo "Shell $PORT has been disabled in the configuration" >&2
continue
fi
DIR=${DIR//_IOCNAME_/$HOSTNAME}
ARGS=${ARGS//_IOCNAME_/$HOSTNAME}
# check if this shell had already been started
if [ "${_PID[$PORT]}" ]
then
# warn if trying to start already running shell
if [ -z "$reload" ]
then
if [ "$USER $DIR $COMMAND" != "${_LINE[$PORT]}" ]
then
echo "Running but modified: ${_LINE[$PORT]}" >&2
echo "New configuration : $USER $DIR $COMMAND" >&2
echo "You may want to restart $PORT" >&2
mod=1
else
echo "Already running: $PORT ${_LINE[$PORT]}" >&2
fi
fi
# skip already running shells
continue
fi
if [ -n "$logdir" ]
then
LOG=$logdir/$PORT
rm -f $LOG
else
LOG=/dev/null
fi
# start shell
echo "Starting: $PORT $USER $DIR $COMMAND"
if [ "$UID" -eq 0 ]
then
# sudo may be installed in different locations
# and may delete important environment variables
SUDO=$(which sudo) && SUDO+=" -H -u $USER SHELLBOX=$HOSTNAME:$PORT EPICS_HOST_ARCH=$EPICS_HOST_ARCH PATH=$PATH"
fi
pidfile=/var/run/procServ/$PORT.pid
rm -f $pidfile
logpipe=/tmp/procServ-$PORT.log
mknod -m 666 $logpipe p 2>/dev/null
cat $logpipe | logger -p local0.info -t shellbox[$PORT] 2>/dev/null &
$exe -p $pidfile $options $DIR -L $logpipe $PORT $SUDO $COMMAND >> $LOG 2>&1 < /dev/null
# check if starting worked or failed
usleep 100000
if [ -e $pidfile ]
then
PID=$(<$pidfile)
_PID[$PORT]=$PID
echo "$PID $PORT $USER $DIR $COMMAND" >> $temp
else
_PID[$PORT]=fail
echo_failure
echo
cat $LOG
fi
done < $conf
mv $temp $shells
chmod 0444 $shells
for p in "$@"
do
if [ -z ${_PID[$p]]} ]
then
echo "No configuration for $p found" >&2
fi
done
[ "$mod" ] && fail "To apply all modifcations use reload"
}
start () {
[ -r $conf ] || fail "$conf not readable"
exe=$(which procServ) || fail "procServ not found"
[ -x $exe ] || fail "$exe is not executable"
mkdir -pm 755 /var/lock/subsys
touch /var/lock/subsys/$prog
launch $*
}
stopshell() {
PID=$1
PORT=$2
shift
echo -n "Stopping: $*"
kill $PID 2> /dev/null || echo_failure
echo
if [ $logdir ]
then
echo -e "\n**** stopped ****" >> $logdir/$PORT
fi
}
stop () {
# anything to stop?
if [ ! -f $shells ]
then
echo "$prog: No shells started."
exit 0
fi
if [ -z "$1" ]
then
# kill all shellboxes
while read -r PID PORT ARGS
do
stopshell $PID $PORT $ARGS
done < $shells
rm -f $shells
rm -f /var/lock/subsys/$prog
else
# kill only selected shellboxes
temp=$(mktemp -p $(dirname $shells)) || fail "can't create temporary file"
while read -r PID PORT ARGS
do
echo "$*" | grep -qE "(^|[[:space:]])$PORT([[:space:]]|$)" && \
stopshell $PID $PORT $ARGS || \
echo "$PID $PORT $ARGS" >> $temp
done < $shells
mv $temp $shells
chmod 0444 $shells
fi
}
reload () {
echo "Reloading $conf... "
[ -f $conf ] || fail "not readable"
# anything to stop?
if [ -f $shells ]
then
# first kill all shells that are modified or not configured any more
temp=$(mktemp -p $(dirname $shells)) || fail "can't create temporary file"
while read -r PID LINE
do
while read -r PORT USER DIR COMMAND ARGS
do
DIR=${DIR//_IOCNAME_/$HOSTNAME}
ARGS=${ARGS//_IOCNAME_/$HOSTNAME}
if [ "$PORT $USER $DIR $COMMAND $ARGS" = "$LINE" ]
then
echo "Keeping: $LINE"
echo "$PID $LINE" >> $temp
continue 2
fi
done < $conf
stopshell $PID $PORT $LINE
done < $shells
mv $temp $shells
chmod 0444 $shells
fi
# now start all new or modified shells
sleep 2
launch -reload
}
status () {
while [ "$1" ]
do
case "$1" in
-log | --log) log=1; shift ;;
--json5) json5=1; shift ;;
--) shift; break;;
-* ) echo "unknown option $1 ignored" >&2; shift ;;
*) break
esac
done
# First read all configured shells
if [ -f $conf ]
then
while read -r PORT USER DIR CMD
do
# Assume stopped until proven otherwise
[ "${PORT%#*}" ] && STATUS=STOPPED || STATUS=DISABLED
# check for empty lines, comments, rubbish
PORT="${PORT#\#}"
test "$PORT" -ge 0 2>/dev/null || continue
_STATUS[$PORT]=$STATUS
_USER[$PORT]=$USER
_DIR[$PORT]=${DIR//_IOCNAME_/$HOSTNAME}
_CMD[$PORT]=${CMD//_IOCNAME_/$HOSTNAME}
_CFG[$PORT]="${_USER[$PORT]} ${_DIR[$PORT]} ${_CMD[$PORT]}"
done < $conf
fi
# Now check all started shells
if [ -f $shells ]
then
while read -r PID PORT USER DIR CMD
do
CFG="$USER $DIR $CMD"
_PID[$PORT]=$PID
_USER[$PORT]=$USER
_DIR[$PORT]=$DIR
_CMD[$PORT]=$CMD
if checkpid $PID
then
if [ "${_STATUS[$PORT]}" = DISABLED ]
then
_STATUS[$PORT]=OBSOLETE
elif [ -z "${_CFG[$PORT]}" ]
then
_STATUS[$PORT]=OBSOLETE
elif [ "${_CFG[$PORT]}" != "$CFG" ]
then
_STATUS[$PORT]=MODIFIED
else
_STATUS[$PORT]=RUNNING
fi
else
_STATUS[$PORT]=DEAD
_PID[$PORT]=
fi
done < $shells
fi
if [ "$json5" ]
then
echo '{ shells: ['
for PORT in ${!_STATUS[*]}
do
echo ' {'
echo ' port: '$PORT','
[ "${_PID[$PORT]}" ] && echo ' pid: '${_PID[$PORT]}','
echo ' status: "'${_STATUS[$PORT]}'",'
echo ' user: "'${_USER[$PORT]}'",'
dir=${_DIR[$PORT]//\\/\\\\}
echo ' dir: "'${dir//\"/\\\"}'",'
cmd=${_CMD[$PORT]//\\/\\\\}
echo ' cmd: "'${cmd//\"/\\\"}'"'
echo ' },'
done
echo ']}'
exit
fi
USERLEN=0
for v in "${_USER[@]}"
do
[ ${#v} -gt $USERLEN ] && USERLEN=${#v}
done
DIRLEN=0
for v in "${_DIR[@]}"
do
[ ${#v} -gt $DIRLEN ] && DIRLEN=${#v}
done
CMDLEN=0
for v in "${_CMD[@]}"
do
[ ${#v} -gt $CMDLEN ] && CMDLEN=${#v}
done
printf "${COLOR[HEADER]}#%-5s %-8s %-5s %-*s %-*s %-*s ${COLOR[NORMAL]}\n" pid status port $USERLEN user $DIRLEN dir $CMDLEN command
for PORT in ${!_STATUS[*]}
do
# check if we have to report all shells
[ "$*" ] && echo "$*" | grep -qvE "(^|[[:space:]])$PORT([[:space:]]|$)" && continue
printf "${COLOR[${_STATUS[$PORT]}]}%-6s %-8s %5d %-*s %-*s %-*s ${COLOR[NORMAL]}\n" "${_PID[$PORT]}" ${_STATUS[$PORT]} $PORT $USERLEN ${_USER[$PORT]} $DIRLEN ${_DIR[$PORT]} $CMDLEN "${_CMD[$PORT]}"
if [ "$logdir" -a "$log" ]
then
grep '\*\*\*\*' $logdir/$PORT 2>/dev/null
fi
done
}
CMD=$1
shift
case "$CMD" in
(start) start $*;;
(stop) stop $*;;
(restart) stop $*; sleep 2; start $*;; # kill all shells, then start again
(reread|reload) reload $*;; # reload shellbox.conf without killing too much
(status) status $*;;
(*) echo "Usage: $0 {start [ports]|stop [ports]|restart [ports]|reload|status [-log] [ports]}" ;;
esac