rc.subr revision 1.13
1# $NetBSD: rc.subr,v 1.13 2000/04/22 03:01:22 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 if ! checkyesno rc_configured; then 226 err 1 '/etc/rc.conf is not configured' 227 fi 228 229 _arg=$1 230 shift 231 _ckvar=${rcvar:-$name} 232 if [ -z "$_ckvar" ]; then 233 err 3 'neither $rcvar or $name is set.' 234 fi 235 236 case "$_arg" in 237 fast*) 238 _arg=${_arg#fast} 239 _rc_fast_run=YES 240 ;; 241 force*) 242 _arg=${_arg#force} 243 eval ${_ckvar}=YES 244 ;; 245 esac 246 247 _keywords="start stop restart rcvar $*" 248 _pidcmd= 249 if [ -z "$_rc_fast_run" ]; then 250 if [ -n "$pidfile" ]; then 251 _pidcmd='_pid=`check_pidfile '$pidfile' '$command'`' 252 elif [ -n "$command" ]; then 253 _pidcmd='_pid=`check_process '$command'`' 254 fi 255 if [ -n "$_pidcmd" ]; then 256 _keywords="${_keywords} status" 257 fi 258 fi 259 260 if [ -z "$_arg" ]; then 261 rc_usage "$_keywords" 262 fi 263 264 if [ -n "$flags" ]; then 265 _flags=$flags 266 else 267 eval _flags=\$${name}_flags 268 fi 269 270 eval $_pidcmd 271 272 for _elem in $_keywords; do 273 if [ "$_elem" != "$_arg" ]; then 274 continue 275 fi 276 277 eval _cmd=\$${_arg}_cmd 278 eval _precmd=\$${_arg}_precmd 279 if [ -n "$_cmd" ]; then 280 eval $_precmd || return 1 281 eval $_cmd 282 return 0 283 fi 284 285 case "$_arg" in 286 287 status) 288 if [ -n "$_pid" ]; then 289 echo "${name} is running as pid $_pid." 290 else 291 echo "${name} is not running." 292 fi 293 ;; 294 295 start) 296 if [ -n "$_pid" ]; then 297 echo "${name} already running? (pid=$_pid)." 298 exit 1 299 fi 300 301 if ! checkyesno ${_ckvar} || [ ! -x $command ]; then 302 return 0 303 fi 304 305 for _f in $required_vars; do 306 if ! checkyesno $_f; then 307 warn \ 308 "\$${_f} is not set; ${name} not started." 309 return 1 310 fi 311 done 312 for _f in $required_dirs; do 313 if [ ! -d "${_f}/." ]; then 314 warn \ 315 "${_f} is not a directory; ${name} not started." 316 return 1 317 fi 318 done 319 for _f in $required_files; do 320 if [ ! -r "${_f}" ]; then 321 warn \ 322 "${_f} is not readable; ${name} not started." 323 return 1 324 fi 325 done 326 327 eval $_precmd || return 1 328 echo "Starting ${name}." 329 eval $command $_flags $command_args 330 ;; 331 332 stop) 333 if [ -z "$_pid" ]; then 334 if checkyesno ${_ckvar}; then 335 if [ -n "$pidfile" ]; then 336 echo \ 337 "${name} not running? (check $pidfile)." 338 else 339 echo "${name} not running?" 340 fi 341 exit 1 342 fi 343 return 0 344 fi 345 346 eval $_precmd || return 1 347 echo "Stopping ${name}." 348 kill -${sig_stop:-TERM} $_pid 349 ;; 350 351 reload) 352 if [ -z "$_pid" ]; then 353 if checkyesno ${_ckvar}; then 354 if [ -n "$pidfile" ]; then 355 echo \ 356 "${name} not running? (check $pidfile)." 357 else 358 echo "${name} not running?" 359 fi 360 exit 1 361 fi 362 return 0 363 fi 364 echo "Reloading ${name} config files." 365 eval $_precmd || return 1 366 kill -${sig_reload:-HUP} $_pid 367 ;; 368 369 restart) 370 if ! checkyesno ${_ckvar}; then 371 return 0 372 fi 373 eval $_precmd || return 1 374 ( $0 stop ) 375 sleep 1 376 $0 start 377 378 ;; 379 380 rcvar) 381 echo "# $name" 382 if checkyesno ${_ckvar}; then 383 echo "\$${_ckvar}=YES" 384 else 385 echo "\$${_ckvar}=NO" 386 fi 387 ;; 388 389 *) 390 rc_usage "$_keywords" 391 ;; 392 393 esac 394 return 0 395 done 396 397 echo 1>&2 "$0: unknown directive '$_arg'." 398 rc_usage "$_keywords" 399 exit 1 400} 401 402# 403# run_rc_script file arg 404# Start the script `file' with `arg', and correctly handle the 405# return value from the script. If `file' ends with `.sh', it's 406# sourced into the current environment. Otherwise it's run as 407# a child process. 408# Note: because `.sh' files are sourced into the current environment 409# run_rc_command shouldn't be used because its difficult to ensure 410# that the global variable state before and after the sourcing of 411# the .sh file won't adversely affect other scripts. 412# 413run_rc_script() 414{ 415 _file=$1 416 _arg=$2 417 if [ -z "$_file" -o -z "$_arg" ]; then 418 err 3 'USAGE: run_rc_script file arg' 419 fi 420 421 _narg=$_arg 422 case "$_narg" in 423 fast*) 424 _narg=${_narg#fast} 425 ;; 426 force*) 427 _narg=${_narg#force} 428 ;; 429 esac 430 eval ${_narg}_precmd="" 431 eval ${_narg}_cmd="" 432 433 case "$_file" in 434 *.sh) # run in current shell 435 set $_arg ; . $_file 436 ;; 437 *) # run in subshell 438 ( set $_arg ; . $_file ) 439 ;; 440 esac 441} 442 443# 444# rc_usage commands 445# Print a usage string for $0, with `commands' being a list of 446# valid commands. 447# 448rc_usage() 449{ 450 echo -n 1>&2 "Usage: $0 [fast|force](" 451 452 _sep= 453 for _elem in $*; do 454 echo -n 1>&2 "$_sep$_elem" 455 _sep="|" 456 done 457 echo 1>&2 ")" 458 exit 1 459} 460 461# 462# err exitval message 463# Display message to stderr and log to the syslog, and exit with exitval. 464# 465err() 466{ 467 exitval=$1 468 shift 469 470 logger "$0: ERROR $*" 471 echo 1>&2 "$0: ERROR $*" 472 exit $exitval 473} 474 475# 476# warn message 477# Display message to stderr and log to the syslog. 478# 479warn() 480{ 481 logger "$0: WARNING $*" 482 echo 1>&2 "$0: WARNING $*" 483} 484