rc.subr revision 1.14
1# $NetBSD: rc.subr,v 1.14 2000/04/26 15:06:46 lukem Exp $ 2# 3# Copyright (c) 1997-2000 The NetBSD Foundation, Inc. 4# All rights reserved. 5# 6# This code is derived from software contributed to The NetBSD Foundation 7# by Luke Mewburn. 8# 9# Redistribution and use in source and binary forms, with or without 10# modification, are permitted provided that the following conditions 11# are met: 12# 1. Redistributions of source code must retain the above copyright 13# notice, this list of conditions and the following disclaimer. 14# 2. Redistributions in binary form must reproduce the above copyright 15# notice, this list of conditions and the following disclaimer in the 16# documentation and/or other materials provided with the distribution. 17# 3. All advertising materials mentioning features or use of this software 18# must display the following acknowledgement: 19# This product includes software developed by the NetBSD 20# Foundation, Inc. and its contributors. 21# 4. Neither the name of The NetBSD Foundation nor the names of its 22# contributors may be used to endorse or promote products derived 23# from this software without specific prior written permission. 24# 25# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35# POSSIBILITY OF SUCH DAMAGE. 36# 37# rc.subr 38# functions used by various rc scripts 39# 40 41# 42# functions 43# --------- 44 45# 46# checkyesno var 47# Test $1 variable, and warn if not set to YES or NO. 48# Return 0 if it's "yes" (et al), nonzero otherwise. 49# 50checkyesno() 51{ 52 eval _value=\$${1} 53 case $_value in 54 55 # "yes", "true", "on", or "1" 56 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 57 return 0 58 ;; 59 60 # "no", "false", "off", or "0" 61 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 62 return 1 63 ;; 64 *) 65 warn "\$${1} is not set properly." 66 return 1 67 ;; 68 esac 69} 70 71# 72# mount_critical_filesystems 73# Go through the list of critical filesystems, checking each one 74# to see if it is mounted, and if it is not, mounting it. 75# 76mount_critical_filesystems() 77{ 78 if [ $1 = local ]; then 79 _fslist=$critical_filesystems_beforenet 80 else 81 _fslist=$critical_filesystems 82 fi 83 for fs in $_fslist; do 84 mount | ( 85 ismounted=no 86 while read what _on on _type type; do 87 if [ $on = $fs ]; then 88 ismounted=yes 89 fi 90 done 91 if [ $ismounted = no ]; then 92 mount $fs >/dev/null 2>&1 93 fi 94 ) 95 done 96} 97 98# 99# check_pidfile pidfile procname 100# Parses the first line of pidfile for a pid, and ensures 101# that the process is running and matches procname. 102# Prints the matching pid upon success, nothing otherwise. 103# 104check_pidfile() 105{ 106 _pidfile=$1 107 _procname=$2 108 if [ -z "$_pidfile" -o -z "$_procname" ]; then 109 err 3 'USAGE: check_pidfile pidfile procname' 110 fi 111 if [ ! -f $_pidfile ]; then 112 return 113 fi 114 read _pid _junk < $_pidfile 115 if [ -z "$_pid" ]; then 116 return 117 fi 118 _procnamebn=`basename $_procname` 119 ps -p $_pid -o 'pid,command' | while read _npid _arg0 _argv; do 120 if [ "$_npid" = "PID" ]; then 121 continue 122 fi 123 if [ "$_arg0" = "$_procname" -o "$_arg0" = "$_procnamebn" \ 124 -o "$_arg0" = "${_procnamebn}:" ]; then 125 echo $_npid 126 return 127 fi 128 done 129} 130 131# 132# check_process procname 133# Ensures that a process (or processes) named procname is running. 134# Prints a list of matching pids. 135# 136check_process() 137{ 138 _procname=$1 139 if [ -z "$_procname" ]; then 140 err 3 'USAGE: check_process procname' 141 fi 142 _procnamebn=`basename $_procname` 143 _pref= 144 ps -ax -o 'pid,command' | while read _npid _arg0 _argv; do 145 if [ "$_npid" = "PID" ]; then 146 continue 147 fi 148 if [ "$_arg0" = "$_procname" -o "$_arg0" = "$_procnamebn" \ 149 -o "$_arg0" = "${_procnamebn}:" ]; then 150 echo -n "$_pref$_npid" 151 _pref=" " 152 fi 153 done 154} 155 156# 157# run_rc_command arg [supported_args] 158# Scan supported_args (which has "start stop restart rcvar status" 159# prepended) for arg. 160# If there's a match, run ${arg}_cmd or the default command (see below). 161# 162# If arg has a given prefix, then: 163# prefix operation 164# ------ --------- 165# fast Skip the pid check. 166# force Set ${rcvar} to YES. 167# 168# The following globals are used: 169# name needed function 170# ---- ------ -------- 171# name y Name of script. 172# command n Full path to command. 173# Not needed if ${arg}_cmd is set for 174# each keyword. 175# command_args n Optional args/shell directives for command. 176# pidfile n If set, use check_pidfile $pidfile, else if 177# $command is set, use check_process $command. 178# ${rcvar} n If the default command is being run, this is 179# checked with checkyesno to determine if 180# the action should be run. 181# If this variable isn't set, ${name} is checked 182# instead. 183# ${name}_flags n Arguments to call ${command} with. 184# NOTE: if $flags is set (e.g, from the parent 185# environment), it overrides this. 186# ${_arg}_cmd n If set, use this as the action when invoked; 187# $_arg is available to the action to use. 188# Otherwise, use default command (see below) 189# NOTE: checkyesno ${rcvar} is NOT performed 190# for ${_arg}_cmd; use ${_arg}_precmd to 191# do this. 192# ${_arg}_precmd n If set, run just before performing the main 193# action in the default command (i.e, after 194# checking for required bits and process 195# (non)existance). 196# If this completes with a non-zero exit code, 197# don't run ${_arg}_cmd. 198# required_dirs n If set, check for the existence of the given 199# directories before running the default 200# (re)start command. 201# required_files n If set, check for the readability of the given 202# files before running the default (re)start 203# command. 204# required_vars n If set, perform checkyesno on each of the 205# listed variables before running the default 206# (re)start command. 207# 208# Default commands for a given arg: 209# arg default 210# --- ------- 211# status Show if ${command} is running, etc. 212# start if !running && checkyesno ${rcvar} 213# ${command} 214# stop if ${pidfile} 215# kill $sig_stop `check_pidfile $pidfile` 216# else 217# kill $sig_stop `check_process $command` 218# $sig_stop defaults to TERM. 219# reload As stop, except use $sig_reload instead. 220# $sig_reload defaults to HUP. 221# restart Run `stop' then `start'. 222# 223run_rc_command() 224{ 225 _arg=$1 226 shift 227 _ckvar=${rcvar:-$name} 228 if [ -z "$_ckvar" ]; then 229 err 3 'neither $rcvar or $name is set.' 230 fi 231 232 case "$_arg" in 233 fast*) 234 _arg=${_arg#fast} 235 _rc_fast_run=YES 236 ;; 237 force*) 238 _arg=${_arg#force} 239 eval ${_ckvar}=YES 240 ;; 241 esac 242 243 _keywords="start stop restart rcvar $*" 244 _pidcmd= 245 if [ -z "$_rc_fast_run" ]; then 246 if [ -n "$pidfile" ]; then 247 _pidcmd='_pid=`check_pidfile '$pidfile' '$command'`' 248 elif [ -n "$command" ]; then 249 _pidcmd='_pid=`check_process '$command'`' 250 fi 251 if [ -n "$_pidcmd" ]; then 252 _keywords="${_keywords} status" 253 fi 254 fi 255 256 if [ -z "$_arg" ]; then 257 rc_usage "$_keywords" 258 fi 259 260 if [ -n "$flags" ]; then 261 _flags=$flags 262 else 263 eval _flags=\$${name}_flags 264 fi 265 266 eval $_pidcmd 267 268 for _elem in $_keywords; do 269 if [ "$_elem" != "$_arg" ]; then 270 continue 271 fi 272 273 eval _cmd=\$${_arg}_cmd 274 eval _precmd=\$${_arg}_precmd 275 if [ -n "$_cmd" ]; then 276 eval $_precmd || return 1 277 eval $_cmd 278 return 0 279 fi 280 281 case "$_arg" in 282 283 status) 284 if [ -n "$_pid" ]; then 285 echo "${name} is running as pid $_pid." 286 else 287 echo "${name} is not running." 288 fi 289 ;; 290 291 start) 292 if [ -n "$_pid" ]; then 293 echo "${name} already running? (pid=$_pid)." 294 exit 1 295 fi 296 297 if ! checkyesno ${_ckvar} || [ ! -x $command ]; then 298 return 0 299 fi 300 301 for _f in $required_vars; do 302 if ! checkyesno $_f; then 303 warn \ 304 "\$${_f} is not set; ${name} not started." 305 return 1 306 fi 307 done 308 for _f in $required_dirs; do 309 if [ ! -d "${_f}/." ]; then 310 warn \ 311 "${_f} is not a directory; ${name} not started." 312 return 1 313 fi 314 done 315 for _f in $required_files; do 316 if [ ! -r "${_f}" ]; then 317 warn \ 318 "${_f} is not readable; ${name} not started." 319 return 1 320 fi 321 done 322 323 eval $_precmd || return 1 324 echo "Starting ${name}." 325 eval $command $_flags $command_args 326 ;; 327 328 stop) 329 if [ -z "$_pid" ]; then 330 if checkyesno ${_ckvar}; then 331 if [ -n "$pidfile" ]; then 332 echo \ 333 "${name} not running? (check $pidfile)." 334 else 335 echo "${name} not running?" 336 fi 337 exit 1 338 fi 339 return 0 340 fi 341 342 eval $_precmd || return 1 343 echo "Stopping ${name}." 344 kill -${sig_stop:-TERM} $_pid 345 ;; 346 347 reload) 348 if [ -z "$_pid" ]; then 349 if checkyesno ${_ckvar}; then 350 if [ -n "$pidfile" ]; then 351 echo \ 352 "${name} not running? (check $pidfile)." 353 else 354 echo "${name} not running?" 355 fi 356 exit 1 357 fi 358 return 0 359 fi 360 echo "Reloading ${name} config files." 361 eval $_precmd || return 1 362 kill -${sig_reload:-HUP} $_pid 363 ;; 364 365 restart) 366 if ! checkyesno ${_ckvar}; then 367 return 0 368 fi 369 eval $_precmd || return 1 370 ( $0 stop ) 371 sleep 1 372 $0 start 373 374 ;; 375 376 rcvar) 377 echo "# $name" 378 if checkyesno ${_ckvar}; then 379 echo "\$${_ckvar}=YES" 380 else 381 echo "\$${_ckvar}=NO" 382 fi 383 ;; 384 385 *) 386 rc_usage "$_keywords" 387 ;; 388 389 esac 390 return 0 391 done 392 393 echo 1>&2 "$0: unknown directive '$_arg'." 394 rc_usage "$_keywords" 395 exit 1 396} 397 398# 399# run_rc_script file arg 400# Start the script `file' with `arg', and correctly handle the 401# return value from the script. If `file' ends with `.sh', it's 402# sourced into the current environment. Otherwise it's run as 403# a child process. 404# Note: because `.sh' files are sourced into the current environment 405# run_rc_command shouldn't be used because its difficult to ensure 406# that the global variable state before and after the sourcing of 407# the .sh file won't adversely affect other scripts. 408# 409run_rc_script() 410{ 411 _file=$1 412 _arg=$2 413 if [ -z "$_file" -o -z "$_arg" ]; then 414 err 3 'USAGE: run_rc_script file arg' 415 fi 416 417 _narg=$_arg 418 case "$_narg" in 419 fast*) 420 _narg=${_narg#fast} 421 ;; 422 force*) 423 _narg=${_narg#force} 424 ;; 425 esac 426 eval ${_narg}_precmd="" 427 eval ${_narg}_cmd="" 428 429 case "$_file" in 430 *.sh) # run in current shell 431 set $_arg ; . $_file 432 ;; 433 *) # run in subshell 434 ( set $_arg ; . $_file ) 435 ;; 436 esac 437} 438 439# 440# rc_usage commands 441# Print a usage string for $0, with `commands' being a list of 442# valid commands. 443# 444rc_usage() 445{ 446 echo -n 1>&2 "Usage: $0 [fast|force](" 447 448 _sep= 449 for _elem in $*; do 450 echo -n 1>&2 "$_sep$_elem" 451 _sep="|" 452 done 453 echo 1>&2 ")" 454 exit 1 455} 456 457# 458# err exitval message 459# Display message to stderr and log to the syslog, and exit with exitval. 460# 461err() 462{ 463 exitval=$1 464 shift 465 466 logger "$0: ERROR $*" 467 echo 1>&2 "$0: ERROR $*" 468 exit $exitval 469} 470 471# 472# warn message 473# Display message to stderr and log to the syslog. 474# 475warn() 476{ 477 logger "$0: WARNING $*" 478 echo 1>&2 "$0: WARNING $*" 479} 480