Home | History | Annotate | Download | only in nfsv4
      1 #
      2 # CDDL HEADER START
      3 #
      4 # The contents of this file are subject to the terms of the
      5 # Common Development and Distribution License (the "License").
      6 # You may not use this file except in compliance with the License.
      7 #
      8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9 # or http://www.opensolaris.org/os/licensing.
     10 # See the License for the specific language governing permissions
     11 # and limitations under the License.
     12 #
     13 # When distributing Covered Code, include this CDDL HEADER in each
     14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15 # If applicable, add the following below this CDDL HEADER, with the
     16 # fields enclosed by brackets "[]" replaced with your own identifying
     17 # information: Portions Copyright [yyyy] [name of copyright owner]
     18 #
     19 # CDDL HEADER END
     20 #
     21 
     22 #
     23 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24 # Use is subject to license terms.
     25 #
     26 # ident	"@(#)libsmf.sh	1.1	08/10/20 SMI"
     27 #
     28 
     29 smf_installed_fn() { # void
     30     #
     31     #  		Will return 0 if smf appears to be installed and should be
     32     #  		usable, otherwise it will return != 0.
     33     #
     34     #  		This function will check and rely on the presence or absence
     35     #  		of /lib/svc/share/smf_include.sh.
     36     #
     37 
     38     # Some debugging stuff....
     39 
     40     echo :${__DEBUG}: | /usr/xpg4/bin/grep -q ':smf_cmd_FMRI_wait:' && \
     41 	set -v && \
     42 	set -x
     43 
     44     [ ! -r /lib/svc/share/smf_include.sh ] && return 1
     45 
     46     . /lib/svc/share/smf_include.sh
     47     smf_present
     48 
     49 }
     50 
     51 _scFw_children_of_fn() { # pid
     52 
     53     /bin/ptree $1 | \
     54 	/bin/awk "BEGIN {seen=0;} { if ( \$1 == $1 ) seen=1;} \
     55 		(seen == 1) {print \$1}"
     56 
     57 }
     58 
     59 _scFw_cleanup_fn() {
     60 
     61     ##########################################################
     62     #
     63     #		This function is private -- Hands off!
     64     #
     65     ##########################################################
     66 
     67 	# Some debugging stuff....
     68 
     69 	echo :${__DEBUG}: | /usr/xpg4/bin/grep -q 'smf_cmd_FMRI_wait::' && \
     70 	    set -v && \
     71 	    set -x
     72 
     73 	# Clean up whatever has been created.
     74 
     75 	if [ -n "$scFw_timeout_id" ]; then
     76 	    echo :${__DEBUG}: | /usr/xpg4/bin/grep -q ':smf_cmd_FMRI_wait:' && \
     77 		/bin/ptree $scFw_timeout_id
     78 
     79 	    pl=`_scFw_children_of_fn $scFw_timeout_id`
     80 	    [ -n "$pl" ] && kill -9 $pl > /dev/null 2>&1
     81 
     82 	fi
     83 	if [ -n "$scFw_svcprop_id" ]; then
     84 	    echo :${__DEBUG}: | /usr/xpg4/bin/grep -q 'smf_cmd_FMRI_wait::' && \
     85 		 /bin/ptree $scFw_svcprop_id
     86 
     87 	    pl=`_scFw_children_of_fn $scFw_svcprop_id`
     88 	    [ -n "$pl" ] && kill -9 $pl > /dev/null 2>&1
     89 
     90 	fi
     91 
     92 	[ -n "$scFw_FIFO" ] && /bin/rm -f $scFw_FIFO
     93 
     94 }
     95 
     96 smf_cmd_FMRI_wait_fn() { # [-v] "quoted command" FMRI status timeout
     97     #
     98     #		Will invoke the quoted command, then use svcprop -w to wait
     99     #		for up to timeout seconds for the restarter/state property of
    100     #		the FMRI named to have the status passed. The command may be
    101     #		empty, and the timeout may be 0 to indicate not to wait or -1
    102     #		to indicate a wait forever.
    103     #
    104     #		'$FMRI' embedded within the quoted command will be replaced
    105     #		with the FMRI parameter passed to this function. Note: Since
    106     #		'$FMRI' references a shell variable, the '$' must be suitably
    107     #		escaped or redundantly quoted to ensure that it remains intact
    108     #		until substitution occurs when the quoted command is
    109     #		invoked. e.g. smf_cmd_FMRI_wait "svcadm enable \$FMRI" svc:."
    110     #
    111     #		-v will enable progress messages.
    112     #
    113     #		If the quoted command returns 0, and the FMRI named reaches
    114     #		the state specified within the timeout allowed, then
    115     #		smf_cmd_FMRI_wait will return 0.
    116     #
    117     #		If the quoted command does not return 0, then
    118     #		smf_cmd_FMRI_wait will return the value returned by the
    119     #		command.
    120     #
    121     #		If the FMRI status changes, but does not match the specified
    122     #		status, then smf_cmd_FMRI_wait will return 35 (ENOMSG).
    123     #
    124     #		If the FMRI status does not change within the timeout
    125     #		specified, then smf_cmd_FMRI_wait will return 62 (ETIME).
    126     #
    127     #		If SMF does not appear to be installed, then smf_cmd_FMRI_wait
    128     #		will return 2 (ENOENT).
    129     #
    130     #		If invalid or insufficient parameters are passed, then
    131     #		smf_cmd_FMRI_wait will return 22 (EINVAL).
    132     #
    133     #		If this routine is interrupted by the user then
    134     #		smf_cmd_FMRI_wait will return 4 (EINTR).
    135     #
    136 
    137     # Some debugging stuff....
    138 
    139     echo :${__DEBUG}: | /usr/xpg4/bin/grep -q ':smf_cmd_FMRI_wait:' && \
    140 	set -v && \
    141 	set -x
    142 
    143     # Collect my parameters....
    144 
    145     scFw_verbose=0
    146     if [ x:-v = x:$1 ]; then
    147 	shift
    148 	scFw_verbose=1
    149 
    150     fi
    151 
    152     [ ${#} -ne 4 ] && return 22
    153 
    154     cmd="$1"
    155     FMRI=$2
    156     FMRI_status=$3
    157     timeout=$4
    158 
    159     scFw_interrupted=0
    160     export scFw_interrupted
    161 
    162     svcprop_w_cmd="/bin/svcprop -w -p restarter/state $FMRI"
    163     svcprop_cmd="/bin/svcprop -p restarter/state $FMRI"
    164 
    165     # Make sure smf is installed, and usable...
    166 
    167     smf_installed_fn || return 2
    168 
    169     # Catch errors.
    170 
    171     trap "_scFw_cleanup_fn; scFw_interrupted=1; trap 2" 2
    172 
    173     # Execute the command. If it returns non-zero, then clean up and bail!
    174 
    175     eval $cmd
    176     status=$?
    177 
    178     if [ $status -ne 0 ]; then
    179 	_scFw_cleanup_fn
    180 	return $status
    181 
    182     fi
    183 
    184     # Spawn a timer to wait for the status change.
    185 
    186     scFw_FIFO=/tmp/smf_cmd_FMRI_wait.FIFO.$$
    187 
    188     /bin/rm -f $scFw_FIFO
    189     /bin/mkfifo $scFw_FIFO || return
    190 
    191     (/bin/sleep $timeout; echo ETIME) > $scFw_FIFO < /dev/null &
    192     status=$?
    193     scFw_timeout_id=$!
    194 
    195     if [ $status -ne 0 ]; then
    196 	_scFw_cleanup_fn
    197 	return $status
    198 
    199     fi
    200 
    201     # Start a svcprop -w to wait for the property to change.
    202 
    203     $svcprop_w_cmd > $scFw_FIFO < /dev/null &
    204     status=$?
    205     scFw_svcprop_id=$!
    206 
    207     if [ $status -ne 0 ]; then
    208 	_scFw_cleanup_fn
    209 	return $status
    210 
    211     fi 
    212 
    213     # Before waiting, see if the state is already what was expected. It might
    214     # have changed before the svcprop -w, above, was started.
    215 
    216     while smf_result=`$svcprop_cmd` && \
    217 	[ x:$FMRI_status != x:$smf_result ] && \
    218 	read smf_result < $scFw_FIFO; do
    219 
    220 	# Did the user try to kill this off?
    221 
    222 	if [ $scFw_interrupted -ne 0 ]; then
    223 	    [ $scFw_verbose -ne 0 ] && echo "Interrupted."
    224 	    return 4
    225 
    226 	fi
    227 
    228 	if [ x:$smf_result = "x:ETIME" ]; then
    229 	    _scFw_cleanup_fn
    230 
    231 	    # The sleep timer and svcprop -w may have been racing to the
    232 	    # pipe. So check for the result of the propery change before
    233 	    # actually declaring this a timeout condition.
    234 
    235 	    [ x:$FMRI_status = x:`$svcprop_cmd` ] && return 0
    236 	    [ $scFw_verbose -ne 0 ] && echo "Timeout."
    237 	    return 62
    238 
    239 	fi
    240 
    241 	[ $scFw_verbose -ne 0 ] && echo "$FMRI moved to $smf_result"
    242 
    243 	# So, we've read one status that was not from the timer, so it must
    244 	# have been from the svcprop -w -- need to start another one waiting
    245 	# for the property to change.
    246 
    247 	pl=`_scFw_children_of_fn $scFw_svcprop_id`
    248 	[ -n "$pl" ] && kill -9 $pl > /dev/null 2>&1
    249 	$svcprop_w_cmd > $scFw_FIFO < /dev/null &
    250 	status=$?
    251 	scFw_svcprop_id=$!
    252 
    253 	if [ $status -ne 0 ]; then
    254 	    _scFw_cleanup_fn
    255 	    return $status
    256 
    257 	fi
    258 
    259     done
    260     status=$?
    261     [ $status -eq 0 ] && \
    262 	[ $scFw_verbose -ne 0 ] && \
    263 	echo "$FMRI status is `$svcprop_cmd`"
    264 
    265     _scFw_cleanup_fn
    266     return $status
    267 
    268 }
    269 
    270 smf_get_state() { # fmri
    271 	#
    272 	# prints the current state of the instance specified by the
    273 	# supplied FMRI.  Returns 22 if usage was incorrect.  Otherwise,
    274 	# returns the exit status of svcprop.
    275 
    276 	# Some debugging stuff....
    277 
    278 	echo :${__DEBUG}: | /usr/xpg4/bin/grep -q ':smf_get_state:' && \
    279 		set -v && \
    280 		set -x
    281 
    282 	# check the number of parameters
    283 	[ ${#} -ne 1 ] && return 22
    284 
    285 	fmri="$1"
    286 
    287 	echo "`/usr/bin/svcprop -p restarter/state ${fmri}`"
    288 	return $?
    289 }
    290 
    291 
    292 smf_fmri_transition_state() { # args
    293 	# Usage:
    294 	#	smf_fmri_state_transition "do" $fmri $state $timeout
    295 	# OR
    296 	#	smf_fmri_state_transition "check" $fmri $state $timeout
    297 	#
    298 	# For more details, see the detailed comments at the end of the
    299 	# function, or the README file in the parent directory
    300 
    301 	# Some debugging stuff....
    302 
    303 	echo :${__DEBUG}: | /usr/xpg4/bin/grep -q ':smf_fmri_transition_state:' && \
    304 		set -v && \
    305 		set -x
    306 
    307 	# check the number of parameters
    308 	[ ${#} -ne 4 ] && return 22
    309 
    310 	# Get the input parameters
    311 	sfts_do_or_check=$1
    312 	sfts_target_fmri=$2
    313 	sfts_target_state=$3
    314 	sfts_timeout=$4
    315 
    316 	# Short-circuit the proceedings if already in the target state
    317 	[ "`smf_get_state $sfts_target_fmri`" = "$sfts_target_state" ] && \
    318 		return 0
    319 
    320 	# if the user requested that we *do* (v/s *check*) the transition, then,
    321 	# just do it!
    322 	if [ "$sfts_do_or_check" != "check" ]; then
    323 		# determine the relevant svcadm subcommand to issue
    324 		sfts_svcadm_subcmd="disable"
    325 		case $sfts_target_state in
    326 			online) sfts_svcadm_subcmd="enable -s" ;;
    327 			offline|disabled) sfts_svcadm_subcmd="disable -s" ;;
    328 			maintenance|degraded)
    329 				sfts_svcadm_subcmd="mark -I $sfts_target_state"	;;
    330 			clear) sfts_svcadm_subcmd="clear" ;;
    331 			refresh) sfts_svcadm_subcmd="$sfts_target_state"
    332 				sfts_target_state="`smf_get_state $fmri`"
    333 				;;
    334 			restart) sfts_svcadm_subcmd="$sfts_target_state"
    335 				sfts_target_state="online"
    336 				if [ `smf_get_state $sfts_target_fmri` = "maintenance" ]; then
    337 					sfts_target_state="maintenance"
    338 				fi
    339 				;;
    340 			*) return 22 ;;
    341 		esac
    342 
    343 		# Invoke svcadm to perform the required state transition
    344 		/usr/sbin/svcadm $sfts_svcadm_subcmd $sfts_target_fmri
    345 		if [ $? -ne 0 ]; then
    346             # svcadm invocation failed
    347             return 2
    348         fi
    349 
    350     fi # if $stfs_do_or_check != check
    351 
    352 	# 'clear' subcommand needs special handling: we can't predict what
    353 	# the next state should be; just that it shouldn't be maintenance
    354 	if [ "$sfts_target_state" = "clear" ]; then
    355 		/bin/sleep 1
    356 		[ "`smf_get_state $sfts_target_fmri`" != "maintenance" ] && \
    357 			return 0 || return 1
    358 	fi
    359 
    360 	# For all other subcommands, loop until the desired state is reached
    361 	# or timeout expires
    362     sfts_waited_time=0
    363     while [ $sfts_waited_time -lt $sfts_timeout -a \
    364         "`smf_get_state $sfts_target_fmri`" != "$sfts_target_state" ]
    365     do
    366         /bin/sleep 1
    367         sfts_waited_time=`/bin/expr $sfts_waited_time + 1`
    368     done
    369 
    370     # Give the FMRI one more chance to complete the transition
    371     if [ "`smf_get_state $sfts_target_fmri`" != "$sfts_target_state" ]; then
    372 		# timed out
    373 		return 1
    374     fi
    375 
    376     return 0
    377 	# END
    378 
    379 	# DEVELOPER NOTES:
    380 	# ================
    381 	# Usage:
    382 	#
    383 	# This function can be used in two modes: 
    384 	#	(1) as a utility that waits for the specified state transition to occur
    385 	#	(2) as a tool that affects the desired state transition
    386 	#
    387 	# Invocation:
    388 	# -----------
    389 	# (1) "check" (waiter-only) mode
    390 	#		smf_fmri_transition_state "check" $fmri $state $timeout
    391 	# (2) "do" mode: 
    392 	#		smf_fmri_transition_state "do" $fmri $state $timeout
    393 	#
    394 	# In the 'check' mode, the function merely waits for the target fmri
    395 	# to attain the desired state in the specified timeout (seconds).  It
    396 	# is up to the invoking process to ensure the issuance of appropriate
    397 	# svcadm commands to actually affect the desired state transition.
    398 	# In the 'do' mode, the function itself issues an svcadm command to 
    399 	# cause the state transition to the desired state and then waits for
    400 	# the fmri to reach the desired state in the specified timeout period
    401 	# (seconds).  In both cases, a return status of 0 (zero) indicates 
    402 	# success and a non-zero return status indicates failure.
    403 	#
    404 	# Note that this is a 'state transition' function, not a substitute
    405 	# for svcadm commands.  Specifically, this function does not issue
    406 	# *all* possible svcadm commands; only those that are needed for the
    407 	# desired state transition to be executed as immediately as possible.  
    408 	# For example, the function cannot be told to issue commands such as
    409 	# the following:
    410 	#	svcadm enable -r FMRI    # recursive enable
    411  	# 	svcadm {en,dis}able -t FMRI # temporary
    412  	#	svcadm mark -t maintenance FMRI # temporary
    413 	#
    414 	# However, for one thing, these types of invocations are quite rare,
    415 	# and, for another, when developers need to issue these svcadm sub-
    416 	# commands, they can invoke them explicitly and simply use this 
    417 	# function in the "check" mode.  Alternatively, users are invited to
    418 	# explore the smf_cmd_wait_FMRI function defined elsewhere in this file.
    419 }
    420