Merge remote branch 'martins/master'
[metze/ctdb/wip.git] / config / functions
1 # utility functions for ctdb event scripts
2
3 PATH=/bin:/usr/bin:/usr/sbin:/sbin:$PATH
4
5 #######################################
6 # pull in a system config file, if any
7 loadconfig() {
8
9     if [ -z "$1" ] ; then
10         foo="${service_config:-${service_name}}"
11         if [ -n "$foo" ] ; then
12             loadconfig "$foo"
13         fi
14     elif [ "$1" != "ctdb" ] ; then
15         loadconfig "ctdb"
16     fi
17
18
19     if [ -f /etc/sysconfig/$1 ]; then
20         . /etc/sysconfig/$1
21     elif [ -f /etc/default/$1 ]; then
22         . /etc/default/$1
23     elif [ -f $CTDB_BASE/sysconfig/$1 ]; then
24         . $CTDB_BASE/sysconfig/$1
25     fi
26 }
27
28 ##############################################################
29 # determine on what type of system (init style) we are running
30 detect_init_style() {
31     # only do detection if not already set:
32     test "x$CTDB_INIT_STYLE" != "x" && return
33
34     if [ -x /sbin/startproc ]; then
35         CTDB_INIT_STYLE="suse"
36     elif [ -x /sbin/start-stop-daemon ]; then
37         CTDB_INIT_STYLE="debian"
38     else
39         CTDB_INIT_STYLE="redhat"
40     fi
41 }
42
43 ######################################################
44 # simulate /sbin/service on platforms that don't have it
45 service() { 
46   _service_name="$1"
47   _op="$2"
48
49   # do nothing, when no service was specified
50   [ -z "$_service_name" ] && return
51
52   if [ -x /sbin/service ]; then
53       /sbin/service "$_service_name" "$_op"
54   elif [ -x /etc/init.d/$_service_name ]; then
55       /etc/init.d/$_service_name "$_op"
56   elif [ -x /etc/rc.d/init.d/$_service_name ]; then
57       /etc/rc.d/init.d/$_service_name "$_op"
58   fi
59 }
60
61 ######################################################
62 # simulate /sbin/service (niced) on platforms that don't have it
63 nice_service() { 
64   _service_name="$1"
65   _op="$2"
66
67   # do nothing, when no service was specified
68   [ -z "$_service_name" ] && return
69
70   if [ -x /sbin/service ]; then
71       nice /sbin/service "$_service_name" "$_op"
72   elif [ -x /etc/init.d/$_service_name ]; then
73       nice /etc/init.d/$_service_name "$_op"
74   elif [ -x /etc/rc.d/init.d/$_service_name ]; then
75       nice /etc/rc.d/init.d/$_service_name "$_op"
76   fi
77 }
78
79 ######################################################
80 # wait for a command to return a zero exit status
81 # usage: ctdb_wait_command SERVICE_NAME <command>
82 ######################################################
83 ctdb_wait_command() {
84   service_name="$1"
85   wait_cmd="$2"
86   [ -z "$wait_cmd" ] && return;
87   all_ok=0
88   echo "Waiting for service $service_name to start"
89   while [ $all_ok -eq 0 ]; do
90           $wait_cmd > /dev/null 2>&1 && all_ok=1
91           ctdb status > /dev/null 2>&1 || {
92                 echo "ctdb daemon has died. Exiting wait for $service_name"
93                 exit 1
94           }
95           [ $all_ok -eq 1 ] || sleep 1
96   done
97   echo "Local service $service_name is up"
98 }
99
100
101 ######################################################
102 # wait for a set of tcp ports
103 # usage: ctdb_wait_tcp_ports SERVICE_NAME <ports...>
104 ######################################################
105 ctdb_wait_tcp_ports() {
106   service_name="$1"
107   shift
108   wait_ports="$*"
109   [ -z "$wait_ports" ] && return;
110   all_ok=0
111   echo "Waiting for tcp service $service_name to start"
112   while [ $all_ok -eq 0 ]; do
113           all_ok=1
114           for p in $wait_ports; do
115               if [ -x /usr/bin/netcat ]; then
116                   /usr/bin/netcat -z 127.0.0.1 $p > /dev/null || all_ok=0
117               elif [ -x /usr/bin/nc ]; then
118                   /usr/bin/nc -z 127.0.0.1 $p > /dev/null || all_ok=0
119               elif [ -x /usr/bin/netstat ]; then
120                   (netstat -a -n | egrep "0.0.0.0:$p[[:space:]]*LISTEN" > /dev/null) || all_ok=0
121               elif [ -x /bin/netstat ]; then
122                   (netstat -a -n | egrep "0.0.0.0:$p[[:space:]]*LISTEN" > /dev/null) || all_ok=0
123               else 
124                   echo "No tool to check tcp ports availabe. can not check in ctdb_wait_tcp_ports"
125                   return 127
126               fi
127           done
128           [ $all_ok -eq 1 ] || sleep 1
129           ctdb status > /dev/null 2>&1 || {
130                 echo "ctdb daemon has died. Exiting tcp wait $service_name"
131                 return 1
132           }
133   done
134   echo "Local tcp services for $service_name are up"
135 }
136
137
138 ######################################################
139 # check that a rpc server is registered with portmap
140 # and responding to requests
141 # usage: ctdb_check_rpc SERVICE_NAME PROGNUM VERSION
142 ######################################################
143 ctdb_check_rpc() {
144     progname="$1"
145     prognum="$2"
146     version="$3"
147     rpcinfo -u localhost $prognum $version > /dev/null || {
148             echo "ERROR: $progname not responding to rpc requests"
149             exit 1
150     }
151 }
152
153 ######################################################
154 # check a set of directories is available
155 # return 1 on a missing directory
156 # usage: ctdb_check_directories_probe SERVICE_NAME <directories...>
157 ######################################################
158 ctdb_check_directories_probe() {
159     while IFS="" read d ; do
160         case "$d" in
161             *%*)
162                 continue
163                 ;;
164             *)
165                 [ -d "${d}/." ] || return 1
166         esac
167     done
168 }
169
170 ######################################################
171 # check a set of directories is available
172 # usage: ctdb_check_directories SERVICE_NAME <directories...>
173 ######################################################
174 ctdb_check_directories() {
175     n="${1:-${service_name}}"
176     ctdb_check_directories_probe || {
177         echo "ERROR: $n directory \"$d\" not available"
178         exit 1
179     }
180 }
181
182 ######################################################
183 # check a set of tcp ports
184 # usage: ctdb_check_tcp_ports <ports...>
185 ######################################################
186 ctdb_check_tcp_ports() {
187
188     for p ; do
189         if ! netstat -a -t -n | grep -q "0\.0\.0\.0:$p .*LISTEN" ; then
190             if ! netstat -a -t -n | grep -q ":::$p .*LISTEN" ; then
191                 echo "ERROR: $service_name tcp port $p is not responding"
192                 return 1
193             fi
194         fi
195     done
196 }
197
198 ######################################################
199 # check a unix socket
200 # usage: ctdb_check_unix_socket SERVICE_NAME <socket_path>
201 ######################################################
202 ctdb_check_unix_socket() {
203     socket_path="$1"
204     [ -z "$socket_path" ] && return
205
206     if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then
207         echo "ERROR: $service_name socket $socket_path not found"
208         return 1
209     fi
210 }
211
212 ######################################################
213 # check a command returns zero status
214 # usage: ctdb_check_command SERVICE_NAME <command>
215 ######################################################
216 ctdb_check_command() {
217   service_name="$1"
218   wait_cmd="$2"
219   [ -z "$wait_cmd" ] && return;
220   $wait_cmd > /dev/null 2>&1 || {
221       echo "ERROR: $service_name - $wait_cmd returned error"
222       exit 1
223   }
224 }
225
226 ################################################
227 # kill off any TCP connections with the given IP
228 ################################################
229 kill_tcp_connections() {
230     _IP="$1"    
231     _failed=0
232
233     _killcount=0
234     connfile="$CTDB_BASE/state/connections.$_IP"
235     netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
236     netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
237
238     while read dest src; do
239         srcip=`echo $src | sed -e "s/:[^:]*$//"`
240         srcport=`echo $src | sed -e "s/^.*://"`
241         destip=`echo $dest | sed -e "s/:[^:]*$//"`
242         destport=`echo $dest | sed -e "s/^.*://"`
243         echo "Killing TCP connection $srcip:$srcport $destip:$destport"
244         ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
245         case $destport in
246           # we only do one-way killtcp for CIFS
247           139|445) : ;;
248           # for all others we do 2-way
249           *) 
250                 ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
251                 ;;
252         esac
253         _killcount=`expr $_killcount + 1`
254      done < $connfile
255     /bin/rm -f $connfile
256
257     [ $_failed = 0 ] || {
258         echo "Failed to send killtcp control"
259         return;
260     }
261     [ $_killcount -gt 0 ] || {
262         return;
263     }
264     _count=0
265     while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
266         sleep 1
267         _count=`expr $_count + 1`
268         [ $_count -gt 3 ] && {
269             echo "Timed out killing tcp connections for IP $_IP"
270             return;
271         }
272     done
273     echo "killed $_killcount TCP connections to released IP $_IP"
274 }
275
276 ##################################################################
277 # kill off the local end for any TCP connections with the given IP
278 ##################################################################
279 kill_tcp_connections_local_only() {
280     _IP="$1"    
281     _failed=0
282
283     _killcount=0
284     connfile="$CTDB_BASE/state/connections.$_IP"
285     netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
286     netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
287
288     while read dest src; do
289         srcip=`echo $src | sed -e "s/:[^:]*$//"`
290         srcport=`echo $src | sed -e "s/^.*://"`
291         destip=`echo $dest | sed -e "s/:[^:]*$//"`
292         destport=`echo $dest | sed -e "s/^.*://"`
293         echo "Killing TCP connection $srcip:$srcport $destip:$destport"
294         ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
295         _killcount=`expr $_killcount + 1`
296      done < $connfile
297     /bin/rm -f $connfile
298
299     [ $_failed = 0 ] || {
300         echo "Failed to send killtcp control"
301         return;
302     }
303     [ $_killcount -gt 0 ] || {
304         return;
305     }
306     _count=0
307     while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
308         sleep 1
309         _count=`expr $_count + 1`
310         [ $_count -gt 3 ] && {
311             echo "Timed out killing tcp connections for IP $_IP"
312             return;
313         }
314     done
315     echo "killed $_killcount TCP connections to released IP $_IP"
316 }
317
318 ##################################################################
319 # tickle any TCP connections with the given IP
320 ##################################################################
321 tickle_tcp_connections() {
322     _IP="$1"
323     _failed=0
324
325     _killcount=0
326     connfile="$CTDB_BASE/state/connections.$_IP"
327     netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
328     netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
329
330     while read dest src; do
331         srcip=`echo $src | sed -e "s/:[^:]*$//"`
332         srcport=`echo $src | sed -e "s/^.*://"`
333         destip=`echo $dest | sed -e "s/:[^:]*$//"`
334         destport=`echo $dest | sed -e "s/^.*://"`
335         echo "Tickle TCP connection $srcip:$srcport $destip:$destport"
336         ctdb tickle $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
337         echo "Tickle TCP connection $destip:$destport $srcip:$srcport"
338         ctdb tickle $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
339      done < $connfile
340     /bin/rm -f $connfile
341
342     [ $_failed = 0 ] || {
343         echo "Failed to send tickle control"
344         return;
345     }
346 }
347
348 ########################################################
349 # start/stop the nfs service on different platforms
350 ########################################################
351 startstop_nfs() {
352         PLATFORM="unknown"
353         [ -x /etc/init.d/nfsserver ] && {
354                 PLATFORM="sles"
355         }
356         [ -x /etc/init.d/nfslock ] && {
357                 PLATFORM="rhel"
358         }
359
360         case $PLATFORM in
361         sles)
362                 case $1 in
363                 start)
364                         service nfsserver start
365                         ;;
366                 stop)
367                         service nfsserver stop > /dev/null 2>&1
368                         ;;
369                 esac
370                 ;;
371         rhel)
372                 case $1 in
373                 start)
374                         service nfslock start
375                         service nfs start
376                         ;;
377                 stop)
378                         service nfs stop > /dev/null 2>&1
379                         service nfslock stop > /dev/null 2>&1
380                         ;;
381                 esac
382                 ;;
383         *)
384                 echo "Unknown platform. NFS is not supported with ctdb"
385                 exit 1
386                 ;;
387         esac
388 }
389
390 ########################################################
391 # start/stop the nfs lockmanager service on different platforms
392 ########################################################
393 startstop_nfslock() {
394         PLATFORM="unknown"
395         [ -x /etc/init.d/nfsserver ] && {
396                 PLATFORM="sles"
397         }
398         [ -x /etc/init.d/nfslock ] && {
399                 PLATFORM="rhel"
400         }
401
402         case $PLATFORM in
403         sles)
404                 # for sles there is no service for lockmanager
405                 # so we instead just shutdown/restart nfs
406                 case $1 in
407                 start)
408                         service nfsserver start
409                         ;;
410                 stop)
411                         service nfsserver stop > /dev/null 2>&1
412                         ;;
413                 esac
414                 ;;
415         rhel)
416                 case $1 in
417                 start)
418                         service nfslock start
419                         ;;
420                 stop)
421                         service nfslock stop > /dev/null 2>&1
422                         ;;
423                 esac
424                 ;;
425         *)
426                 echo "Unknown platform. NFS locking is not supported with ctdb"
427                 exit 1
428                 ;;
429         esac
430 }
431
432 # better use delete_ip_from_iface() together with add_ip_to_iface
433 # remove_ip should be removed in future
434 remove_ip() {
435         local _ip_maskbits=$1
436         local _iface=$2
437         local _ip=`echo "$_ip_maskbits" | cut -d '/' -f1`
438         local _maskbits=`echo "$_ip_maskbits" | cut -d '/' -f2`
439
440         delete_ip_from_iface "$_iface" "$_ip" "$_maskbits"
441         return $?
442 }
443
444 add_ip_to_iface()
445 {
446         local _iface=$1
447         local _ip=$2
448         local _maskbits=$3
449         local _state_dir="$CTDB_BASE/state/interface_modify"
450         local _lockfile="$_state_dir/$_iface.flock"
451         local _readd_base="$_state_dir/$_iface.readd.d"
452
453         mkdir -p $_state_dir || {
454                 ret=$?
455                 echo "Failed to mkdir -p $_state_dir - $ret"
456                 return $ret
457         }
458
459         test -f $_lockfile || {
460                 touch $_lockfile
461         }
462
463         flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh add "$_iface" "$_ip" "$_maskbits" "$_readd_base"
464         return $?
465 }
466
467 delete_ip_from_iface()
468 {
469         local _iface=$1
470         local _ip=$2
471         local _maskbits=$3
472         local _state_dir="$CTDB_BASE/state/interface_modify"
473         local _lockfile="$_state_dir/$_iface.flock"
474         local _readd_base="$_state_dir/$_iface.readd.d"
475
476         mkdir -p $_state_dir || {
477                 ret=$?
478                 echo "Failed to mkdir -p $_state_dir - $ret"
479                 return $ret
480         }
481
482         test -f $_lockfile || {
483                 touch $_lockfile
484         }
485
486         flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh delete "$_iface" "$_ip" "$_maskbits" "$_readd_base"
487         return $?
488 }
489
490 setup_iface_ip_readd_script()
491 {
492         local _iface=$1
493         local _ip=$2
494         local _maskbits=$3
495         local _readd_script=$4
496         local _state_dir="$CTDB_BASE/state/interface_modify"
497         local _lockfile="$_state_dir/$_iface.flock"
498         local _readd_base="$_state_dir/$_iface.readd.d"
499
500         mkdir -p $_state_dir || {
501                 ret=$?
502                 echo "Failed to mkdir -p $_state_dir - $ret"
503                 return $ret
504         }
505
506         test -f $_lockfile || {
507                 touch $_lockfile
508         }
509
510         flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh readd_script "$_iface" "$_ip" "$_maskbits" "$_readd_base" "$_readd_script"
511         return $?
512 }
513
514 ########################################################
515 # some simple logic for counting events - per eventscript
516 # usage: ctdb_counter_init
517 #        ctdb_counter_incr
518 #        ctdb_check_counter_limit <limit>
519 # ctdb_check_counter_limit succeeds when count >= <limit>
520 ########################################################
521 _ctdb_counter_common () {
522     _counter_file="$ctdb_fail_dir/$service_name"
523     mkdir -p "${_counter_file%/*}" # dirname
524 }
525 ctdb_counter_init () {
526     _ctdb_counter_common
527
528     >"$_counter_file"
529 }
530 ctdb_counter_incr () {
531     _ctdb_counter_common
532
533     # unary counting!
534     echo -n 1 >> "$_counter_file"
535 }
536 ctdb_check_counter_limit () {
537     _ctdb_counter_common
538
539     _limit="${1:-${service_fail_limit}}"
540     _quiet="$2"
541
542     # unary counting!
543     _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0)
544     if [ $_size -ge $_limit ] ; then
545         echo "ERROR: more than $_limit consecutive failures for $service_name, marking cluster unhealthy"
546         exit 1
547     elif [ $_size -gt 0 -a -z "$_quiet" ] ; then
548         echo "WARNING: less than $_limit consecutive failures ($_size) for $service_name, not unhealthy yet"
549     fi
550 }
551 ########################################################
552
553 ctdb_spool_dir="/var/spool/ctdb"
554 ctdb_status_dir="$ctdb_spool_dir/status"
555 ctdb_fail_dir="$ctdb_spool_dir/failcount"
556 ctdb_active_dir="$ctdb_spool_dir/active"
557
558 log_status_cat ()
559 {
560     echo "node is \"$1\", \"${script_name}\" reports problem: $(cat $2)"
561 }
562
563 ctdb_checkstatus ()
564 {
565     if [ -r "$ctdb_status_dir/$script_name/unhealthy" ] ; then
566         log_status_cat "unhealthy" "$ctdb_status_dir/$script_name/unhealthy"
567         return 1
568     elif [ -r "$ctdb_status_dir/$script_name/banned" ] ; then
569         log_status_cat "banned" "$ctdb_status_dir/$script_name/banned"
570         return 2
571     else
572         return 0
573     fi
574 }
575
576 ctdb_setstatus ()
577 {
578     d="$ctdb_status_dir/$script_name"
579     case "$1" in
580         unhealthy|banned)
581             mkdir -p "$d"
582             cat "$2" >"$d/$1"
583             ;;
584         *)
585             for i in "banned" "unhealthy" ; do
586                 rm -f "$d/$i"
587             done
588             ;;
589     esac
590 }
591
592 ctdb_service_needs_reconfigure ()
593 {
594     [ -e "$ctdb_status_dir/$service_name/reconfigure" ]
595 }
596
597 ctdb_service_set_reconfigure ()
598 {
599     d="$ctdb_status_dir/$service_name"
600     mkdir -p "$d"
601     >"$d/reconfigure"
602 }
603
604 ctdb_service_unset_reconfigure ()
605 {
606     rm -f "$ctdb_status_dir/$service_name/reconfigure"
607 }
608
609 ctdb_service_reconfigure ()
610 {
611     if [ -n "$service_reconfigure" ] ; then
612         eval $service_reconfigure
613     else
614         service "$service_name" restart
615     fi
616     ctdb_service_unset_reconfigure
617     ctdb_counter_init
618 }
619
620 ctdb_compat_managed_service ()
621 {
622     if [ "$1" = "yes" ] ; then
623         t="$t $2 "
624     fi
625 }
626
627 is_ctdb_managed_service ()
628 {
629     t=" $CTDB_MANAGED_SERVICES "
630
631     ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD"   "vsftpd"
632     ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA"    "samba"
633     ctdb_compat_managed_service "$CTDB_MANAGES_SCP"      "scp"
634     ctdb_compat_managed_service "$CTDB_MANAGES_WINDBIND" "windbind"
635     ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD"    "httpd"
636     ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI"    "iscsi"
637     ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD"    "clamd"
638     ctdb_compat_managed_service "$CTDB_MANAGES_NFS"      "nfs"
639
640     # Returns 0 if "<space>$service_name<space>" appears in $t
641     [ "${t#* ${service_name} }" != "${t}" ]
642 }
643
644 ctdb_start_stop_service ()
645 {
646     _active="$ctdb_active_dir/$service_name"
647
648     if is_ctdb_managed_service ; then
649         if ! [ -e "$_active" ] ; then
650             echo "Starting service $service_name"
651             ctdb_service_start || exit $?
652             mkdir -p "$ctdb_active_dir"
653             touch "$_active"
654             exit 0
655         fi
656     elif ! is_ctdb_managed_service ; then
657         if [ -e "$_active" ] ; then
658             echo "Stopping service $service_name"
659             ctdb_service_stop || exit $?
660             rm -f "$_active"
661         fi
662         exit 0
663     fi
664 }
665
666 ctdb_service_start ()
667 {
668     if [ -n "$service_start" ] ; then
669         eval $service_start
670     else
671         service "$service_name" start
672     fi
673     ctdb_counter_init
674 }
675
676 ctdb_service_stop ()
677 {
678     if [ -n "$service_stop" ] ; then
679         eval $service_stop
680     else
681         service "$service_name" stop
682     fi
683 }
684
685 ctdb_standard_event_handler ()
686 {
687     case "$1" in
688         status)
689             ctdb_checkstatus
690             exit
691             ;;
692         setstatus)
693             shift
694             ctdb_setstatus "$@"
695             exit
696             ;;
697     esac
698 }
699
700 ipv4_host_addr_to_net_addr()
701 {
702         local HOST=$1
703         local MASKBITS=$2
704
705         local HOST0=$(echo $HOST | awk -F . '{print $4}')
706         local HOST1=$(echo $HOST | awk -F . '{print $3}')
707         local HOST2=$(echo $HOST | awk -F . '{print $2}')
708         local HOST3=$(echo $HOST | awk -F . '{print $1}')
709
710         local HOST_NUM=$(( $HOST0 + $HOST1 * 256 + $HOST2 * (256 ** 2) + $HOST3 * (256 ** 3) ))
711
712         local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
713
714         local NET_NUM=$(( $HOST_NUM & $MASK_NUM))
715
716         local NET0=$(( $NET_NUM & 255 ))
717         local NET1=$(( ($NET_NUM & (255 * 256)) / 256 ))
718         local NET2=$(( ($NET_NUM & (255 * 256**2)) / 256**2 ))
719         local NET3=$(( ($NET_NUM & (255 * 256**3)) / 256**3 ))
720
721         echo "$NET3.$NET2.$NET1.$NET0"
722 }
723
724 ipv4_maskbits_to_net_mask()
725 {
726         local MASKBITS=$1
727
728         local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
729
730         local MASK0=$(( $MASK_NUM & 255 ))
731         local MASK1=$(( ($MASK_NUM & (255 * 256)) / 256 ))
732         local MASK2=$(( ($MASK_NUM & (255 * 256**2)) / 256**2 ))
733         local MASK3=$(( ($MASK_NUM & (255 * 256**3)) / 256**3 ))
734
735         echo "$MASK3.$MASK2.$MASK1.$MASK0"
736 }
737
738 ipv4_is_valid_addr()
739 {
740         local ADDR=$1
741         local fail=0
742
743         local N=`echo $ADDR | sed -e 's/[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*//'`
744         test -n "$N" && fail=1
745
746         local ADDR0=$(echo $ADDR | awk -F . '{print $4}')
747         local ADDR1=$(echo $ADDR | awk -F . '{print $3}')
748         local ADDR2=$(echo $ADDR | awk -F . '{print $2}')
749         local ADDR3=$(echo $ADDR | awk -F . '{print $1}')
750
751         test "$ADDR0" -gt 255 && fail=1
752         test "$ADDR1" -gt 255 && fail=1
753         test "$ADDR2" -gt 255 && fail=1
754         test "$ADDR3" -gt 255 && fail=1
755
756         test x"$fail" != x"0" && {
757                 #echo "IPv4: '$ADDR' is not a valid address"
758                 return 1;
759         }
760
761         return 0;
762 }
763
764 # iptables doesn't like being re-entered, so flock-wrap it.
765 iptables()
766 {
767         flock -w 30 /var/ctdb/iptables-ctdb.flock /sbin/iptables "$@"
768 }
769
770 ########################################################
771 # load a site local config file
772 ########################################################
773
774 [ -x $CTDB_BASE/rc.local ] && {
775         . $CTDB_BASE/rc.local
776 }
777
778 [ -d $CTDB_BASE/rc.local.d ] && {
779         for i in $CTDB_BASE/rc.local.d/* ; do
780                 [ -x "$i" ] && . "$i"
781         done
782 }
783
784 script_name="${0##*/}"       # basename
785 service_name="$script_name"  # default is just the script name
786 service_fail_limit=1