mirror of https://github.com/sipwise/heartbeat.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
498 lines
12 KiB
498 lines
12 KiB
#!/bin/sh
|
|
#
|
|
# Startup/shutdown script for services managed by xinetd.
|
|
#
|
|
# Copyright (C) 2003 Charlie Brooks
|
|
#
|
|
# WARNING: Tested ONLY on Red Hat 7.3 and Fedora Core 2/4 at this time.
|
|
#
|
|
# Author: Charlie Brooks <ha@HBCS.Org>
|
|
# Description: given parameters of a service name and start|stop|status,
|
|
# will enable, disable or report on a specified xinetd service
|
|
# Config: all services must have a descriptor file in /etc/xinetd.d
|
|
# Support: linux-ha@lists.linux-ha.org
|
|
# License: GNU General Public License (GPL)
|
|
#
|
|
# OCF parameters are as below:
|
|
# OCF_RESKEY_service
|
|
|
|
#######################################################################
|
|
# Initialization:
|
|
|
|
. ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs
|
|
|
|
#######################################################################
|
|
|
|
meta_data() {
|
|
cat <<END
|
|
<?xml version="1.0"?>
|
|
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
|
<resource-agent name="Xinetd">
|
|
<version>1.0</version>
|
|
|
|
<longdesc lang="en">
|
|
Resource script for Xinetd. It starts/stops services managed
|
|
by xinetd.
|
|
|
|
Note that the xinetd daemon itself must be running: we are not
|
|
going to start it or stop it ourselves.
|
|
|
|
Important: in case the services managed by the cluster are the
|
|
only ones enabled, you should specify the -stayalive option for
|
|
xinetd or it will exit on Heartbeat stop. Alternatively, you may
|
|
enable some internal service such as echo.
|
|
</longdesc>
|
|
<shortdesc lang="en">Xinetd resource agent</shortdesc>
|
|
|
|
<parameters>
|
|
<parameter name="service" unique="0" required="1">
|
|
<longdesc lang="en">
|
|
The service name managed by xinetd.
|
|
</longdesc>
|
|
<shortdesc lang="en">service name</shortdesc>
|
|
<content type="string" default="" />
|
|
</parameter>
|
|
</parameters>
|
|
|
|
<actions>
|
|
<action name="start" timeout="20" />
|
|
<action name="stop" timeout="20" />
|
|
<action name="restart" timeout="40" />
|
|
<action name="status" depth="0" timeout="10" interval="10" start-delay="10" />
|
|
<action name="monitor" depth="0" timeout="10" interval="10" start-delay="10" />
|
|
<action name="validate-all" timeout="5" />
|
|
<action name="meta-data" timeout="5" />
|
|
</actions>
|
|
</resource-agent>
|
|
END
|
|
}
|
|
|
|
# don't rely on the pid file, but lookup xinetd in the list of
|
|
# processes
|
|
|
|
hup_inetd () {
|
|
pid=`ps -e -o pid,command | grep '/[x]inetd' | awk '{print $1}'`
|
|
if [ "$pid" ]; then
|
|
if kill -HUP $pid; then
|
|
:
|
|
else
|
|
ocf_log err "Could not SigHUP xinetd superdaemon!"
|
|
ocf_log err "perhaps we are booting after a system crash"
|
|
exit $OCF_ERR_GENERIC
|
|
fi
|
|
else
|
|
ocf_log err "xinetd superdaemon process not found!"
|
|
ocf_log err "perhaps we are currently booting the system."
|
|
exit $OCF_ERR_GENERIC
|
|
fi
|
|
}
|
|
|
|
xup_start () {
|
|
if [ "running" = "`xup_status`" ]; then
|
|
ocf_log info "Service $service already started"
|
|
exit $OCF_SUCCESS
|
|
fi
|
|
|
|
ocf_log "info" "$0: enabling in $RCFILE"
|
|
if $AWK '!/disable/' $RCFILE > $RCFILE.xup
|
|
then
|
|
if mv $RCFILE.xup $RCFILE
|
|
then
|
|
ocf_log "info" "$0: Starting"
|
|
hup_inetd
|
|
touch $PIDFILE
|
|
else
|
|
ocf_log "err" "Could not replace $RCFILE"
|
|
fi
|
|
else
|
|
ocf_log "err" "Could not rewrite $RCFILE!"
|
|
fi
|
|
}
|
|
|
|
xup_stop () {
|
|
if [ "stopped" = "`xup_status`" ]; then
|
|
ocf_log info "Service $service already stopped"
|
|
exit $OCF_SUCCESS
|
|
fi
|
|
|
|
ocf_log "info" "$0: disabling in $RCFILE"
|
|
if $AWK '!/disable/;/{/{printf "\tdisable\t\t\t= yes\n"}' $RCFILE >$RCFILE.xup
|
|
then
|
|
if mv $RCFILE.xup $RCFILE
|
|
then
|
|
ocf_log "info" "$0: Shutting down"
|
|
hup_inetd
|
|
rm -f $PIDFILE
|
|
else
|
|
ocf_log "err" "Could not replace $RCFILE"
|
|
fi
|
|
else
|
|
ocf_log "err" "Could not rewrite $RCFILE!"
|
|
fi
|
|
}
|
|
|
|
xup_usage () {
|
|
echo "Usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}"
|
|
return 0
|
|
}
|
|
|
|
xup_status () {
|
|
if [ -f $PIDFILE ]; then
|
|
echo running
|
|
return $OCF_SUCCESS
|
|
else
|
|
echo stopped
|
|
return $OCF_NOT_RUNNING
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Check if the arg is a valid integer
|
|
#
|
|
CheckInteger() {
|
|
# Examples of valid integer: "1080", "1", "0080", "0", "0000"
|
|
# Examples of invalid integer: "1080bad", ""
|
|
case "$1" in
|
|
"") #empty string
|
|
false;;
|
|
*[^0-9]*) #got invalid char
|
|
false;;
|
|
*) #no invalid char, and has at least one digit, so is a good integer
|
|
true;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Check if the arg is a valid umask
|
|
#
|
|
CheckUmask() {
|
|
# Examples of valid umask: "100", "1", "000", "0"
|
|
# Examples of invalid umask: "108", "bad", "1111" ""
|
|
case "$1" in
|
|
[0-7])
|
|
true;;
|
|
[0-7][0-7])
|
|
true;;
|
|
[0-7][0-7][0-7])
|
|
true;;
|
|
*)
|
|
false;;
|
|
esac
|
|
}
|
|
|
|
# Check (part of) the attributes based on xinetd.conf(5) and xinetd source code
|
|
# confparse.c
|
|
# parsers.c
|
|
# attr.h
|
|
check_attributes () {
|
|
# Empty these attributes before validating them
|
|
unset socket_type wait server user protocol port group instances \
|
|
type flags disable nice umask
|
|
VAR=""
|
|
for SECTION in $*; do
|
|
case $SECTION in
|
|
*=*) # Check to see if we need to export the previous name=value
|
|
# pair.
|
|
if [ -n "$VAR" ]; then
|
|
export "$VAR"
|
|
fi
|
|
# Save the "new" name=value pair in VAR
|
|
VAR=$SECTION
|
|
;;
|
|
*) # This section does not have an equal sign, therefore it is part of
|
|
# the *previous* name=value pair, thus we will append it to the
|
|
# previous name=value assignment.
|
|
VAR="$VAR $SECTION"
|
|
;;
|
|
esac
|
|
# A final cleanup step.
|
|
# Do we need to export VAR ?
|
|
if [ -n "$VAR" ]; then
|
|
export "$VAR"
|
|
fi
|
|
done
|
|
if [ $? -ne 0 ]; then
|
|
return $OCF_ERR_GENERIC
|
|
fi
|
|
|
|
case $disable in
|
|
"") disable=no # Default to no.
|
|
;;
|
|
yes|no) ;;
|
|
*) ocf_log err "Invalid value for disable [$disable] in $RCFILE, yes|no please"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
case $socket_type in
|
|
"") socket_type=dgram
|
|
# Default value for socket_type is dgram.
|
|
;;
|
|
stream|dgram|raw|seqpacket)
|
|
;;
|
|
*) ocf_log err "Invalid socket type $socket_type in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
case $wait in # Wait has no default value.
|
|
yes|no) ;;
|
|
*) ocf_log err "Invalid waid [$wait] in $RCFILE, yes|no please"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
case $type in
|
|
# Default value for type is RPC or INTERNAL, determined at compile time.
|
|
# It may be a list in $RCFILE, however we only capture the first one.
|
|
""|RPC|INTERNAL|UNLISTED|SPECIAL|TCPMUX|TCPMUXPLUS)
|
|
;;
|
|
*) ocf_log err "Invalid service type [$type] in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
if [ ! -z "$type" -a "INTERNAL" != "$type" ]; then
|
|
# Type is explicitly set to EXTERNAL, hence server and user are necessary.
|
|
case $server in
|
|
"") ocf_log err "Please specify server in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
/*) if [ -x $server ]; then
|
|
: OK
|
|
else
|
|
ocf_log err "Server $server is not executable"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
*) ocf_log err "Server $server is not of obsolute path"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
case $user in
|
|
"") ocf_log err "Please specify user in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
*) getent passwd $user >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
ocf_log err "User $user does not exist!"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Protocol is necessary when type is MUX
|
|
if [ $type = "TCPMUX" -o $type ="TCPMUXPLUS" ]; then
|
|
case $protocol in
|
|
"") ocf_log err "Please specify protocol in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
*) get protocols $protocol >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
ocf_log err "Invalid protocol [$protocol] in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
|
|
case $group in
|
|
"") ;; # OK to be empty, the group for $user is used
|
|
*) getent group $group >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
ocf_log err "Group $group does not exist!"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
case $flags in
|
|
# Default value for flags is REUSE.
|
|
# It may be a list in $RCFILE, however we only capture the first one.
|
|
"") flags=RESUME
|
|
;;
|
|
REUSE|INTERCEPT|NORETRY|IDONLY|NAMEINARGS|NODELAY|KEEPALIVE|NOLIBWRAP|SENSOR|IPv4|IPv6) ;;
|
|
*) ocf_log err "Invalid flags [$flags] in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
|
|
case $instances in
|
|
""|[Uu][Nn][Ll][Ii][Mm][Ii][Ti][Ee][Dd]) ;;
|
|
*) if CheckInteger $instances; then
|
|
: OK
|
|
else
|
|
ocf_log err "Invalid instances [$instances] in $RCFILE, non-negative integer expected"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
case $nice in
|
|
"") ;;
|
|
*) local foo=`echo $nice | sed s/^-//`
|
|
if CheckInteger $foo; then
|
|
: OK
|
|
else
|
|
ocf_log err "Invalid nice [$nice] in $RCFILE, integer expected"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [ ! -z $umask ]; then
|
|
if CheckUmask $umask; then
|
|
: OK
|
|
else
|
|
ocf_log err "Invalid umask [$umask] in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
fi
|
|
fi
|
|
}
|
|
|
|
xup_validate_all () {
|
|
check_binary $AWK
|
|
|
|
# Parse the $RCFILE for necessary attributes, assume $RCFILE does not
|
|
# contain "include" or "includedir" directives.
|
|
space="[ \t]*"
|
|
leading_space="^$space"
|
|
trailing_space="$space$"
|
|
comment="$space\#"
|
|
|
|
# Strip comments, delete blank lines.
|
|
stripped=`sed -e "/^$comment/d" -e "/=$trailing_space/d" -e "/$leading_space$/d" $RCFILE`
|
|
|
|
stripped=`echo $stripped`
|
|
# At this stage, stripped="service <service-name> { attribute-list }".
|
|
case $stripped in
|
|
*#*)
|
|
ocf_log err "Descriptor file $RCFILE contains extra \"#\", which is forbidden"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
|
|
service*)
|
|
case $stripped in
|
|
*[^\ \ +-]=*)
|
|
ocf_log err "Attribute needs a space before operator ="
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
*[^\ \ ][+-]=*)
|
|
ocf_log err "Attribute needs a space before operator [+-]="
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
*) ;;
|
|
esac
|
|
|
|
# Strip leading "service" keyword, remove spaces surrounding "=".
|
|
stripped=`echo $stripped | sed -e "s/^service//" -e "s/-=/ /g" \
|
|
-e "s/+=/=/g" -e "s/$space=$space/=/g"`
|
|
# At this stage, stripped=" <service-name> { attribute-list }",
|
|
# note that the leading space before <service-name> is significant.
|
|
case $stripped in
|
|
" "*)
|
|
stripped=`echo $stripped | sed -e "s/$leading_space[^ \t]\+$space//"`
|
|
# At this stage, stripped="{ attribute-list }"
|
|
case $stripped in
|
|
{*})
|
|
stripped=`echo $stripped | sed -e "s/^{//" -e "s/}$//"`
|
|
# At this stage, stripped=<attribute-list>
|
|
# echo $stripped
|
|
check_attributes "$stripped"
|
|
;;
|
|
|
|
*)
|
|
ocf_log err "Attrbute list should be contained in {}"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
*)
|
|
ocf_log err "Service name should follow the service key word"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
*)
|
|
ocf_log err "Service key word is necessary in $RCFILE"
|
|
exit $OCF_ERR_CONFIGURED
|
|
;;
|
|
esac
|
|
}
|
|
if
|
|
( [ $# -ne 1 ] )
|
|
then
|
|
xup_usage
|
|
exit $OCF_ERR_ARGS
|
|
fi
|
|
|
|
# These operations do not require OCF instance parameters to be set
|
|
case "$1" in
|
|
meta-data)
|
|
meta_data
|
|
exit $OCF_SUCCESS
|
|
;;
|
|
usage)
|
|
xup_usage
|
|
exit $OCF_SUCCESS
|
|
;;
|
|
*) ;;
|
|
esac
|
|
|
|
if
|
|
[ -z "$OCF_RESKEY_service" ]
|
|
then
|
|
ocf_log err "Please set OCF_RESKEY_service to the service managed by Xinetd"
|
|
if [ "$1" = "start" ]; then
|
|
exit $OCF_ERR_ARGS
|
|
else
|
|
exit $OCF_NOT_RUNNING
|
|
fi
|
|
fi
|
|
|
|
service=$OCF_RESKEY_service
|
|
RCFILE=/etc/xinetd.d/$service
|
|
PIDFILE=$HA_VARRUN/xup$service
|
|
|
|
# Make sure the OCF_RESKEY_service is a valid xinetd service name
|
|
if [ ! -f $RCFILE ]; then
|
|
ocf_log err "Service descriptor $RCFILE not found!"
|
|
if [ "$1" = "start" ]; then
|
|
exit $OCF_ERR_ARGS
|
|
else
|
|
exit $OCF_NOT_RUNNING
|
|
fi
|
|
fi
|
|
|
|
# See how we were called.
|
|
case "$1" in
|
|
start)
|
|
xup_start
|
|
;;
|
|
stop)
|
|
xup_stop
|
|
;;
|
|
restart)
|
|
$0 stop
|
|
$0 start
|
|
;;
|
|
status)
|
|
xup_status
|
|
;;
|
|
monitor)
|
|
xup_status > /dev/null
|
|
;;
|
|
validate-all)
|
|
xup_validate_all
|
|
;;
|
|
*)
|
|
xup_usage
|
|
exit $OCF_ERR_UNIMPLEMENTED
|
|
esac
|
|
|
|
exit $?
|