diff --git a/rgmanager/src/resources/ip.sh b/rgmanager/src/resources/ip.sh index 8686f0279..29d6bfc6b 100755 --- a/rgmanager/src/resources/ip.sh +++ b/rgmanager/src/resources/ip.sh @@ -1,1006 +1,1023 @@ #!/bin/bash # # IPv4/IPv6 address management using new /sbin/ifcfg instead of # ifconfig utility. # # # Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # LC_ALL=C LANG=C PATH=/bin:/sbin:/usr/bin:/usr/sbin export LC_ALL LANG PATH # Grab nfs lock tricks if available export NFS_TRICKS=1 if [ -f "$(dirname $0)/svclib_nfslock" ]; then . $(dirname $0)/svclib_nfslock NFS_TRICKS=0 fi . $(dirname $0)/ocf-shellfuncs meta_data() { cat < 1.0 This is an IP address. Both IPv4 and IPv6 addresses are supported, as well as NIC link monitoring for each IP address. This is an IP address. IPv4 or IPv6 address to use as a virtual IP resource. IP Address IPv4 or IPv6 address protocol family. Family Enabling this causes the status check to fail if the link on the NIC to which this IP address is bound is not present. Monitor NIC Link If set and unmounting the file system fails, the node will try to kill lockd and issue reclaims across all remaining network interface cards. Enable NFS lock workarounds Amount of time to sleep after removing an IP address. Value is specified in seconds. Default value is 10. Amount of time (seconds) to sleep. Disable updating of routing using RDISC protocol and preserve static routes. Disable updating of routing using RDISC protocol + + + The network interface to which the IP address should be added. The interface must already be configured and active. This parameter should be used only when at least two active interfaces have IP addresses on the same subnet and it is desired to have the IP address added to a particular interface. + + + Network interface + + + EOT } verify_address() { # XXX TBD return 0 } verify_all() { # XXX TBD return 0 } # # Expand an IPv6 address. # ipv6_expand() { typeset addr=$1 typeset maskbits typeset -i x typeset tempaddr maskbits=${addr/*\//} if [ "$maskbits" = "$addr" ]; then maskbits="" else # chop off mask bits addr=${addr/\/*/} fi # grab each hex quad and expand it to 4 digits if it isn't already # leave doublecolon in place for expansion out to the proper number of zeros later tempaddr="" for count in `seq 1 8`; do quad=`echo $addr|awk -v count=$count -F : '{print $count}'` quadlen=${#quad} if [ $quadlen -eq 0 ]; then quad=:: elif [ $quadlen -eq 1 ]; then quad=000$quad elif [ $quadlen -eq 2 ]; then quad=00$quad elif [ $quadlen -eq 3 ]; then quad=0$quad fi tempaddr=$tempaddr$quad done addr=$tempaddr # use space as placeholder addr=${addr/::/\ } # get rid of colons addr=${addr//:/} # add in zeroes where the doublecolon was len=$((${#addr}-1)) zeroes= while [ $len -lt 32 ]; do zeroes="0$zeroes" ((len++)) done addr=${addr/\ /$zeroes} # probably a better way to do this for (( x=0; x < ${#addr} ; x++)); do naddr=$naddr${addr:x:1} if (( x < (${#addr} - 1) && x%4 == 3)); then naddr=$naddr: fi done if [ -n "$maskbits" ]; then echo "$naddr/$maskbits" return 0 fi echo "$naddr" return 0 } # # see if two ipv6 addrs are in the same subnet # ipv6_same_subnet() { declare addrl=$1 declare addrr=$2 declare m=$3 declare r x llsb rlsb if [ $# -lt 2 ]; then ocf_log err "usage: ipv6_same_subnet addr1 addr2 [mask]" return 255 fi if [ -z "$m" ]; then m=${addrl/*\//} [ -n "$m" ] || return 1 fi if [ "${addrr}" != "${addrr/*\//}" ] && [ "$m" != "${addrr/*\//}" ]; then return 1 fi addrl=${addrl/\/*/} if [ ${#addrl} -lt 39 ]; then addrl=$(ipv6_expand $addrl) fi addrr=${addrr/\/*/} if [ ${#addrr} -lt 39 ]; then addrr=$(ipv6_expand $addrr) fi # Calculate the amount to compare directly x=$(($m/4+$m/16-(($m%4)==0))) # and the remaining number of bits r=$(($m%4)) if [ $r -ne 0 ]; then # If we have any remaining bits, we will need to compare # them later. Get them now. llsb=`printf "%d" 0x${addrl:$x:1}` rlsb=`printf "%d" 0x${addrr:$x:1}` # One less byte to compare directly, please ((--x)) fi # direct (string comparison) to see if they are equal if [ "${addrl:0:$x}" != "${addrr:0:$x}" ]; then return 1 fi case $r in 0) return 0 ;; 1) [ $(($llsb & 8)) -eq $(($rlsb & 8)) ] return $? ;; 2) [ $(($llsb & 12)) -eq $(($rlsb & 12)) ] return $? ;; 3) [ $(($llsb & 14)) -eq $(($rlsb & 14)) ] return $? ;; esac return 1 } ipv4_same_subnet() { declare addrl=$1 declare addrr=$2 declare m=$3 declare r x llsb rlsb if [ $# -lt 2 ]; then ocf_log err "usage: ipv4_same_subnet current_addr new_addr [maskbits]" return 255 fi # # Chop the netmask off of the ipaddr: # e.g. 1.2.3.4/22 -> 22 # if [ -z "$m" ]; then m=${addrl/*\//} [ -n "$m" ] || return 1 fi # # Check to see if there was a subnet mask provided on the # new IP address. If there was one and it does not match # our expected subnet mask, we are done. # if [ "${addrr}" != "${addrr/\/*/}" ] && [ "$m" != "${addrr/*\//}" ]; then return 1 fi # # Chop off subnet bits for good. # addrl=${addrl/\/*/} addrr=${addrr/\/*/} # # Remove '.' characters from dotted decimal notation and save # in arrays. i.e. # # 192.168.1.163 -> array[0] = 192 # array[1] = 168 # array[2] = 1 # array[3] = 163 # let x=0 for quad in ${addrl//./\ }; do ip1[((x++))]=$quad done x=0 for quad in ${addrr//./\ }; do ip2[((x++))]=$quad done x=0 while [ $m -ge 8 ]; do ((m-=8)) if [ ${ip1[x]} -ne ${ip2[x]} ]; then return 1 fi ((x++)) done case $m in 0) return 0 ;; 1) [ $((${ip1[x]} & 128)) -eq $((${ip2[x]} & 128)) ] return $? ;; 2) [ $((${ip1[x]} & 192)) -eq $((${ip2[x]} & 192)) ] return $? ;; 3) [ $((${ip1[x]} & 224)) -eq $((${ip2[x]} & 224)) ] return $? ;; 4) [ $((${ip1[x]} & 240)) -eq $((${ip2[x]} & 240)) ] return $? ;; 5) [ $((${ip1[x]} & 248)) -eq $((${ip2[x]} & 248)) ] return $? ;; 6) [ $((${ip1[x]} & 252)) -eq $((${ip2[x]} & 252)) ] return $? ;; 7) [ $((${ip1[x]} & 254)) -eq $((${ip2[x]} & 254)) ] return $? ;; esac return 1 } ipv6_list_interfaces() { declare idx dev ifaddr declare ifaddr_exp while read idx dev ifaddr; do isSlave $dev if [ $? -ne 2 ]; then continue fi idx=${idx/:/} ifaddr_exp=$(ipv6_expand $ifaddr) echo $dev ${ifaddr_exp/\/*/} ${ifaddr_exp/*\//} done < <(/sbin/ip -o -f inet6 addr | awk '{print $1,$2,$4}') return 0 } isSlave() { declare intf=$1 declare line if [ -z "$intf" ]; then ocf_log err "usage: isSlave " return $OCF_ERR_ARGS fi line=$(/sbin/ip link list dev $intf) if [ $? -ne 0 ]; then ocf_log err "$intf not found" return $OCF_ERR_GENERIC fi if [ "$line" = "${line/<*SLAVE*>/}" ]; then return 2 fi # Yes, it is a slave device. Ignore. return 0 } # # Check if interface is in UP state # interface_up() { declare intf=$1 if [ -z "$intf" ]; then ocf_log err "usage: interface_up " return 1 fi line=$(/sbin/ip -o link show up dev $intf 2> /dev/null) [ -z "$line" ] && return 2 return 0 } ethernet_link_up() { declare linkstate=$(ethtool $1 | grep "Link detected:" |\ awk '{print $3}') [ -n "$linkstate" ] || return 0 case $linkstate in yes) return 0 ;; *) return 1 ;; esac return 1 } # # Checks the physical link status of an ethernet or bonded interface. # network_link_up() { declare slaves declare intf_arg=$1 declare link_up=1 # Assume link down declare intf_test if [ -z "$intf_arg" ]; then ocf_log err "usage: network_link_up " return 1 fi ethernet_link_up $intf_arg link_up=$? if [ $link_up -eq 0 ]; then ocf_log debug "Link for $intf_arg: Detected" else ocf_log warn "Link for $intf_arg: Not detected" fi return $link_up } ipv4_list_interfaces() { declare idx dev ifaddr while read idx dev ifaddr; do isSlave $dev if [ $? -ne 2 ]; then continue fi idx=${idx/:/} echo $dev ${ifaddr/\/*/} ${ifaddr/*\//} done < <(/sbin/ip -o -f inet addr | awk '{print $1,$2,$4}') return 0 } # # Add an IP address to our interface. # ipv6() { declare dev maskbits declare addr=$2 declare addr_exp=$(ipv6_expand $addr) while read dev ifaddr_exp maskbits; do if [ -z "$dev" ]; then continue fi if [ "$1" = "add" ]; then + if [ -n "$OCF_RESKEY_prefer_interface" ] && \ + [ "$OCF_RESKEY_prefer_interface" != $dev ]; then + continue + fi ipv6_same_subnet $ifaddr_exp/$maskbits $addr_exp if [ $? -ne 0 ]; then continue fi interface_up $dev if [ $? -ne 0 ]; then continue fi if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then network_link_up $dev if [ $? -ne 0 ]; then continue fi fi if [ "${addr/\/*/}" = "${addr}" ]; then addr="$addr/$maskbits" fi ocf_log info "Adding IPv6 address $addr to $dev" fi if [ "$1" = "del" ]; then if [ "${addr_exp/\/*/}" != "$ifaddr_exp" ]; then continue fi addr=`/sbin/ip addr list | grep "$addr" | head -n 1 | awk '{print $2}'` ocf_log info "Removing IPv6 address $addr from $dev" fi if [ "$1" = "add" ]; then ocf_log debug "Pinging addr ${addr%%/*} from dev $dev" if ping_check inet6 ${addr%%/*} $dev; then ocf_log err "IPv6 address collision ${addr%%/*}" return 1 fi fi /sbin/ip -f inet6 addr $1 dev $dev $addr [ $? -ne 0 ] && return 1 # # NDP should take of figuring out our new address. Plus, # we do not have something (like arping) to do this for ipv6 # anyway. # # RFC 2461, section 7.2.6 states thusly: # # Note that because unsolicited Neighbor Advertisements do not # reliably update caches in all nodes (the advertisements might # not be received by all nodes), they should only be viewed as # a performance optimization to quickly update the caches in # most neighbors. # # Not sure if this is necessary for ipv6 either. file=$(which rdisc 2>/dev/null) if [ -f "$file" ]; then if [ "$OCF_RESKEY_disable_rdisc" != "yes" ] && \ [ "$OCF_RESKEY_disable_rdisc" != "1" ]; then killall -HUP rdisc || rdisc -fs fi fi return 0 done < <(ipv6_list_interfaces) return 1 } # # Add an IP address to our interface. # ipv4() { declare dev ifaddr maskbits declare addr=$2 while read dev ifaddr maskbits; do if [ -z "$dev" ]; then continue fi if [ "$1" = "add" ]; then + if [ -n "$OCF_RESKEY_prefer_interface" ] && \ + [ "$OCF_RESKEY_prefer_interface" != $dev ]; then + continue + fi ipv4_same_subnet $ifaddr/$maskbits $addr if [ $? -ne 0 ]; then continue fi interface_up $dev if [ $? -ne 0 ]; then continue fi if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then network_link_up $dev if [ $? -ne 0 ]; then continue fi fi if [ "${addr/\/*/}" = "${addr}" ]; then addr="$addr/$maskbits" fi ocf_log info "Adding IPv4 address $addr to $dev" fi if [ "$1" = "del" ]; then if [ "${addr/\/*/}" != "$ifaddr" ]; then continue fi addr=`/sbin/ip addr list | grep "$ifaddr/" | head -n 1 | awk '{print $2}'` ocf_log info "Removing IPv4 address $addr from $dev" fi if [ "$1" = "add" ]; then ocf_log debug "Pinging addr ${addr%%/*} from dev $dev" if ping_check inet ${addr%%/*} $dev; then ocf_log err "IPv4 address collision ${addr%%/*}" return 1 fi fi /sbin/ip -f inet addr $1 dev $dev $addr [ $? -ne 0 ] && return 1 # # The following is needed only with ifconfig; ifcfg does it for us # if [ "$1" = "add" ]; then # do that freak arp thing hwaddr=$(/sbin/ip -o link show $dev) hwaddr=${hwaddr/*link\/ether\ /} hwaddr=${hwaddr/\ \*/} addr=${addr/\/*/} ocf_log debug "Sending gratuitous ARP: $addr $hwaddr" arping -q -c 2 -U -I $dev $addr fi file=$(which rdisc 2>/dev/null) if [ -f "$file" ]; then if [ "$OCF_RESKEY_disable_rdisc" != "yes" ] && \ [ "$OCF_RESKEY_disable_rdisc" != "1" ]; then killall -HUP rdisc || rdisc -fs fi fi return 0 done < <(ipv4_list_interfaces) return 1 } # # Usage: # ping_check
[interface] # ping_check() { declare ops="-c 1 -w 2" declare pingcmd="" if [ "$1" = "inet6" ]; then pingcmd="ping6" else pingcmd="ping" fi if [ -n "$3" ]; then ops="$ops -I $3" fi return $($pingcmd $ops $2 &> /dev/null) } # # Usage: # check_interface_up
# check_interface_up() { declare dev declare addr=${2/\/*/} declare currentAddr caExpanded if [ "$1" == "inet6" ]; then addrExpanded=$(ipv6_expand $addr) for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do caExpanded=$(ipv6_expand $currentAddr) caExpanded=${caExpanded/\/*/} if [ "$addrExpanded" == "$caExpanded" ]; then dev=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $2}') break fi done else dev=$(/sbin/ip -f $1 -o addr | grep " $addr/" | awk '{print $2}') fi if [ -z "$dev" ]; then return 1 fi interface_up $dev return $? } # # Usage: # address_configured
# address_configured() { declare line declare addr declare currentAddr caExpanded # Chop off maxk bits addr=${2/\/*/} if [ "$1" == "inet6" ]; then addrExpanded=$(ipv6_expand $addr) for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do caExpanded=$(ipv6_expand $currentAddr) caExpanded=${caExpanded/\/*/} if [ "$addrExpanded" == "$caExpanded" ]; then line=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}"); break fi done else line=$(/sbin/ip -f $1 -o addr | grep " $addr/") fi if [ -z "$line" ]; then return 1 fi return 0 } # # Usage: # ip_op
[quiet] # ip_op() { declare dev declare rtr declare addr=${3/\/*/} declare caExpanded currentAddr if [ "$2" = "status" ]; then ocf_log debug "Checking $3, Level $OCF_CHECK_LEVEL" if [ "$1" == "inet6" ]; then addrExpanded=$(ipv6_expand $addr) for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do caExpanded=$(ipv6_expand $currentAddr) caExpanded=${caExpanded/\/*/} if [ "$addrExpanded" == "$caExpanded" ]; then dev=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $2}') break fi done else dev=$(/sbin/ip -f $1 -o addr | grep " $addr/" | awk '{print $2}') fi if [ -z "$dev" ]; then ocf_log warn "$3 is not configured" return 1 fi ocf_log debug "$3 present on $dev" if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then if ! network_link_up $dev; then ocf_log warn "No link on $dev..." return 1 fi ocf_log debug "Link detected on $dev" fi [ $OCF_CHECK_LEVEL -lt 10 ] && return 0 if ! ping_check $1 $addr $dev; then ocf_log warn "Failed to ping $addr" return 1 fi ocf_log debug "Local ping to $addr succeeded" return 0 fi case $1 in inet) ipv4 $2 $3 return $? ;; inet6) if [ "$2" = "del" ]; then addrExpanded=$(ipv6_expand $addr) for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do caExpanded=$(ipv6_expand $currentAddr) caExpanded=${caExpanded/\/*/} if [ "$addrExpanded" == "$caExpanded" ]; then addr6=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $4}') ipv6 $2 $addr6 return $? fi done fi ipv6 $2 $3 return $? ;; esac return 1 } case ${OCF_RESKEY_family} in inet) ;; inet6) ;; *) if [ "${OCF_RESKEY_address//:/}" != "${OCF_RESKEY_address}" ]; then export OCF_RESKEY_family=inet6 else export OCF_RESKEY_family=inet fi ;; esac if [ -z "$OCF_CHECK_LEVEL" ]; then OCF_CHECK_LEVEL=0 fi if [ "${OCF_RESKEY_monitor_link}" = "no" ] || [ "${OCF_RESKEY_monitor_link}" = "0" ]; then OCF_RESKEY_monitor_link="no" else OCF_RESKEY_monitor_link="yes" fi case $1 in start) if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then ocf_log debug "${OCF_RESKEY_address} already configured" exit 0 fi ip_op ${OCF_RESKEY_family} add ${OCF_RESKEY_address} if [ $? -ne 0 ]; then exit $OCF_ERR_GENERIC fi if [ $NFS_TRICKS -eq 0 ]; then if [ "$OCF_RESKEY_nfslock" = "yes" ] || \ [ "$OCF_RESKEY_nfslock" = "1" ]; then notify_list_broadcast /var/lib/nfs/statd fi fi exit $? ;; stop) if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then ip_op ${OCF_RESKEY_family} del ${OCF_RESKEY_address} # Make sure it's down if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then ocf_log err "Failed to remove ${OCF_RESKEY_address}" exit 1 fi # XXX Let nfsd/lockd clear their queues; we hope to have a # way to enforce this in the future if [ -z "$OCF_RESKEY_sleeptime" ]; then sleep 10 else if [ "$OCF_RESKEY_sleeptime" -gt "0" ]; then sleep $OCF_RESKEY_sleeptime fi fi else ocf_log debug "${OCF_RESKEY_address} is not configured" fi exit 0 ;; status|monitor) ip_op ${OCF_RESKEY_family} status ${OCF_RESKEY_address} [ $? -ne 0 ] && exit $OCF_NOT_RUNNING check_interface_up ${OCF_RESKEY_family} ${OCF_RESKEY_address} exit $? ;; restart) $0 stop || exit $OCF_ERR_GENERIC $0 start || exit $OCF_ERR_GENERIC exit 0 ;; meta-data) meta_data exit 0 ;; validate-all|verify_all) verify_all exit $? ;; *) echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}" exit $OCF_ERR_UNIMPLEMENTED ;; esac diff --git a/rgmanager/src/resources/orainstance.sh b/rgmanager/src/resources/orainstance.sh index 93c4c68d1..3d4c12349 100644 --- a/rgmanager/src/resources/orainstance.sh +++ b/rgmanager/src/resources/orainstance.sh @@ -1,526 +1,526 @@ #!/bin/bash # # Copyright 2003-2004, 2006-2011 Red Hat, Inc. # # Author(s): # Hardy Merrill # Lon Hohberger # Michael Moon # # This program is Open Source software. You may modify and/or redistribute # it persuant to the terms of the Open Software License version 2.1, which # is available from the following URL and is included herein by reference: # # http://opensource.org/licenses/osl-2.1.php # # chkconfig: 345 99 01 # description: Service script for starting/stopping \ # Oracle(R) Database 10g on \ # Red Hat Enterprise Linux 5 # # NOTES: # # (1) You can comment out the LOCKFILE declaration below. This will prevent # the need for this script to access anything outside of the ORACLE_HOME # path. # # (2) You MUST customize ORACLE_USER, ORACLE_HOME, ORACLE_SID, and # ORACLE_HOSTNAME to match your installation if not running from within # rgmanager. # # (3) Do NOT place this script in shared storage; place it in ORACLE_USER's # home directory in non-clustered environments and /usr/share/cluster # in rgmanager/Red Hat cluster environments. # # Oracle is a registered trademark of Oracle Corporation. # Oracle9i is a trademark of Oracle Corporation. # Oracle10g is a trademark of Oracle Corporation. # All other trademarks are property of their respective owners. # # # $Id: orainstance.sh 127 2009-08-21 09:17:52Z hevirtan $ # # Original version is distributed with RHCS. The modifications include # the following minor changes: # - Meta-data moved to a dedicated file # - Support for multiple listeners # - Disabled EM # - SysV init support removed. Only usable with rgmanager # . /etc/init.d/functions declare SCRIPT="`basename $0`" declare SCRIPTDIR="`dirname $0`" # Required parameters from rgmanager ORACLE_USER=$OCF_RESKEY_user ORACLE_HOME=$OCF_RESKEY_home ORACLE_SID=$OCF_RESKEY_name # Optional parameters with default values LISTENERS=$OCF_RESKEY_listeners LOCKFILE="/tmp/.oracle10g-${ORACLE_SID}.lock" [ -n "$OCF_RESKEY_lockfile" ] && LOCKFILE=$OCF_RESKEY_lockfile export LISTENERS ORACLE_USER ORACLE_HOME ORACLE_SID LOCKFILE export LD_LIBRARY_PATH=$ORACLE_HOME/lib export PATH=$ORACLE_HOME/bin:$PATH declare -i RESTART_RETRIES=3 declare -r DB_PROCNAMES="pmon" declare -r LSNR_PROCNAME="tnslsnr" # # Start Oracle (database portion) # start_db() { declare tmpfile declare logfile declare -i rv tmpfile=/tmp/$SCRIPT-start.$$ logfile=/tmp/$SCRIPT-start.log.$$ # Set up our sqlplus script. Basically, we're trying to # capture output in the hopes that it's useful in the case # that something doesn't work properly. echo "startup" > $tmpfile echo "quit" >> $tmpfile sqlplus "/ as sysdba" < $tmpfile > $logfile rv=$? rm -f $tmpfile # Dump logfile to /var/log/messages initlog -q -c "cat $logfile" if [ $rv -ne 0 ]; then rm -f $logfile initlog -n $SCRIPT -q -s "sqlplus returned 1, failed" return 1 fi # If we see: # ORA-.....: failure, we failed - grep -q "failure" $logfile + grep -q "^ORA-" $logfile rv=$? rm -f $logfile if [ $rv -eq 0 ]; then initlog -n $SCRIPT -q -s "found failure in stdout, returning 1" return 1 fi return 0 } # # Stop Oracle (database portion) # stop_db() { declare tmpfile declare logfile declare -i rv tmpfile=/tmp/$SCRIPT-stop.$$ logfile=/tmp/$SCRIPT-stop.log.$$ ora_procname="ora_${DB_PROCNAMES}_${ORACLE_SID}" status $ora_procname if [ $? -ne 0 ]; then # No pmon process found, db already down return 0 fi # Setup for Stop ... echo "shutdown immediate" > $tmpfile echo "quit" >> $tmpfile sqlplus "/ as sysdba" < $tmpfile > $logfile rv=$? rm -f $tmpfile # Dump logfile to /var/log/messages initlog -q -c "cat $logfile" # sqlplus returned failure. We'll return failed to rhcs if [ $rv -ne 0 ]; then rm -f $logfile initlog -n $SCRIPT -q -s "sqlplus returned 1, failed" return 1 fi - grep -q failure $logfile + grep -q "^ORA-" $logfile rv=$? rm -f $logfile # If we see 'failure' in the log, we're done. if [ $rv -eq 0 ]; then initlog -n $SCRIPT -q -s "found failure in stdout, returning 1" return 1 fi return 0 } # # Destroy any remaining processes with refs to $ORACLE_SID # force_cleanup() { declare pids declare pid pids=`ps ax | grep $ORACLE_SID | grep -v grep | awk '{print $1}'` initlog -n $SCRIPT -s " Not all Oracle processes exited cleanly, killing" for pid in $pids; do kill -9 $pid if [ $? -eq 0 ]; then initlog -n $SCRIPT -s "Killed $pid" fi done return 0 } # # Wait for oracle processes to exit. Time out after 60 seconds # exit_idle() { declare -i n=0 while ps ax | grep $ORACLE_SID | grep -q -v $LSNR_PROCNAME | grep -q -v grep; do if [ $n -ge 90 ]; then force_cleanup return 0 fi sleep 1 ((n++)) done return 0 } # # Get database background process status. Restart it if it failed and # we have seen the lock file. # get_db_status() { declare -i subsys_lock=$1 declare -i i=0 declare -i rv=0 declare ora_procname for procname in $DB_PROCNAMES ; do ora_procname="ora_${procname}_${ORACLE_SID}" status $ora_procname if [ $? -eq 0 ] ; then # This one's okay; go to the next one. continue fi # We're not supposed to be running, and we are, # in fact, not running... if [ $subsys_lock -ne 0 ]; then return 3 fi for (( i=$RESTART_RETRIES ; i; i-- )) ; do # this db process is down - stop and # (re)start all ora_XXXX_$ORACLE_SID processes initlog -q -n $SCRIPT -s "Restarting Oracle Database..." stop_db start_db if [ $? == 0 ] ; then # ora_XXXX_$ORACLE_SID processes started # successfully, so break out of the # stop/start # 'for' loop break fi done if [ $i -eq 0 ]; then # stop/start's failed - return 1 (failure) initlog -q -n $SCRIPT -s "Restart failed, retuning 1" return 1 fi done return 0 } # # Get the status of the Oracle listener process # get_lsnr_status() { declare -i subsys_lock=$1 declare -i rv declare -r LISTENER=$3 lsnrctl status $LISTENER >& /dev/null rv=$? if [ $rv == 0 ] ; then return 0 # Listener is running fine fi # We're not supposed to be running, and we are, # in fact, not running. Return 3 if [ $subsys_lock -ne 0 ]; then return 3 fi # Listener is NOT running (but should be) - try to restart for (( i=$RESTART_RETRIES ; i; i-- )) ; do initlog -n $SCRIPT -q -s "Restarting Oracle listener ($LISTENER)" lsnrctl start $LISTENER lsnrctl status $LISTENER >& /dev/null if [ $? == 0 ] ; then break # Listener was (re)started and is running fine fi done if [ $i -eq 0 ]; then # stop/start's failed - return 1 (failure) initlog -n $SCRIPT -q -s "Listener restart failed, retuning 1" return 1 fi lsnrctl status $LISTENER >& /dev/null if [ $? != 0 ] ; then initlog -n $SCRIPT -q -s "Listener status failed, retuning 1" return 1 # Problem restarting the Listener fi return 0 # Success restarting the Listener } # # Helps us keep a running status so we know what our ultimate return # code will be. Returns 1 if the $1 and $2 are not equivalent, otherwise # returns $1. The return code is meant to be the next $1 when this is # called, so, for example: # # update_status 0 <-- returns 0 # update_status $? 0 <-- returns 0 # update_status $? 3 <-- returns 1 (values different - error condition) # update_status $? 1 <-- returns 1 (same, but happen to be error state!) # # update_status 3 # update_status $? 3 <-- returns 3 # # (and so forth...) # update_status() { declare -i old_status=$1 declare -i new_status=$2 if [ -z "$2" ]; then return $old_status fi if [ $old_status -ne $new_status ]; then initlog -n $SCRIPT -q -s "$old_status vs $new_status - returning 1" return 1 fi return $old_status } # # Print an error message to the user and exit. # oops() { #echo "Please configure this script ($0) to" #echo "match your installation." #echo #echo " $1 failed validation checks." initlog -n $SCRIPT -q -s "$1 failed validation checks" exit 1 } # # Do some validation on the user-configurable stuff at the beginning of the # script. # validation_checks() { # If the oracle user doesn't exist, we're done. [ -n "$ORACLE_USER" ] || oops "ORACLE_USER" id -u $ORACLE_USER > /dev/null || oops "ORACLE_USER" id -g $ORACLE_USER > /dev/null || oops "ORACLE_USER" # If the oracle home isn't a directory, we're done [ -n "$ORACLE_HOME" ] || oops ORACLE_HOME # If the oracle SID is NULL, we're done [ -n "$ORACLE_SID" ] || oops ORACLE_SID # Super user? Automatically change UID and exec as oracle user. # Oracle needs to be run as the Oracle user, not root! if [ "`id -u`" = "0" ]; then su $ORACLE_USER -c "$0 $*" exit $? fi # If we're not root and not the Oracle user, we're done. [ "`id -u`" = "`id -u $ORACLE_USER`" ] || exit 1 [ "`id -g`" = "`id -g $ORACLE_USER`" ] || exit 1 # Go home. cd $ORACLE_HOME return 0 } # # Start Oracle # start_oracle() { initlog -n $SCRIPT -q -s "Starting Oracle Database" start_db || return 1 for LISTENER in ${LISTENERS}; do logfile=/tmp/$SCRIPT-lsn-$$.log initlog -n $SCRIPT -q -s "Starting Oracle Listener $LISTENER" lsnrctl start $LISTENER > $logfile initlog -q -c "cat $logfile" rm -f $logfile done if [ -n "$LOCKFILE" ]; then touch $LOCKFILE fi return 0 } # # Stop Oracle # stop_oracle() { if ! [ -e "$ORACLE_HOME/bin/lsnrctl" ]; then initlog -n $SCRIPT -q -s "Oracle Listener Control is not available ($ORACLE_HOME not mounted?)" return 0 fi initlog -n $SCRIPT -q -s "Stopping Oracle Database" stop_db || return 1 for LISTENER in ${LISTENERS}; do initlog -n $SCRIPT -q -s "Stopping Oracle Listener $LISTENER" lsnrctl stop $LISTENER done initlog -n $SCRIPT -q -s "Waiting for all Oracle processes to exit" exit_idle if [ $? -ne 0 ]; then initlog -n $SCRIPT -q -s "WARNING: Not all Oracle processes exited cleanly" fi if [ -n "$LOCKFILE" ]; then rm -f $LOCKFILE fi return 0 } # # Find and display the status of iAS infrastructure. # # This has three parts: # (1) Oracle database itself # (2) Oracle listener process # (3) OPMN and OPMN-managed processes # # - If all are (cleanly) down, we return 3. In order for this to happen, # $LOCKFILE must not exist. In this case, we try and restart certain parts # of the service - as this may be running in a clustered environment. # # - If some but not all are running (and, if $LOCKFILE exists, we could not # restart the failed portions), we return 1 (ERROR) # # - If all are running, return 0. In the "all-running" case, we recreate # $LOCKFILE if it does not exist. # status_oracle() { declare -i subsys_lock=1 declare -i last declare -i depth=$1 # Check for lock file. Crude and rudimentary, but it works if [ -z "$LOCKFILE" ] || [ -f $LOCKFILE ]; then subsys_lock=0 fi # Check database status get_db_status $subsys_lock $depth update_status $? # Start last=$? # Check & report listener status for LISTENER in ${LISTENERS}; do get_lsnr_status $subsys_lock $depth $LISTENER update_status $? $last last=$? done # No lock file, but everything's running. Put the lock # file back. XXX - this kosher? if [ $last -eq 0 ] && [ $subsys_lock -ne 0 ]; then touch $LOCKFILE fi return $last } ######################## # Do some real work... # ######################## case $1 in meta-data) cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'` exit 0 ;; start) validation_checks $* start_oracle exit $? ;; stop) validation_checks $* stop_oracle exit $? ;; status|monitor) validation_checks $* status_oracle $OCF_CHECK_LEVEL exit $? ;; restart) $0 stop || exit $? $0 start || exit $? exit 0 ;; *) echo "usage: $SCRIPT {start|stop|restart|status|monitor|meta-data}" exit 1 ;; esac exit 0 diff --git a/rgmanager/src/resources/utils/fs-lib.sh b/rgmanager/src/resources/utils/fs-lib.sh index 3bc7cacd8..d026f8385 100644 --- a/rgmanager/src/resources/utils/fs-lib.sh +++ b/rgmanager/src/resources/utils/fs-lib.sh @@ -1,1005 +1,1007 @@ #!/bin/bash # # Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved. # Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # File system common functions # LC_ALL=C LANG=C PATH=/bin:/sbin:/usr/bin:/usr/sbin export LC_ALL LANG PATH # Private return codes FAIL=2 NO=1 YES=0 YES_STR="yes" [ -z "$OCF_RESOURCE_INSTANCE" ] && export OCF_RESOURCE_INSTANCE="filesystem:$OCF_RESKEY_name" # # Using a global to contain the return value saves # clone() operations. This is important to reduce # resource consumption during status checks. # # There is no way to return a string from a function # in bash without cloning the process, which is exactly # what we are trying to avoid. So, we have to resort # to using a dedicated global variable. This one is # for the real_device() function below. # declare REAL_DEVICE # # Stub ocf_log function for when we are using # quick_status, since ocf_log generally forks (and # sourcing ocf-shellfuncs forks -a lot-). # ocf_log() { echo $* } # # Assume NFS_TRICKS are not available until we are # proved otherwise. # export NFS_TRICKS=1 # # Quick status doesn't fork() or clone() when using # device files directly. (i.e. not symlinks, LABEL= or # UUID= # if [ "$1" = "status" -o "$1" = "monitor" ] && [ "$OCF_RESKEY_quick_status" = "1" ]; then echo Using Quick Status # XXX maybe we can make ocf-shellfuncs have a 'quick' mode too? export OCF_SUCCESS=0 export OCF_ERR_GENERIC=1 else # # Grab nfs lock tricks if available # if [ -f "$(dirname $0)/svclib_nfslock" ]; then . $(dirname $0)/svclib_nfslock NFS_TRICKS=0 fi . $(dirname $0)/ocf-shellfuncs fi verify_name() { if [ -z "$OCF_RESKEY_name" ]; then ocf_log err "No file system name specified." return $OCF_ERR_ARGS fi return $OCF_SUCCESS } verify_mountpoint() { if [ -z "$OCF_RESKEY_mountpoint" ]; then ocf_log err "No mount point specified." return $OCF_ERR_ARGS fi if ! [ -e "$OCF_RESKEY_mountpoint" ]; then ocf_log info "Mount point $OCF_RESKEY_mountpoint will be "\ "created at mount time." return $OCF_SUCCESS fi [ -d "$OCF_RESKEY_mountpoint" ] && return $OCF_SUCCESS ocf_log err "$OCF_RESKEY_mountpoint exists but is not a directory." return $OCF_ERR_ARGS } # # This used to be called using $(...), but doing this causes bash # to set up a pipe and clone(). So, the output of this function is # stored in the global variable REAL_DEVICE, declared previously. # real_device() { declare dev="$1" declare realdev REAL_DEVICE="" [ -z "$dev" ] && return $OCF_ERR_ARGS # Oops, we have a link. Sorry, this is going to fork. if [ -h "$dev" ]; then realdev=$(readlink -f $dev) if [ $? -ne 0 ]; then return $OCF_ERR_ARGS fi REAL_DEVICE="$realdev" return $OCF_SUCCESS fi # If our provided blockdev is a device, we are done if [ -b "$dev" ]; then REAL_DEVICE="$dev" return $OCF_SUCCESS fi # It's not a link, it's not a block device. If it also # does not match UUID= or LABEL=, then findfs is not # going to find anything useful, so we should quit now. if [ "${dev/UUID=/}" = "$dev" ] && [ "${dev/LABEL=/}" = "$dev" ]; then return $OCF_ERR_GENERIC fi # When using LABEL= or UUID=, we can't save a fork. realdev=$(findfs "$dev" 2> /dev/null) if [ -n "$realdev" ] && [ -b "$realdev" ]; then REAL_DEVICE="$realdev" return $OCF_SUCCESS fi return $OCF_ERR_GENERIC } verify_device() { declare realdev if [ -z "$OCF_RESKEY_device" ]; then ocf_log err "No device or label specified." return $OCF_ERR_ARGS fi real_device "$OCF_RESKEY_device" realdev="$REAL_DEVICE" if [ -n "$realdev" ]; then if [ "$realdev" != "$OCF_RESKEY_device" ]; then ocf_log info "Specified $OCF_RESKEY_device maps to $realdev" fi return $OCF_SUCCESS fi ocf_log err "Device or label \"$OCF_RESKEY_device\" not valid" return $OCF_ERR_ARGS } # # mount_in_use device mount_point # # Check to see if either the device or mount point are in use anywhere on # the system. It is not required that the device be mounted on the named # moint point, just if either are in use. # mount_in_use () { declare mp tmp_mp declare dev tmp_dev declare junka junkb junkc junkd if [ $# -ne 2 ]; then ocf_log err "Usage: mount_in_use device mount_point". return $FAIL fi dev="$1" mp="$2" while read -r tmp_dev tmp_mp junka junkb junkc junkd; do # XXX fork/clone warning XXX if [ "${tmp_dev:0:1}" != "-" ]; then tmp_dev="$(printf "$tmp_dev")" fi if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then case $OCF_RESKEY_fstype in cifs|nfs|nfs4) ;; *) return $YES ;; esac fi # Mountpoint from /proc/mounts containing spaces will # have spaces represented in octal. printf takes care # of this for us. tmp_mp="$(printf "$tmp_mp")" if [ -n "$tmp_mp" -a "$tmp_mp" = "$mp" ]; then return $YES fi done < /proc/mounts return $NO } # # is_mounted device mount_point # # Check to see if the device is mounted. Print a warning if its not # mounted on the directory we expect it to be mounted on. # is_mounted () { declare mp tmp_mp declare dev tmp_dev declare ret=$FAIL declare found=1 declare poss_mp if [ $# -ne 2 ]; then ocf_log err "Usage: is_mounted device mount_point" return $FAIL fi real_device "$1" dev="$REAL_DEVICE" if [ -z "$dev" ]; then ocf_log err "$OCF_RESOURCE_INSTANCE: is_mounted: Could not match $1 with a real device" return $OCF_ERR_ARGS fi if [ -h "$2" ]; then mp="$(readlink -f $2)" else mp="$2" fi ret=$NO # This bash glyph simply removes a trailing slash # if one exists. /a/b/ -> /a/b; /a/b -> /a/b. mp="${mp%/}" while read -r tmp_dev tmp_mp junk_a junk_b junk_c junk_d do # XXX fork/clone warning XXX if [ "${tmp_dev:0:1}" != "-" ]; then tmp_dev="$(printf "$tmp_dev")" fi real_device "$tmp_dev" tmp_dev="$REAL_DEVICE" # XXX fork/clone warning XXX # Mountpoint from /proc/mounts containing spaces will # have spaces represented in octal. printf takes care # of this for us. tmp_mp="$(printf "$tmp_mp")" if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then # # Check to see if its mounted in the right # place # if [ -n "$tmp_mp" ]; then if [ "$tmp_mp" != "$mp" ]; then poss_mp=$tmp_mp else found=0 fi fi ret=$YES fi done < /proc/mounts if [ $ret -eq $YES ] && [ $found -ne 0 ]; then case $OCF_RESKEY_fstype in cifs|nfs|nfs4) ret=$NO ;; *) ocf_log warn "Device $dev is mounted on $poss_mp instead of $mp" ;; esac fi return $ret } # # is_alive mount_point # # Check to see if mount_point is alive (testing read/write) # is_alive() { declare errcode declare mount_point="$1" declare file=".writable_test.$(hostname)" declare rw if [ $# -ne 1 ]; then ocf_log err "Usage: is_alive mount_point" return $FAIL fi [ -z "$OCF_CHECK_LEVEL" ] && export OCF_CHECK_LEVEL=0 test -d "$mount_point" if [ $? -ne 0 ]; then ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: $mount_point is not a directory" return $FAIL fi [ $OCF_CHECK_LEVEL -lt 10 ] && return $YES # depth 10 test (read test) ls "$mount_point" > /dev/null 2> /dev/null errcode=$? if [ $errcode -ne 0 ]; then ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed read test on [$mount_point]. Return code: $errcode" return $NO fi [ $OCF_CHECK_LEVEL -lt 20 ] && return $YES # depth 20 check (write test) rw=$YES for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do if [ "$o" = "ro" ]; then rw=$NO fi done if [ $rw -eq $YES ]; then file="$mount_point"/$file while true; do if [ -e "$file" ]; then file=${file}_tmp continue else break fi done touch $file > /dev/null 2> /dev/null errcode=$? if [ $errcode -ne 0 ]; then ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed write test on [$mount_point]. Return code: $errcode" return $NO fi rm -f $file > /dev/null 2> /dev/null fi return $YES } # # Decide which quota options are enabled and return a string # which we can pass to quotaon # quota_opts() { declare quotaopts="" declare opts="$1" declare mopt for mopt in `echo $opts | sed -e s/,/\ /g`; do case $mopt in quota) quotaopts="gu" break ;; usrquota) quotaopts="u$quotaopts" continue ;; grpquota) quotaopts="g$quotaopts" continue ;; noquota) quotaopts="" return 0 ;; esac done echo $quotaopts return 0 } # # Enable quotas on the mount point if the user requested them # enable_fs_quotas() { declare -i need_check=0 declare -i rv declare quotaopts="" declare mopt declare opts="$1" declare mp="$2" if ! type quotaon &> /dev/null; then ocf_log err "quotaon not found in $PATH" return $OCF_ERR_GENERIC fi quotaopts=$(quota_opts $opts) [ -z "$quotaopts" ] && return 0 ocf_log debug "quotaopts = $quotaopts" # Ok, create quota files if they don't exist for f in quota.user aquota.user quota.group aquota.group; do if ! [ -f "$mp/$f" ]; then ocf_log info "$mp/$f was missing - creating" touch "$mp/$f" chmod 600 "$mp/$f" need_check=1 fi done if [ $need_check -eq 1 ]; then ocf_log info "Checking quota info in $mp" quotacheck -$quotaopts "$mp" fi ocf_log info "Enabling Quotas on $mp" ocf_log debug "quotaon -$quotaopts \"$mp\"" quotaon -$quotaopts "$mp" rv=$? if [ $rv -ne 0 ]; then # Just a warning ocf_log warn "Unable to turn on quotas for $mp; return = $rv" fi return $rv } # Agent-specific actions to take before mounting # (if required). Typically things like fsck. do_pre_mount() { return 0 } # Default mount handler - for block devices # do_mount() { declare dev="$1" declare mp="$2" declare mount_options="" declare fstype_option="" declare fstype # # Get the filesystem type, if specified. # fstype_option="" fstype=${OCF_RESKEY_fstype} case "$fstype" in ""|"[ ]*") fstype="" ;; *) # found it fstype_option="-t $fstype" ;; esac # # Get the mount options, if they exist. # mount_options="" opts=${OCF_RESKEY_options} case "$opts" in ""|"[ ]*") opts="" ;; *) # found it mount_options="-o $opts" ;; esac # # Mount the device # ocf_log info "mounting $dev on $mp" ocf_log err "mount $fstype_option $mount_options $dev $mp" mount $fstype_option $mount_options "$dev" "$mp" ret_val=$? if [ $ret_val -ne 0 ]; then ocf_log err "\ 'mount $fstype_option $mount_options $dev $mp' failed, error=$ret_val" return 1 fi return 0 } # Agent-specific actions to take after mounting # (if required). do_post_mount() { return 0 } # Agent-specific actions to take before unmounting # (if required) do_pre_unmount() { return 0 } # Agent-specific actions to take after umount succeeds # (if required) do_post_unmount() { return 0 } # Agent-specific force-unmount logic, if required # return = nonzero if successful, or 0 if unsuccessful # (unsuccessful = try harder) do_force_unmount() { return 1 } # # start_filesystem # start_filesystem() { declare -i ret_val=$OCF_SUCCESS declare mp="${OCF_RESKEY_mountpoint}" declare dev="" # device declare fstype="" declare opts="" declare mount_options="" # # Check if mount point was specified. If not, no need to continue. # case "$mp" in ""|"[ ]*") # nothing to mount return $OCF_SUCCESS ;; /*) # found it ;; *) # invalid format ocf_log err \ "start_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'" return $OCF_ERR_ARGS ;; esac # # Get the device # real_device "$OCF_RESKEY_device" dev="$REAL_DEVICE" if [ -z "$dev" ]; then ocf_log err "\ start_filesystem: Could not match $OCF_RESKEY_device with a real device" return $OCF_ERR_ARGS fi # # Ensure we've got a valid directory # if [ -e "$mp" ]; then if ! [ -d "$mp" ]; then ocf_log err"\ start_filesystem: Mount point $mp exists but is not a directory" return $OCF_ERR_ARGS fi else ocf_log err "\ start_filesystem: Creating mount point $mp for device $dev" mkdir -p "$mp" ret_val=$? if [ $ret_val -ne 0 ]; then ocf_log err "\ start_filesystem: Unable to create $mp. Error code: $ret_val" return $OCF_ERR_GENERIC fi fi # # See if the device is already mounted. # is_mounted "$dev" "$mp" case $? in $YES) # already mounted ocf_log debug "$dev already mounted" return $OCF_SUCCESS ;; $NO) # not mounted, continue ;; *) return $FAIL ;; esac # # Make sure that neither the device nor the mount point are mounted # (i.e. they may be mounted in a different location). The'mount_in_use' # function checks to see if either the device or mount point are in # use somewhere else on the system. # mount_in_use "$dev" "$mp" case $? in $YES) # uh oh, someone is using the device or mount point ocf_log err "\ Cannot mount $dev on $mp, the device or mount point is already in use!" return $FAIL ;; $NO) # good, no one else is using it ;; $FAIL) return $FAIL ;; *) ocf_log err "Unknown return from mount_in_use" return $FAIL ;; esac do_pre_mount case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) return $OCF_SUCCESS ;; esac do_mount "$dev" "$mp" case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) return $OCF_SUCCESS ;; esac do_post_mount case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) return $OCF_SUCCESS ;; esac enable_fs_quotas "$opts" "$mp" return $OCF_SUCCESS } # # stop_filesystem - unmount a file system; calls out to # stop_filesystem() { declare -i ret_val=0 declare -i try declare -i sleep_time=5 # time between each umount failure declare umount_failed="" declare force_umount="" declare self_fence="" declare quotaopts="" # # Get the mount point, if it exists. If not, no need to continue. # mp=${OCF_RESKEY_mountpoint} case "$mp" in ""|"[ ]*") # nothing to mount return $OCF_SUCCESS ;; /*) # found it ;; *) # invalid format ocf_log err \ "stop_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'" return $FAIL ;; esac # # Get the device # real_device "$OCF_RESKEY_device" dev="$REAL_DEVICE" if [ -z "$dev" ]; then ocf_log err "\ stop: Could not match $OCF_RESKEY_device with a real device" return $FAIL fi # # Get the force unmount setting if there is a mount point. # case ${OCF_RESKEY_force_unmount} in $YES_STR) force_umount=$YES ;; on) force_umount=$YES ;; true) force_umount=$YES ;; 1) force_umount=$YES ;; *) force_umount="" ;; esac case ${OCF_RESKEY_self_fence} in $YES_STR) self_fence=$YES ;; on) self_fence=$YES ;; true) self_fence=$YES ;; 1) self_fence=$YES ;; *) self_fence="" ;; esac do_pre_unmount case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) return $OCF_SUCCESS ;; esac # # Preparations: sync, turn off quotas # sync quotaopts=$(quota_opts $OCF_RESKEY_options) if [ -n "$quotaopts" ]; then ocf_log debug "Turning off quotas for $mp" quotaoff -$quotaopts "$mp" &> /dev/null fi # # Unmount the device. # for try in 1 2 3; do if [ $try -ne 1 ]; then sleep $sleep_time fi is_mounted "$dev" "$mp" case $? in $NO) ocf_log info "$dev is not mounted" umount_failed= break ;; $YES) # fallthrough ;; *) return $FAIL ;; esac ocf_log info "unmounting $mp" umount "$mp" ret_val=$? - if [ $ret_val -eq 0 ]; then + # some versions of umount will exit with status 16 iff + # the umount(2) succeeded but /etc/mtab could not be written. + if [ $ret_val -eq 0 -o $ret_val -eq 16 ]; then umount_failed= break fi ocf_log debug "umount failed: $ret_val" umount_failed=yes if [ -z "$force_umount" ]; then continue fi # Force unmount: try #1: send SIGTERM if [ $try -eq 1 ]; then # Try fs-specific force-unmount, if provided do_force_unmount if [ $? -eq 0 ]; then # if this succeeds, we should be done continue fi ocf_log warning "Sending SIGTERM to processes on $mp" fuser -TERM -kvm "$mp" continue else ocf_log warning "Sending SIGKILL to processes on $mp" fuser -kvm "$mp" case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) break ;; esac fi done # for do_post_unmount case $? in 0) ;; 1) return $OCF_ERR_GENERIC ;; 2) return $OCF_SUCCESS ;; esac if [ -n "$umount_failed" ]; then ocf_log err "'umount $mp' failed, error=$ret_val" if [ "$self_fence" ]; then ocf_log alert "umount failed - REBOOTING" sync reboot -fn fi return $OCF_ERR_GENERIC fi return $OCF_SUCCESS } do_start() { declare tries=0 declare rv while [ $tries -lt 3 ]; do start_filesystem rv=$? if [ $rv -eq 0 ]; then return 0 fi ((tries++)) sleep 3 done return $rv } do_stop() { stop_filesystem return $? } do_monitor() { # # Get the device # real_device "$OCF_RESKEY_device" dev="$REAL_DEVICE" if [ -z "$dev" ]; then ocf_log err "\ start_filesystem: Could not match $OCF_RESKEY_device with a real device" return $OCF_NOT_RUNNING fi is_mounted "$dev" "${OCF_RESKEY_mountpoint}" if [ $? -ne $YES ]; then ocf_log err "${OCF_RESOURCE_INSTANCE}: ${OCF_RESKEY_device} is not mounted on ${OCF_RESKEY_mountpoint}" return $OCF_NOT_RUNNING fi if [ "$OCF_RESKEY_quick_status" = "1" ]; then return 0 fi is_alive "${OCF_RESKEY_mountpoint}" [ $? -eq $YES ] && return 0 ocf_log err "fs:${OCF_RESKEY_name}: Mount point is not accessible!" return $OCF_ERR_GENERIC } do_restart() { stop_filesystem if [ $? -ne 0 ]; then return $OCF_ERR_GENERIC fi start_filesystem if [ $? -ne 0 ]; then return $OCF_ERR_GENERIC fi return 0 } # MUST BE OVERRIDDEN do_metadata() { return 1 } do_validate() { return 1 } main() { case $1 in start) do_start exit $? ;; stop) do_stop exit $? ;; status|monitor) do_monitor exit $? ;; restart) do_restart exit $? ;; meta-data) do_metadata exit $? ;; validate-all) do_validate ;; *) echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}" exit $OCF_ERR_UNIMPLEMENTED ;; esac exit 0 }