1 # Hey Emacs, this is a -*- shell-script -*- !!!
3 # utility functions for ctdb event scripts
5 CTDB_VARDIR="/usr/local/var/lib/ctdb"
7 # Only (and always) override these variables in test code
9 if [ -z "$CTDB_SCRIPT_VARDIR" ] ; then
10 CTDB_SCRIPT_VARDIR="/usr/local/var/lib/ctdb/state"
13 if [ -z "$CTDB_ETCDIR" ] ; then
17 #######################################
18 # pull in a system config file, if any
22 foo="${service_config:-${service_name}}"
23 if [ -n "$foo" ] ; then
29 if [ "$1" != "ctdb" ] ; then
37 if [ -f $CTDB_ETCDIR/sysconfig/$1 ]; then
38 . $CTDB_ETCDIR/sysconfig/$1
39 elif [ -f $CTDB_ETCDIR/default/$1 ]; then
40 . $CTDB_ETCDIR/default/$1
41 elif [ -f $CTDB_BASE/sysconfig/$1 ]; then
42 . $CTDB_BASE/sysconfig/$1
45 if [ "$1" = "ctdb" ] ; then
46 _config="${CTDB_BASE}/ctdbd.conf"
47 if [ -r "$_config" ] ; then
57 ##############################################################
59 # CTDB_SCRIPT_DEBUGLEVEL can be overwritten by setting it in a
63 if [ ${CTDB_SCRIPT_DEBUGLEVEL:-2} -ge 4 ] ; then
64 # If there are arguments then echo them. Otherwise expect to
65 # use stdin, which allows us to pass lots of debug using a
88 # Log given message or stdin to either syslog or a CTDB log file
89 # $1 is the tag passed to logger if syslog is in use.
94 case "$CTDB_LOGGING" in
96 if [ -n "$CTDB_LOGGING" ] ; then
97 _file="${CTDB_LOGGING#file:}"
99 _file="/var/log/log.ctdb"
102 if [ -n "$*" ] ; then
110 # Handle all syslog:* variants here too. There's no tool to do
111 # the lossy things, so just use logger.
112 logger -t "ctdbd: ${_tag}" $*
117 # When things are run in the background in an eventscript then logging
118 # output might get lost. This is the "solution". :-)
119 background_with_logging ()
122 "$@" 2>&1 </dev/null |
123 script_log "${script_name}&"
129 ##############################################################
130 # check number of args for different events
136 echo "ERROR: must supply interface, IP and maskbits"
142 echo "ERROR: must supply old interface, new interface, IP and maskbits"
149 ##############################################################
150 # determine on what type of system (init style) we are running
153 # only do detection if not already set:
154 [ -z "$CTDB_INIT_STYLE" ] || return
156 if [ -x /sbin/startproc ]; then
157 CTDB_INIT_STYLE="suse"
158 elif [ -x /sbin/start-stop-daemon ]; then
159 CTDB_INIT_STYLE="debian"
161 CTDB_INIT_STYLE="redhat"
165 ######################################################
166 # simulate /sbin/service on platforms that don't have it
167 # _service() makes it easier to hook the service() function for
174 # do nothing, when no service was specified
175 [ -z "$_service_name" ] && return
177 if [ -x /sbin/service ]; then
178 $_nice /sbin/service "$_service_name" "$_op"
179 elif [ -x /usr/sbin/service ]; then
180 $_nice /usr/sbin/service "$_service_name" "$_op"
181 elif [ -x $CTDB_ETCDIR/init.d/$_service_name ]; then
182 $_nice $CTDB_ETCDIR/init.d/$_service_name "$_op"
183 elif [ -x $CTDB_ETCDIR/rc.d/init.d/$_service_name ]; then
184 $_nice $CTDB_ETCDIR/rc.d/init.d/$_service_name "$_op"
194 ######################################################
195 # simulate /sbin/service (niced) on platforms that don't have it
202 ######################################################
203 # Cached retrieval of PNN from local node. This never changes so why
204 # open a client connection to the server each time this is needed?
205 # This sets $pnn - this avoid an unnecessary subprocess.
208 _pnn_file="${CTDB_SCRIPT_VARDIR}/my-pnn"
209 if [ ! -f "$_pnn_file" ] ; then
210 ctdb pnn | sed -e 's@.*:@@' >"$_pnn_file"
213 read pnn <"$_pnn_file"
216 ######################################################
217 # wrapper around /proc/ settings to allow them to be hooked
219 # 1st arg is relative path under /proc/, 2nd arg is value to set
222 echo "$2" >"/proc/$1"
227 if [ -w "/proc/$1" ] ; then
232 ######################################################
233 # wrapper around getting file contents from /proc/ to allow
234 # this to be hooked for testing
235 # 1st arg is relative path under /proc/
241 ######################################################
242 # Print up to $_max kernel stack traces for processes named $_program
243 program_stack_traces ()
249 for _pid in $(pidof "$_prog") ; do
250 [ $_count -le $_max ] || break
252 # Do this first to avoid racing with process exit
253 _stack=$(get_proc "${_pid}/stack" 2>/dev/null)
254 if [ -n "$_stack" ] ; then
255 echo "Stack trace for ${_prog}[${_pid}]:"
257 _count=$(($_count + 1))
262 ######################################################
263 # Ensure $service_name is set
264 assert_service_name ()
266 [ -n "$service_name" ] || die "INTERNAL ERROR: \$service_name not set"
269 ######################################################
270 # check a set of directories is available
271 # return 1 on a missing directory
272 # directories are read from stdin
273 ######################################################
274 ctdb_check_directories_probe()
276 while IFS="" read d ; do
282 [ -d "${d}/." ] || return 1
287 ######################################################
288 # check a set of directories is available
289 # directories are read from stdin
290 ######################################################
291 ctdb_check_directories()
293 ctdb_check_directories_probe || {
294 echo "ERROR: $service_name directory \"$d\" not available"
299 ######################################################
300 # check a set of tcp ports
301 # usage: ctdb_check_tcp_ports <ports...>
302 ######################################################
304 # This flag file is created when a service is initially started. It
305 # is deleted the first time TCP port checks for that service succeed.
306 # Until then ctdb_check_tcp_ports() prints a more subtle "error"
307 # message if a port check fails.
308 _ctdb_check_tcp_common ()
311 _d="${CTDB_SCRIPT_VARDIR}/failcount"
312 _ctdb_service_started_file="${_d}/${service_name}.started"
315 ctdb_check_tcp_init ()
317 _ctdb_check_tcp_common
318 mkdir -p "${_ctdb_service_started_file%/*}" # dirname
319 touch "$_ctdb_service_started_file"
322 # Check whether something is listening on all of the given TCP ports
323 # using the "ctdb checktcpport" command.
324 ctdb_check_tcp_ports()
326 if [ -z "$1" ] ; then
327 echo "INTERNAL ERROR: ctdb_check_tcp_ports - no ports specified"
331 for _p ; do # process each function argument (port)
332 _cmd="ctdb checktcpport $_p"
337 _ctdb_check_tcp_common
338 if [ ! -f "$_ctdb_service_started_file" ] ; then
339 echo "ERROR: $service_name tcp port $_p is not responding"
340 debug "\"ctdb checktcpport $_p\" was able to bind to port"
342 echo "INFO: $service_name tcp port $_p is not responding"
348 # Couldn't bind, something already listening, next port...
352 echo "ERROR: unexpected error running \"ctdb checktcpport\""
354 ctdb checktcpport (exited with $_ret) with output:
361 # All ports listening
362 _ctdb_check_tcp_common
363 rm -f "$_ctdb_service_started_file"
367 ######################################################
368 # check a unix socket
369 # usage: ctdb_check_unix_socket SERVICE_NAME <socket_path>
370 ######################################################
371 ctdb_check_unix_socket() {
373 [ -z "$socket_path" ] && return
375 if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then
376 echo "ERROR: $service_name socket $socket_path not found"
381 ######################################################
382 # check a command returns zero status
383 # usage: ctdb_check_command <command>
384 ######################################################
385 ctdb_check_command ()
387 _out=$("$@" 2>&1) || {
388 echo "ERROR: $* returned error"
394 ################################################
395 # kill off any TCP connections with the given IP
396 ################################################
397 kill_tcp_connections ()
402 if [ "$2" = "oneway" ] ; then
406 get_tcp_connections_for_ip "$_ip" | {
411 while read _dst _src; do
412 _destport="${_dst##*:}"
415 # we only do one-way killtcp for CIFS
416 139|445) __oneway=true ;;
419 echo "Killing TCP connection $_src $_dst"
420 _connections="${_connections}${_nl}${_src} ${_dst}"
421 if ! $__oneway ; then
422 _connections="${_connections}${_nl}${_dst} ${_src}"
425 _killcount=$(($_killcount + 1))
428 if [ $_killcount -eq 0 ] ; then
432 echo "$_connections" | ctdb killtcp || {
433 echo "Failed to send killtcp control"
439 _remaining=$(get_tcp_connections_for_ip $_ip | wc -l)
441 if [ $_remaining -eq 0 ] ; then
442 echo "Killed $_killcount TCP connections to released IP $_ip"
446 _count=$(($_count + 1))
447 if [ $_count -gt 3 ] ; then
448 echo "Timed out killing tcp connections for IP $_ip ($_remaining remaining)"
452 echo "Waiting for $_remaining connections to be killed for IP $_ip"
458 ##################################################################
459 # kill off the local end for any TCP connections with the given IP
460 ##################################################################
461 kill_tcp_connections_local_only ()
463 kill_tcp_connections "$1" "oneway"
466 ##################################################################
467 # tickle any TCP connections with the given IP
468 ##################################################################
469 tickle_tcp_connections ()
473 get_tcp_connections_for_ip "$_ip" |
477 while read dest src; do
478 echo "Tickle TCP connection $src $dest"
479 ctdb tickle $src $dest >/dev/null 2>&1 || _failed=true
480 echo "Tickle TCP connection $dest $src"
481 ctdb tickle $dest $src >/dev/null 2>&1 || _failed=true
485 echo "Failed to send tickle control"
490 get_tcp_connections_for_ip ()
494 netstat -tn | awk -v ip=$_ip \
495 'index($1, "tcp") == 1 && \
496 (index($4, ip ":") == 1 || index($4, "::ffff:" ip ":") == 1) \
497 && $6 == "ESTABLISHED" \
501 ########################################################
509 # Ensure interface is up
510 ip link set "$_iface" up || \
511 die "Failed to bringup interface $_iface"
513 # Only need to define broadcast for IPv4
519 ip addr add "$_ip/$_maskbits" $_bcast dev "$_iface" || {
520 echo "Failed to add $_ip/$_maskbits on dev $_iface"
524 # Wait 5 seconds for IPv6 addresses to stop being tentative...
525 if [ -z "$_bcast" ] ; then
526 for _x in $(seq 1 10) ; do
527 ip addr show to "${_ip}/128" | grep -q "tentative" || break
531 # If the address was a duplicate then it won't be on the
532 # interface so flag an error.
533 _t=$(ip addr show to "${_ip}/128")
536 echo "Failed to add $_ip/$_maskbits on dev $_iface"
539 *tentative*|*dadfailed*)
540 echo "Failed to add $_ip/$_maskbits on dev $_iface"
541 ip addr del "$_ip/$_maskbits" dev "$_iface"
548 delete_ip_from_iface()
554 # This could be set globally for all interfaces but it is probably
555 # better to avoid surprises, so limit it the interfaces where CTDB
556 # has public IP addresses. There isn't anywhere else convenient
557 # to do this so just set it each time. This is much cheaper than
558 # remembering and re-adding secondaries.
559 set_proc "sys/net/ipv4/conf/${_iface}/promote_secondaries" 1
561 ip addr del "$_ip/$_maskbits" dev "$_iface" || {
562 echo "Failed to del $_ip on dev $_iface"
567 # If the given IP is hosted then print 2 items: maskbits and iface
573 *:*) _family="inet6" ; _bits=128 ;;
574 *) _family="inet" ; _bits=32 ;;
577 ip addr show to "${_addr}/${_bits}" 2>/dev/null | \
578 awk -v family="${_family}" \
579 'NR == 1 { iface = $2; sub(":$", "", iface) ; \
580 sub("@.*", "", iface) } \
581 $1 ~ /inet/ { mask = $2; sub(".*/", "", mask); \
582 print mask, iface, family }'
587 _addr="${1%/*}" # Remove optional maskbits
589 set -- $(ip_maskbits_iface $_addr)
590 if [ -n "$1" ] ; then
593 echo "Removing public address $_addr/$_maskbits from device $_iface"
594 delete_ip_from_iface $_iface $_addr $_maskbits >/dev/null 2>&1
598 drop_all_public_ips ()
600 while read _ip _x ; do
602 done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}"
607 set_proc_maybe sys/net/ipv4/route/flush 1
608 set_proc_maybe sys/net/ipv6/route/flush 1
611 ########################################################
613 _ctdb_counter_common () {
614 _service_name="${1:-${service_name:-${script_name}}}"
615 _counter_file="${CTDB_SCRIPT_VARDIR}/failcount/${_service_name}"
616 mkdir -p "${_counter_file%/*}" # dirname
618 ctdb_counter_init () {
619 _ctdb_counter_common "$1"
623 ctdb_counter_incr () {
624 _ctdb_counter_common "$1"
627 echo -n 1 >> "$_counter_file"
629 ctdb_counter_get () {
630 _ctdb_counter_common "$1"
632 stat -c "%s" "$_counter_file" 2>/dev/null || echo 0
634 ctdb_check_counter () {
635 _msg="${1:-error}" # "error" - anything else is silent on fail
636 _op="${2:--ge}" # an integer operator supported by test
637 _limit="${3:-${service_fail_limit}}"
640 _size=$(ctdb_counter_get "$1")
643 if [ "$_op" != "%" ] ; then
644 if [ $_size $_op $_limit ] ; then
648 if [ $(($_size $_op $_limit)) -eq 0 ] ; then
653 if [ "$_msg" = "error" ] ; then
654 echo "ERROR: $_size consecutive failures for $_service_name, marking node unhealthy"
662 ########################################################
664 ctdb_setup_service_state_dir ()
666 service_state_dir="${CTDB_SCRIPT_VARDIR}/service_state/${1:-${service_name}}"
667 mkdir -p "$service_state_dir" || {
668 echo "Error creating state dir \"$service_state_dir\""
673 ########################################################
674 # Managed status history, for auto-start/stop
676 _ctdb_managed_common ()
678 _ctdb_managed_file="${CTDB_SCRIPT_VARDIR}/managed_history/${service_name}"
681 ctdb_service_managed ()
684 mkdir -p "${_ctdb_managed_file%/*}" # dirname
685 touch "$_ctdb_managed_file"
688 ctdb_service_unmanaged ()
691 rm -f "$_ctdb_managed_file"
694 is_ctdb_previously_managed_service ()
697 [ -f "$_ctdb_managed_file" ]
700 ##################################################################
701 # Reconfigure a service on demand
703 _ctdb_service_reconfigure_common ()
705 _d="${CTDB_SCRIPT_VARDIR}/service_status/${service_name}"
707 _ctdb_service_reconfigure_flag="$_d/reconfigure"
710 ctdb_service_needs_reconfigure ()
712 _ctdb_service_reconfigure_common
713 [ -e "$_ctdb_service_reconfigure_flag" ]
716 ctdb_service_set_reconfigure ()
718 _ctdb_service_reconfigure_common
719 >"$_ctdb_service_reconfigure_flag"
722 ctdb_service_unset_reconfigure ()
724 _ctdb_service_reconfigure_common
725 rm -f "$_ctdb_service_reconfigure_flag"
728 ctdb_service_reconfigure ()
730 echo "Reconfiguring service \"${service_name}\"..."
731 ctdb_service_unset_reconfigure
732 service_reconfigure || return $?
736 # Default service_reconfigure() function does nothing.
737 service_reconfigure ()
742 ctdb_reconfigure_take_lock ()
744 _ctdb_service_reconfigure_common
745 _lock="${_d}/reconfigure_lock"
746 mkdir -p "${_lock%/*}" # dirname
751 # This is overkill but will work if we need to extend this to
752 # allow certain events to run multiple times in parallel
753 # (e.g. takeip) and write multiple PIDs to the file.
755 if [ -n "$_locker_event" ] ; then
757 if [ -n "$_pid" -a "$_pid" != $$ ] && \
758 kill -0 "$_pid" 2>/dev/null ; then
764 printf "%s\n%s\n" "$event_name" $$ >"$_lock"
769 ctdb_reconfigure_release_lock ()
771 _ctdb_service_reconfigure_common
772 _lock="${_d}/reconfigure_lock"
777 ctdb_replay_monitor_status ()
779 echo "Replaying previous status for this script due to reconfigure..."
780 # Leading separator ('|') is missing in some versions...
781 _out=$(ctdb scriptstatus -X | grep -E "^\|?monitor\|${script_name}\|")
782 # Output looks like this:
783 # |monitor|60.nfs|1|ERROR|1314764004.030861|1314764004.035514|foo bar|
784 # This is the cheapest way of getting fields in the middle.
785 set -- $(IFS="|" ; echo $_out)
788 # The error output field can include colons so we'll try to
789 # preserve them. The weak checking at the beginning tries to make
790 # this work for both broken (no leading '|') and fixed output.
792 _err_out="${_out#*monitor|${script_name}|*|*|*|*|}"
794 OK) : ;; # Do nothing special.
796 # Recast this as an error, since we can't exit with the
797 # correct negative number.
799 _err_out="[Replay of TIMEDOUT scriptstatus - note incorrect return code.] ${_err_out}"
802 # Recast this as an OK, since we can't exit with the
803 # correct negative number.
805 _err_out="[Replay of DISABLED scriptstatus - note incorrect return code.] ${_err_out}"
807 *) : ;; # Must be ERROR, do nothing special.
809 if [ -n "$_err_out" ] ; then
815 ctdb_service_check_reconfigure ()
819 # We only care about some events in this function. For others we
821 case "$event_name" in
822 monitor|ipreallocated|reconfigure) : ;;
826 if ctdb_reconfigure_take_lock ; then
827 # No events covered by this function are running, so proceed
829 case "$event_name" in
831 (ctdb_service_reconfigure)
835 if ctdb_service_needs_reconfigure ; then
836 ctdb_service_reconfigure
841 ctdb_reconfigure_release_lock
843 # Somebody else is running an event we don't want to collide
844 # with. We proceed with caution.
845 case "$event_name" in
847 # Tell whoever called us to retry.
851 # Defer any scheduled reconfigure and just run the
852 # rest of the ipreallocated event, as per the
853 # eventscript. There's an assumption here that the
854 # event doesn't depend on any scheduled reconfigure.
855 # This is true in the current code.
859 # There is most likely a reconfigure in progress so
860 # the service is possibly unstable. As above, we
861 # defer any scheduled reconfigured. We also replay
862 # the previous monitor status since that's the best
863 # information we have.
864 ctdb_replay_monitor_status
870 ##################################################################
871 # Does CTDB manage this service? - and associated auto-start/stop
873 ctdb_compat_managed_service ()
875 if [ "$1" = "yes" -a "$2" = "$service_name" ] ; then
876 CTDB_MANAGED_SERVICES="$CTDB_MANAGED_SERVICES $2"
880 is_ctdb_managed_service ()
884 # $t is used just for readability and to allow better accurate
885 # matching via leading/trailing spaces
886 t=" $CTDB_MANAGED_SERVICES "
888 # Return 0 if "<space>$service_name<space>" appears in $t
889 if [ "${t#* ${service_name} }" != "${t}" ] ; then
893 # If above didn't match then update $CTDB_MANAGED_SERVICES for
894 # backward compatibility and try again.
895 ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD" "vsftpd"
896 ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA" "samba"
897 ctdb_compat_managed_service "$CTDB_MANAGES_WINBIND" "winbind"
898 ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "apache2"
899 ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "httpd"
900 ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI" "iscsi"
901 ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD" "clamd"
902 ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs"
904 t=" $CTDB_MANAGED_SERVICES "
906 # Return 0 if "<space>$service_name<space>" appears in $t
907 [ "${t#* ${service_name} }" != "${t}" ]
910 ctdb_start_stop_service ()
914 # Allow service-start/service-stop pseudo-events to start/stop
915 # services when we're not auto-starting/stopping and we're not
917 case "$event_name" in
919 if is_ctdb_managed_service ; then
920 die 'service-start event not permitted when service is managed'
922 if [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] ; then
923 die 'service-start event not permitted with $CTDB_SERVICE_AUTOSTARTSTOP = yes'
929 if is_ctdb_managed_service ; then
930 die 'service-stop event not permitted when service is managed'
932 if [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] ; then
933 die 'service-stop event not permitted with $CTDB_SERVICE_AUTOSTARTSTOP = yes'
940 # Do nothing unless configured to...
941 [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] || return 0
943 [ "$event_name" = "monitor" ] || return 0
945 if is_ctdb_managed_service ; then
946 if ! is_ctdb_previously_managed_service ; then
947 echo "Starting service \"$service_name\" - now managed"
948 background_with_logging ctdb_service_start
952 if is_ctdb_previously_managed_service ; then
953 echo "Stopping service \"$service_name\" - no longer managed"
954 background_with_logging ctdb_service_stop
960 ctdb_service_start ()
962 # The service is marked managed if we've ever tried to start it.
965 service_start || return $?
973 ctdb_service_unmanaged
977 # Default service_start() and service_stop() functions.
979 # These may be overridden in an eventscript.
982 service "$service_name" start
987 service "$service_name" stop
990 ##################################################################
992 ctdb_standard_event_handler ()
1000 if [ "$_family" = "inet6" ] ; then
1001 _iptables_cmd="ip6tables"
1003 _iptables_cmd="iptables"
1006 # iptables doesn't like being re-entered, so flock-wrap it.
1007 flock -w 30 "${CTDB_VARDIR}/iptables-ctdb.flock" "$_iptables_cmd" "$@"
1010 # AIX (and perhaps others?) doesn't have mktemp
1011 if ! type mktemp >/dev/null 2>&1 ; then
1015 if [ "$1" = "-d" ] ; then
1019 _d="${TMPDIR:-/tmp}"
1020 _hex10=$(dd if=/dev/urandom count=20 2>/dev/null | \
1022 sed -e 's@\(..........\).*@\1@')
1023 _t="${_d}/tmp.${_hex10}"
1036 ########################################################
1038 ########################################################
1044 tickledir="${CTDB_SCRIPT_VARDIR}/tickles"
1045 mkdir -p "$tickledir"
1049 # What public IPs do I hold?
1050 _ips=$(ctdb -X ip | awk -F'|' -v pnn=$pnn '$3 == pnn {print $2}')
1052 # IPs as a regexp choice
1053 _ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))"
1055 # Record connections to our public IPs in a temporary file
1056 _my_connections="${tickledir}/${_port}.connections"
1057 rm -f "$_my_connections"
1059 awk -v destpat="^${_ipschoice}:${_port}\$" \
1060 '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' |
1061 sort >"$_my_connections"
1063 # Record our current tickles in a temporary file
1064 _my_tickles="${tickledir}/${_port}.tickles"
1065 rm -f "$_my_tickles"
1066 for _i in $_ips ; do
1067 ctdb -X gettickles $_i $_port |
1068 awk -F'|' 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }'
1070 sort >"$_my_tickles"
1072 # Add tickles for connections that we haven't already got tickles for
1073 comm -23 "$_my_connections" "$_my_tickles" |
1074 while read _src _dst ; do
1075 ctdb addtickle $_src $_dst
1078 # Remove tickles for connections that are no longer there
1079 comm -13 "$_my_connections" "$_my_tickles" |
1080 while read _src _dst ; do
1081 ctdb deltickle $_src $_dst
1084 rm -f "$_my_connections" "$_my_tickles"
1087 ########################################################
1088 # load a site local config file
1089 ########################################################
1091 [ -n "$CTDB_RC_LOCAL" -a -x "$CTDB_RC_LOCAL" ] && {
1095 [ -x $CTDB_BASE/rc.local ] && {
1096 . $CTDB_BASE/rc.local
1099 [ -d $CTDB_BASE/rc.local.d ] && {
1100 for i in $CTDB_BASE/rc.local.d/* ; do
1101 [ -x "$i" ] && . "$i"
1105 script_name="${0##*/}" # basename
1106 service_fail_limit=1