#!/bin/sh # ############################## # ctdb: Starts the clustered tdb daemon # # chkconfig: - 90 01 # # description: Starts and stops the clustered tdb daemon # pidfile: /var/run/ctdb/ctdbd.pid # ### BEGIN INIT INFO # Provides: ctdb # Required-Start: $network # Required-Stop: $network # Default-Stop: # Default-Start: 3 5 # Short-Description: start and stop ctdb service # Description: initscript for the ctdb service ### END INIT INFO # Source function library. if [ -f /etc/init.d/functions ] ; then . /etc/init.d/functions elif [ -f /etc/rc.d/init.d/functions ] ; then . /etc/rc.d/init.d/functions fi [ -f /etc/rc.status ] && { . /etc/rc.status rc_reset LC_ALL=en_US.UTF-8 } if [ -f /lib/lsb/init-functions ] ; then . /lib/lsb/init-functions fi # Avoid using root's TMPDIR unset TMPDIR [ -z "$CTDB_BASE" ] && { export CTDB_BASE="/etc/ctdb" } . $CTDB_BASE/functions loadconfig network loadconfig ctdb # check networking is up (for redhat) [ "$NETWORKING" = "no" ] && exit 0 detect_init_style export CTDB_INIT_STYLE ctdbd=${CTDBD:-/usr/sbin/ctdbd} pidfile="/var/run/ctdb/ctdbd.pid" if [ "$CTDB_VALGRIND" = "yes" ]; then init_style="valgrind" else init_style="$CTDB_INIT_STYLE" fi build_ctdb_options () { maybe_set () { # If the 2nd arg is null then return - don't set anything. # Else if the 3rd arg is set and it doesn't match the 2nd arg # then return [ -z "$2" -o \( -n "$3" -a "$3" != "$2" \) ] && return val="'$2'" case "$1" in --*) sep="=" ;; -*) sep=" " ;; esac # For these options we're only passing a value-less flag. [ -n "$3" ] && { val="" sep="" } CTDB_OPTIONS="${CTDB_OPTIONS}${CTDB_OPTIONS:+ }${1}${sep}${val}" } [ -z "$CTDB_RECOVERY_LOCK" ] && { echo "No recovery lock specified. Starting CTDB without split brain prevention" } maybe_set "--reclock" "$CTDB_RECOVERY_LOCK" mkdir -p $(dirname "$pidfile") maybe_set "--pidfile" "$pidfile" # build up CTDB_OPTIONS variable from optional parameters maybe_set "--logfile" "$CTDB_LOGFILE" maybe_set "--nlist" "$CTDB_NODES" maybe_set "--socket" "$CTDB_SOCKET" maybe_set "--public-addresses" "$CTDB_PUBLIC_ADDRESSES" maybe_set "--public-interface" "$CTDB_PUBLIC_INTERFACE" maybe_set "--dbdir" "$CTDB_DBDIR" maybe_set "--dbdir-persistent" "$CTDB_DBDIR_PERSISTENT" maybe_set "--event-script-dir" "$CTDB_EVENT_SCRIPT_DIR" maybe_set "--transport" "$CTDB_TRANSPORT" maybe_set "-d" "$CTDB_DEBUGLEVEL" maybe_set "--notification-script" "$CTDB_NOTIFY_SCRIPT" maybe_set "--start-as-disabled" "$CTDB_START_AS_DISABLED" "yes" maybe_set "--start-as-stopped " "$CTDB_START_AS_STOPPED" "yes" maybe_set "--no-recmaster" "$CTDB_CAPABILITY_RECMASTER" "no" maybe_set "--no-lmaster" "$CTDB_CAPABILITY_LMASTER" "no" maybe_set "--lvs --single-public-ip" "$CTDB_LVS_PUBLIC_IP" maybe_set "--script-log-level" "$CTDB_SCRIPT_LOG_LEVEL" maybe_set "--log-ringbuf-size" "$CTDB_LOG_RINGBUF_SIZE" maybe_set "--syslog" "$CTDB_SYSLOG" "yes" maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS" } export_debug_variables () { export CTDB_DEBUG_HUNG_SCRIPT CTDB_EXTERNAL_TRACE } # Log given message or stdin to either syslog or a CTDB log file do_log () { script_log "ctdb.init" "$@" } select_tdb_checker () { # Find the best TDB consistency check available. use_tdb_tool_check=false if [ -x /usr/bin/tdbtool ] && \ echo "help" | /usr/bin/tdbtool | grep -q check ; then use_tdb_tool_check=true elif [ -x /usr/bin/tdbtool -a -x /usr/bin/tdbdump ] ; then do_log </dev/null | grep -q "Database integrity is OK" ; then return 0 else return 1 fi else tdbdump "$_db" >/dev/null 2>/dev/null return $? fi } check_persistent_databases () { _dir="${CTDB_DBDIR_PERSISTENT:-${CTDB_DBDIR:-/var/ctdb}/persistent}" mkdir -p "$_dir" 2>/dev/null [ "${CTDB_MAX_PERSISTENT_CHECK_ERRORS:-0}" = "0" ] || return 0 for _db in $(ls "$_dir/"*.tdb.*[0-9] 2>/dev/null) ; do check_tdb $_db || { do_log "Persistent database $_db is corrupted! CTDB will not start." return 1 } done } check_non_persistent_databases () { _dir="${CTDB_DBDIR:-/var/ctdb}" mkdir -p "$_dir" 2>/dev/null for _db in $(ls "${_dir}/"*.tdb.*[0-9] 2>/dev/null) ; do check_tdb $_db || { _backup="${_db}.$(date +'%Y%m%d.%H%M%S.%N').corrupt" do_log </dev/null 2>&1 ; do if [ $_count -ge $_timeout ] ; then return 1 fi sleep 1 _count=$(($_count + 1)) done } start() { echo -n $"Starting ctdbd service: " ctdb ping >/dev/null 2>&1 && { echo $"CTDB is already running" return 0 } # About to start new $ctdbd. The ping above has failed and any # new $ctdbd will destroy the Unix domain socket, so any processes # that aren't yet completely useless soon will be... so kill # them. pkill -9 -f "$ctdbd" build_ctdb_options export_debug_variables # make sure we drop any ips that might still be held if previous # instance of ctdb got killed with -9 or similar drop_all_public_ips "ctdb.init" if select_tdb_checker ; then check_persistent_databases || return $? check_non_persistent_databases fi if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then ulimit -c 0 else ulimit -c unlimited fi case $init_style in valgrind) eval valgrind -q --log-file=/var/log/ctdb_valgrind \ $ctdbd --valgrinding "$CTDB_OPTIONS" RETVAL=$? echo ;; suse) eval startproc $ctdbd "$CTDB_OPTIONS" RETVAL=$? ;; redhat) eval $ctdbd "$CTDB_OPTIONS" RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ctdb || RETVAL=1 ;; debian) eval start-stop-daemon --start --quiet --background \ --exec $ctdbd -- "$CTDB_OPTIONS" RETVAL=$? ;; esac if [ $RETVAL -eq 0 ] ; then if ! wait_until_ready ; then RETVAL=1 pkill -9 -f $ctdbd >/dev/null 2>&1 fi fi case $init_style in suse) set_retval $RETVAL rc_status -v ;; redhat) [ $RETVAL -eq 0 ] && success || failure echo ;; esac return $RETVAL } stop() { echo -n $"Shutting down ctdbd service: " pkill -0 -f $ctdbd || { echo -n " Warning: ctdbd not running ! " case $init_style in suse) rc_status -v ;; redhat) echo "" ;; esac return 0 } ctdb shutdown >/dev/null 2>&1 RETVAL=$? count=0 while pkill -0 -f $ctdbd ; do sleep 1 count=$(($count + 1)) [ $count -gt 30 ] && { echo -n $"killing ctdbd " pkill -9 -f $ctdbd pkill -9 -f $CTDB_BASE/events.d/ } done # make sure all ips are dropped, pfkill -9 might leave them hanging around drop_all_public_ips rm -f "$pidfile" case $init_style in suse) # re-set the return code to the recorded RETVAL in order # to print the correct status message set_retval $RETVAL rc_status -v ;; redhat) [ $RETVAL -eq 0 ] && success || failure [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb echo "" ;; esac return $RETVAL } restart() { stop start } # Given that CTDB_VALGRIND is a debug option we don't support the pid # file. We just do a quick and dirty hack instead. Otherwise we just # end up re-implementing each distro's pidfile support... check_status_valgrind () { if pkill -0 -f "valgrind.*${ctdbd}" ; then echo "ctdbd is running under valgrind..." return 0 else echo "ctdbd is not running" return 1 fi } check_status () { # Backward compatibility. When we arrange to pass --pidfile to # ctdbd we also create the directory that will contain it. If # that directory is missing then we don't use the pidfile to check # status. if [ -d $(dirname "$pidfile") ] ; then _pf_opt="-p $pidfile" else _pf_opt="" fi case "$init_style" in valgrind) check_status_valgrind ;; suse) checkproc $_pf_opt "$ctdbd" rc_status -v ;; redhat) status $_pf_opt -l "ctdb" "$ctdbd" ;; debian) status_of_proc $_pf_opt "$ctdbd" "ctdb" ;; esac } [ -x "$CTDB_BASE/rc.ctdb" ] && "$CTDB_BASE/rc.ctdb" $1 case "$1" in start) start ;; stop) stop ;; restart|reload|force-reload) restart ;; status) check_status ;; condrestart|try-restart) if check_status >/dev/null ; then restart fi ;; cron) # used from cron to auto-restart ctdb check_status >/dev/null || restart ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}" exit 1 esac exit $?