rc.subr revision 124832
172613Skris# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $ 272613Skris# $FreeBSD: head/etc/rc.subr 124832 2004-01-22 08:46:03Z mtm $ 372613Skris# 472613Skris# Copyright (c) 1997-2002 The NetBSD Foundation, Inc. 5205128Ssimon# All rights reserved. 672613Skris# 772613Skris# This code is derived from software contributed to The NetBSD Foundation 872613Skris# by Luke Mewburn. 972613Skris# 1072613Skris# Redistribution and use in source and binary forms, with or without 1172613Skris# modification, are permitted provided that the following conditions 1272613Skris# are met: 1372613Skris# 1. Redistributions of source code must retain the above copyright 14205128Ssimon# notice, this list of conditions and the following disclaimer. 15205128Ssimon# 2. Redistributions in binary form must reproduce the above copyright 16205128Ssimon# notice, this list of conditions and the following disclaimer in the 1772613Skris# documentation and/or other materials provided with the distribution. 1872613Skris# 3. All advertising materials mentioning features or use of this software 1972613Skris# must display the following acknowledgement: 20205128Ssimon# This product includes software developed by the NetBSD 21205128Ssimon# Foundation, Inc. and its contributors. 2272613Skris# 4. Neither the name of The NetBSD Foundation nor the names of its 2372613Skris# contributors may be used to endorse or promote products derived 24205128Ssimon# from this software without specific prior written permission. 25205128Ssimon# 2672613Skris# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2789837Skris# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2872613Skris# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2972613Skris# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3089837Skris# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3172613Skris# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32205128Ssimon# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33205128Ssimon# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34205128Ssimon# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35205128Ssimon# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36205128Ssimon# POSSIBILITY OF SUCH DAMAGE. 3772613Skris# 3872613Skris# rc.subr 3972613Skris# functions used by various rc scripts 4072613Skris# 41205128Ssimon 42205128Ssimon# 43205128Ssimon# Operating System dependent/independent variables 4472613Skris# 4572613Skris 4672613SkrisSYSCTL="/sbin/sysctl" 4772613SkrisSYSCTL_N="${SYSCTL} -n" 48205128SsimonCMD_OSTYPE="${SYSCTL_N} kern.ostype" 4972613SkrisOSTYPE=`${CMD_OSTYPE}` 5089837SkrisID="/usr/bin/id" 5189837SkrisIDCMD="if [ -x $ID ]; then $ID -un; fi" 5289837Skris 53100936Snectarcase ${OSTYPE} in 5489837SkrisFreeBSD) 5589837Skris SYSCTL_W="${SYSCTL}" 5672613Skris ;; 5772613SkrisNetBSD) 5872613Skris SYSCTL_W="${SYSCTL} -w" 5972613Skris ;; 6072613Skrisesac 6172613Skris 6272613Skris# 6372613Skris# functions 6472613Skris# --------- 6572613Skris 6672613Skris# 6772613Skris# set_rcvar base_var 6872613Skris# Set the variable name enabling a specific service. 6972613Skris# FreeBSD uses ${service}_enable, while NetBSD uses 7072613Skris# just the name of the service. For example: 7172613Skris# FreeBSD: sendmail_enable="YES" 7272613Skris# NetBSD : sendmail="YES" 7372613Skris# $1 - if $name is not the base to work of off, specify 7472613Skris# a different one 7572613Skris# 7676866Skrisset_rcvar() 7772613Skris{ 7872613Skris if [ -z "$1" ]; then 7972613Skris base_var=${name} 8072613Skris else 81216166Ssimon base_var="$1" 8272613Skris fi 8372613Skris 8472613Skris case ${OSTYPE} in 8572613Skris FreeBSD) 8672613Skris echo ${base_var}_enable 8772613Skris ;; 8872613Skris NetBSD) 8972613Skris echo ${base_var} 9072613Skris ;; 91261037Sjkim *) 9272613Skris echo 'XXX' 93261037Sjkim ;; 94261037Sjkim esac 9572613Skris} 9672613Skris 9772613Skris# 9872613Skris# force_depend script 9972613Skris# Force a service to start. Intended for use by services 10072613Skris# to resolve dependency issues. It is assumed the caller 10172613Skris# has check to make sure this call is necessary 10272613Skris# $1 - filename of script, in /etc/rc.d, to run 10372613Skris# 10472613Skrisforce_depend() 10572613Skris{ 10672613Skris _depend="$1" 10772613Skris 108100936Snectar info "${name} depends on ${_depend}, which will be forced to start." 109100936Snectar if ! /etc/rc.d/${_depend} forcestart ; then 110100936Snectar warn "Unable to force ${_depend}. It may already be running." 111100936Snectar return 1 112100936Snectar fi 113100936Snectar return 0 114100936Snectar} 115267256Sjkim 116267256Sjkim# 117267256Sjkim# checkyesno var 118267256Sjkim# Test $1 variable, and warn if not set to YES or NO. 119267256Sjkim# Return 0 if it's "yes" (et al), nonzero otherwise. 120267256Sjkim# 12172613Skrischeckyesno() 12272613Skris{ 12372613Skris eval _value=\$${1} 12472613Skris debug "checkyesno: $1 is set to $_value." 12572613Skris case $_value in 12672613Skris 127100936Snectar # "yes", "true", "on", or "1" 128100936Snectar [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 129100936Snectar return 0 13072613Skris ;; 13172613Skris 13272613Skris # "no", "false", "off", or "0" 13372613Skris [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 13472613Skris return 1 135109998Smarkm ;; 136109998Smarkm *) 137109998Smarkm warn "\$${1} is not set properly - see rc.conf(5)." 138109998Smarkm return 1 139109998Smarkm ;; 140109998Smarkm esac 141109998Smarkm} 142109998Smarkm 143109998Smarkm# reverse_list list 144109998Smarkm# print the list in reverse order 145109998Smarkm# 146109998Smarkmreverse_list() 14772613Skris{ 14872613Skris _revlist= 14989837Skris for _revfile in $*; do 15089837Skris _revlist="$_revfile $_revlist" 15189837Skris done 15289837Skris echo $_revlist 15389837Skris} 15489837Skris 15589837Skris# 156109998Smarkm# mount_critical_filesystems type 15789837Skris# Go through the list of critical filesystems as provided in 15872613Skris# the rc.conf(5) variable $critical_filesystems_${type}, checking 15972613Skris# each one to see if it is mounted, and if it is not, mounting it. 16072613Skris# 161276861Sjkimmount_critical_filesystems() 16272613Skris{ 163109998Smarkm eval _fslist=\$critical_filesystems_${1} 164109998Smarkm for _fs in $_fslist; do 165109998Smarkm mount | ( 166109998Smarkm _ismounted=no 167109998Smarkm while read what _on on _type type; do 168109998Smarkm if [ $on = $_fs ]; then 169160814Ssimon _ismounted=yes 170109998Smarkm fi 17172613Skris done 17272613Skris if [ $_ismounted = no ]; then 17372613Skris mount $_fs >/dev/null 2>&1 17472613Skris fi 17572613Skris ) 17672613Skris done 17772613Skris} 17872613Skris 17972613Skris# 18072613Skris# check_pidfile pidfile procname [interpreter] 18172613Skris# Parses the first line of pidfile for a PID, and ensures 182120631Snectar# that the process is running and matches procname. 18372613Skris# Prints the matching PID upon success, nothing otherwise. 18472613Skris# interpreter is optional; see _find_processes() for details. 18572613Skris# 18672613Skrischeck_pidfile() 18772613Skris{ 18872613Skris _pidfile=$1 18972613Skris _procname=$2 19072613Skris _interpreter=$3 19172613Skris if [ -z "$_pidfile" -o -z "$_procname" ]; then 192296279Sjkim err 3 'USAGE: check_pidfile pidfile procname [interpreter]' 19372613Skris fi 19472613Skris if [ ! -f $_pidfile ]; then 19572613Skris debug "pid file {$_pidfile): not readable." 19672613Skris return 197296279Sjkim fi 19872613Skris read _pid _junk < $_pidfile 19972613Skris if [ -z "$_pid" ]; then 20072613Skris debug "pid file {$_pidfile): no pid in file." 20172613Skris return 20272613Skris fi 203296279Sjkim _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" 204296279Sjkim} 205296279Sjkim 206296279Sjkim# 207296279Sjkim# check_process procname [interpreter] 208296279Sjkim# Ensures that a process (or processes) named procname is running. 209296279Sjkim# Prints a list of matching PIDs. 210296279Sjkim# interpreter is optional; see _find_processes() for details. 211109998Smarkm# 212109998Smarkmcheck_process() 213109998Smarkm{ 214109998Smarkm _procname=$1 215205128Ssimon _interpreter=$2 216109998Smarkm if [ -z "$_procname" ]; then 217194206Ssimon err 3 'USAGE: check_process procname [interpreter]' 218194206Ssimon fi 219194206Ssimon _find_processes $_procname ${_interpreter:-.} '-ax' 220238405Sjkim} 221194206Ssimon 222194206Ssimon# 223194206Ssimon# _find_processes procname interpreter psargs 224194206Ssimon# Search for procname in the output of ps generated by psargs. 225205128Ssimon# Prints the PIDs of any matching processes, space separated. 226205128Ssimon# 227205128Ssimon# If interpreter == ".", check the following variations of procname 228205128Ssimon# against the first word of each command: 229205128Ssimon# procname 230205128Ssimon# `basename procname` 231205128Ssimon# `basename procname` + ":" 232205128Ssimon# "(" + `basename procname` + ")" 233205128Ssimon# 234205128Ssimon# If interpreter != ".", read the first line of procname, remove the 235205128Ssimon# leading #!, normalise whitespace, append procname, and attempt to 23672613Skris# match that against each command, either as is, or with extra words 23772613Skris# at the end. 238205128Ssimon# 239205128Ssimon_find_processes() 240205128Ssimon{ 241205128Ssimon if [ $# -ne 3 ]; then 242205128Ssimon err 3 'USAGE: _find_processes procname interpreter psargs' 243205128Ssimon fi 244205128Ssimon _procname=$1 245205128Ssimon _interpreter=$2 246205128Ssimon _psargs=$3 247205128Ssimon 248205128Ssimon _pref= 249205128Ssimon if [ $_interpreter != "." ]; then # an interpreted script 250205128Ssimon read _interp < $_procname # read interpreter name 251205128Ssimon _interp=${_interp#\#!} # strip #! 252205128Ssimon set -- $_interp 253205128Ssimon if [ $_interpreter != $1 ]; then 254205128Ssimon warn "\$command_interpreter $_interpreter != $1" 255205128Ssimon fi 256205128Ssimon _interp="$* $_procname" # cleanup spaces, add _procname 257205128Ssimon _fp_args='_argv' 258205128Ssimon _fp_match='case "$_argv" in 259205128Ssimon ${_interp}|"${_interp} "*)' 260205128Ssimon else # a normal daemon 261269682Sjkim _procnamebn=${_procname##*/} 262205128Ssimon _fp_args='_arg0 _argv' 263205128Ssimon _fp_match='case "$_arg0" in 264205128Ssimon $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")' 265205128Ssimon fi 266205128Ssimon 267205128Ssimon _proccheck=' 268205128Ssimon ps -o "pid,command" '"$_psargs"' | 269205128Ssimon while read _npid '"$_fp_args"'; do 270205128Ssimon case "$_npid" in 271205128Ssimon PID) 272205128Ssimon continue ;; 273205128Ssimon esac ; '"$_fp_match"' 274205128Ssimon echo -n "$_pref$_npid" ; 275205128Ssimon _pref=" " 276205128Ssimon ;; 277205128Ssimon esac 278205128Ssimon done' 279205128Ssimon 280205128Ssimon# debug "in _find_processes: proccheck is ($_proccheck)." 281205128Ssimon eval $_proccheck 282205128Ssimon} 283205128Ssimon 284205128Ssimon# 285205128Ssimon# wait_for_pids pid [pid ...] 286205128Ssimon# spins until none of the pids exist 287205128Ssimon# 288205128Ssimonwait_for_pids() 289205128Ssimon{ 290205128Ssimon _list=$* 291205128Ssimon if [ -z "$_list" ]; then 292205128Ssimon return 293205128Ssimon fi 294205128Ssimon _prefix= 295205128Ssimon while true; do 296205128Ssimon _nlist=""; 297205128Ssimon for _j in $_list; do 298205128Ssimon if kill -0 $_j 2>/dev/null; then 299205128Ssimon _nlist="${_nlist}${_nlist:+ }$_j" 300205128Ssimon fi 301205128Ssimon done 302205128Ssimon if [ -z "$_nlist" ]; then 303205128Ssimon break 304205128Ssimon fi 305205128Ssimon _list=$_nlist 306205128Ssimon echo -n ${_prefix:-"Waiting for PIDS: "}$_list 307205128Ssimon _prefix=", " 308205128Ssimon sleep 2 309205128Ssimon done 310205128Ssimon if [ -n "$_prefix" ]; then 311205128Ssimon echo "." 312205128Ssimon fi 31372613Skris} 31472613Skris 31572613Skris# 31672613Skris# run_rc_command argument 31772613Skris# Search for argument in the list of supported commands, which is: 318205128Ssimon# "start stop restart rcvar status poll ${extra_commands}" 319205128Ssimon# If there's a match, run ${argument}_cmd or the default method 320205128Ssimon# (see below). 32172613Skris# 32272613Skris# If argument has a given prefix, then change the operation as follows: 323205128Ssimon# Prefix Operation 324205128Ssimon# ------ --------- 325205128Ssimon# fast Skip the pid check, and set rc_fast=yes 32672613Skris# force Set ${rcvar} to YES, and set rc_force=yes 32772613Skris# 32889837Skris# The following globals are used: 32989837Skris# 33089837Skris# Name Needed Purpose 33189837Skris# ---- ------ ------- 33272613Skris# name y Name of script. 33372613Skris# 33472613Skris# command n Full path to command. 335109998Smarkm# Not needed if ${rc_arg}_cmd is set for 336109998Smarkm# each keyword. 337109998Smarkm# 33872613Skris# command_args n Optional args/shell directives for command. 339109998Smarkm# 340109998Smarkm# command_interpreter n If not empty, command is interpreted, so 341109998Smarkm# call check_{pidfile,process}() appropriately. 342109998Smarkm# 343100936Snectar# extra_commands n List of extra commands supported. 344100936Snectar# 345100936Snectar# pidfile n If set, use check_pidfile $pidfile $command, 346100936Snectar# otherwise use check_process $command. 347100936Snectar# In either case, only check if $command is set. 348205128Ssimon# 349205128Ssimon# procname n Process name to check for instead of $command. 350205128Ssimon# 351205128Ssimon# rcvar n This is checked with checkyesno to determine 352205128Ssimon# if the action should be run. 353205128Ssimon# 354205128Ssimon# ${name}_chroot n Directory to chroot to before running ${command} 35572613Skris# Requires /usr to be mounted. 356# 357# ${name}_chdir n Directory to cd to before running ${command} 358# (if not using ${name}_chroot). 359# 360# ${name}_flags n Arguments to call ${command} with. 361# NOTE: $flags from the parent environment 362# can be used to override this. 363# 364# ${name}_nice n Nice level to run ${command} at. 365# 366# ${name}_user n User to run ${command} as, using su(1) if not 367# using ${name}_chroot. 368# Requires /usr to be mounted. 369# 370# ${name}_group n Group to run chrooted ${command} as. 371# Requires /usr to be mounted. 372# 373# ${name}_groups n Comma separated list of supplementary groups 374# to run the chrooted ${command} with. 375# Requires /usr to be mounted. 376# 377# ${rc_arg}_cmd n If set, use this as the method when invoked; 378# Otherwise, use default command (see below) 379# 380# ${rc_arg}_precmd n If set, run just before performing the 381# ${rc_arg}_cmd method in the default 382# operation (i.e, after checking for required 383# bits and process (non)existence). 384# If this completes with a non-zero exit code, 385# don't run ${rc_arg}_cmd. 386# 387# ${rc_arg}_postcmd n If set, run just after performing the 388# ${rc_arg}_cmd method, if that method 389# returned a zero exit code. 390# 391# required_dirs n If set, check for the existence of the given 392# directories before running the default 393# (re)start command. 394# 395# required_files n If set, check for the readability of the given 396# files before running the default (re)start 397# command. 398# 399# required_vars n If set, perform checkyesno on each of the 400# listed variables before running the default 401# (re)start command. 402# 403# Default behaviour for a given argument, if no override method is 404# provided: 405# 406# Argument Default behaviour 407# -------- ----------------- 408# start if !running && checkyesno ${rcvar} 409# ${command} 410# 411# stop if ${pidfile} 412# rc_pid=$(check_pidfile $pidfile $command) 413# else 414# rc_pid=$(check_process $command) 415# kill $sig_stop $rc_pid 416# wait_for_pids $rc_pid 417# ($sig_stop defaults to TERM.) 418# 419# reload Similar to stop, except use $sig_reload instead, 420# and doesn't wait_for_pids. 421# $sig_reload defaults to HUP. 422# 423# restart Run `stop' then `start'. 424# 425# status Show if ${command} is running, etc. 426# 427# poll Wait for ${command} to exit. 428# 429# rcvar Display what rc.conf variable is used (if any). 430# 431# Variables available to methods, and after run_rc_command() has 432# completed: 433# 434# Variable Purpose 435# -------- ------- 436# rc_arg Argument to command, after fast/force processing 437# performed 438# 439# rc_flags Flags to start the default command with. 440# Defaults to ${name}_flags, unless overridden 441# by $flags from the environment. 442# This variable may be changed by the precmd method. 443# 444# rc_pid PID of command (if appropriate) 445# 446# rc_fast Not empty if "fast" was provided (q.v.) 447# 448# rc_force Not empty if "force" was provided (q.v.) 449# 450# 451run_rc_command() 452{ 453 _return=0 454 rc_arg=$1 455 if [ -z "$name" ]; then 456 err 3 'run_rc_command: $name is not set.' 457 fi 458 459 case "$rc_arg" in 460 fast*) # "fast" prefix; don't check pid 461 rc_arg=${rc_arg#fast} 462 rc_fast=yes 463 ;; 464 force*) # "force prefix; always start 465 rc_arg=${rc_arg#force} 466 rc_force=yes 467 if [ -n "${rcvar}" ]; then 468 eval ${rcvar}=YES 469 fi 470 ;; 471 esac 472 473 eval _overide_command=\$${name}_program 474 if [ -n "$_overide_command" ]; then 475 command=$_overide_command 476 fi 477 478 _keywords="start stop restart rcvar $extra_commands" 479 rc_pid= 480 _pidcmd= 481 _procname=${procname:-${command}} 482 483 # setup pid check command if not fast 484 if [ -z "$rc_fast" -a -n "$_procname" ]; then 485 if [ -n "$pidfile" ]; then 486 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 487 else 488 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 489 fi 490 if [ -n "$_pidcmd" ]; then 491 _keywords="${_keywords} status poll" 492 fi 493 fi 494 495 if [ -z "$rc_arg" ]; then 496 rc_usage "$_keywords" 497 fi 498 499 if [ -n "$flags" ]; then # allow override from environment 500 rc_flags=$flags 501 else 502 eval rc_flags=\$${name}_flags 503 fi 504 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 505 _nice=\$${name}_nice _user=\$${name}_user \ 506 _group=\$${name}_group _groups=\$${name}_groups 507 508 if [ -n "$_user" ]; then # unset $_user if running as that user 509 if [ "$_user" = "$(eval $IDCMD)" ]; then 510 unset _user 511 fi 512 fi 513 514 # if ${rcvar} is set, and $1 is not 515 # "rcvar", then run 516 # checkyesno ${rcvar} 517 # and return if that failed 518 # 519 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then 520 if ! checkyesno ${rcvar}; then 521 return 0 522 fi 523 fi 524 525 eval $_pidcmd # determine the pid if necessary 526 527 for _elem in $_keywords; do 528 if [ "$_elem" != "$rc_arg" ]; then 529 continue 530 fi 531 532 # if there's a custom ${XXX_cmd}, 533 # run that instead of the default 534 # 535 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 536 _postcmd=\$${rc_arg}_postcmd 537 if [ -n "$_cmd" ]; then 538 # if the precmd failed and force 539 # isn't set, exit 540 # 541 if [ -n "$_precmd" ]; then 542 debug "run_rc_command: evaluating ${_precmd}()." 543 eval $_precmd 544 _return=$? 545 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 546 return 1 547 fi 548 549 if [ -n "$_cmd" ]; then 550 debug "run_rc_command: evaluating ${_cmd}()." 551 eval $_cmd 552 _return=$? 553 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 554 return 1 555 fi 556 557 if [ -n "$_postcmd" ]; then 558 debug "run_rc_command: evaluating ${_postcmd}()." 559 eval $_postcmd 560 _return=$? 561 fi 562 return $_return 563 fi 564 565 case "$rc_arg" in # default operations... 566 567 status) 568 if [ -n "$rc_pid" ]; then 569 echo "${name} is running as pid $rc_pid." 570 else 571 echo "${name} is not running." 572 return 1 573 fi 574 ;; 575 576 start) 577 if [ -n "$rc_pid" ]; then 578 echo "${name} already running? (pid=$rc_pid)." 579 exit 1 580 fi 581 582 if [ ! -x $command ]; then 583 info "run_rc_command: cannot run ($command)." 584 return 0 585 fi 586 587 # check for required variables, 588 # directories, and files 589 # 590 for _f in $required_vars; do 591 if ! checkyesno $_f; then 592 warn "\$${_f} is not set." 593 if [ -z "$rc_force" ]; then 594 return 1 595 fi 596 fi 597 done 598 for _f in $required_dirs; do 599 if [ ! -d "${_f}/." ]; then 600 warn "${_f} is not a directory." 601 if [ -z "$rc_force" ]; then 602 return 1 603 fi 604 fi 605 done 606 for _f in $required_files; do 607 if [ ! -r "${_f}" ]; then 608 warn "${_f} is not readable." 609 if [ -z "$rc_force" ]; then 610 return 1 611 fi 612 fi 613 done 614 615 # if the precmd failed and force 616 # isn't set, exit 617 # 618 if [ -n "${_precmd}" ]; then 619 debug "run_rc_command: evaluating ${_precmd}()." 620 eval $_precmd 621 _return=$? 622 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 623 return 1 624 fi 625 626 # setup the command to run, and run it 627 # 628 echo "Starting ${name}." 629 if [ -n "$_chroot" ]; then 630 _doit="\ 631${_nice:+nice -n $_nice }\ 632chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 633$_chroot $command $rc_flags $command_args" 634 else 635 _doit="\ 636${_chdir:+cd $_chdir; }\ 637${_nice:+nice -n $_nice }\ 638$command $rc_flags $command_args" 639 if [ -n "$_user" ]; then 640 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 641 fi 642 fi 643 644 # if the cmd failed and force 645 # isn't set, exit 646 # 647 debug "run_rc_command: _doit: $_doit" 648 eval $_doit 649 _return=$? 650 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 651 652 # finally, run postcmd 653 # 654 if [ -n "${_postcmd}" ]; then 655 debug "run_rc_command: evaluating ${_postcmd}()." 656 eval $_postcmd 657 fi 658 ;; 659 660 stop) 661 if [ -z "$rc_pid" ]; then 662 if [ -n "$pidfile" ]; then 663 echo \ 664 "${name} not running? (check $pidfile)." 665 else 666 echo "${name} not running?" 667 fi 668 exit 1 669 fi 670 671 # if the precmd failed and force 672 # isn't set, exit 673 # 674 if [ -n "$_precmd" ]; then 675 eval $_precmd 676 _return=$? 677 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 678 return 1 679 fi 680 681 # send the signal to stop 682 # 683 echo "Stopping ${name}." 684 _doit="kill -${sig_stop:-TERM} $rc_pid" 685 if [ -n "$_user" ]; then 686 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 687 fi 688 689 # if the stop cmd failed and force 690 # isn't set, exit 691 # 692 eval $_doit 693 _return=$? 694 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 695 696 # wait for the command to exit, 697 # and run postcmd. 698 wait_for_pids $rc_pid 699 if [ -n "$_postcmd" ]; then 700 eval $_postcmd 701 _return=$? 702 fi 703 ;; 704 705 reload) 706 if [ -z "$rc_pid" ]; then 707 if [ -n "$pidfile" ]; then 708 echo \ 709 "${name} not running? (check $pidfile)." 710 else 711 echo "${name} not running?" 712 fi 713 exit 1 714 fi 715 echo "Reloading ${name} config files." 716 if [ -n "$_precmd" ]; then 717 eval $_precmd 718 _return=$? 719 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 720 return 1 721 fi 722 _doit="kill -${sig_reload:-HUP} $rc_pid" 723 if [ -n "$_user" ]; then 724 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 725 fi 726 eval $_doit 727 _return=$? 728 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 729 if [ -n "$_postcmd" ]; then 730 eval $_postcmd 731 _return=$? 732 fi 733 ;; 734 735 restart) 736 if [ -n "$_precmd" ]; then 737 eval $_precmd 738 _return=$? 739 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 740 return 1 741 fi 742 # prevent restart being called more 743 # than once by any given script 744 # 745 if [ -n "$_rc_restart_done" ]; then 746 return 0 747 fi 748 _rc_restart_done=YES 749 750 ( $0 ${rc_force:+force}stop ) 751 $0 ${rc_force:+force}start 752 753 if [ -n "$_postcmd" ]; then 754 eval $_postcmd 755 _return=$? 756 fi 757 ;; 758 759 poll) 760 if [ -n "$rc_pid" ]; then 761 wait_for_pids $rc_pid 762 fi 763 ;; 764 765 rcvar) 766 echo "# $name" 767 if [ -n "$rcvar" ]; then 768 if checkyesno ${rcvar}; then 769 echo "\$${rcvar}=YES" 770 else 771 echo "\$${rcvar}=NO" 772 fi 773 fi 774 ;; 775 776 *) 777 rc_usage "$_keywords" 778 ;; 779 780 esac 781 return $_return 782 done 783 784 echo 1>&2 "$0: unknown directive '$rc_arg'." 785 rc_usage "$_keywords" 786 exit 1 787} 788 789# 790# run_rc_script file arg 791# Start the script `file' with `arg', and correctly handle the 792# return value from the script. If `file' ends with `.sh', it's 793# sourced into the current environment. If `file' appears to be 794# a backup or scratch file, ignore it. Otherwise if it's 795# executable run as a child process. 796# 797run_rc_script() 798{ 799 _file=$1 800 _arg=$2 801 if [ -z "$_file" -o -z "$_arg" ]; then 802 err 3 'USAGE: run_rc_script file arg' 803 fi 804 805 trap "echo 'Reboot interrupted'; exit 1" 3 806 807 unset name command command_args command_interpreter \ 808 extra_commands pidfile procname \ 809 rcvar required_dirs required_files required_vars 810 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 811 812 case "$_file" in 813 *.sh) # run in current shell 814 set $_arg ; . $_file 815 ;; 816 *[~#]|*.OLD|*.orig) # scratch file; skip 817 warn "Ignoring scratch file $_file" 818 ;; 819 *) # run in subshell 820 if [ -x $_file ]; then 821 if [ -n "$rc_fast_and_loose" ]; then 822 set $_arg ; . $_file 823 else 824 ( trap "echo 'Reboot interrupted'; exit 1" 3 825 set $_arg ; . $_file ) 826 fi 827 fi 828 ;; 829 esac 830} 831 832# 833# load_rc_config 834# Source in the configuration file for a given command. 835# 836load_rc_config() 837{ 838 _command=$1 839 if [ -z "$_command" ]; then 840 err 3 'USAGE: load_rc_config command' 841 fi 842 843 if [ -z "$_rc_conf_loaded" ]; then 844 if [ -r /etc/defaults/rc.conf ]; then 845 debug "Sourcing /etc/defaults/rc.conf" 846 . /etc/defaults/rc.conf 847 source_rc_confs 848 elif [ -r /etc/rc.conf ]; then 849 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 850 . /etc/rc.conf 851 fi 852 _rc_conf_loaded=YES 853 fi 854 if [ -f /etc/rc.conf.d/"$_command" ]; then 855 debug "Sourcing /etc/rc.conf.d/${_command}" 856 . /etc/rc.conf.d/"$_command" 857 fi 858 859 # XXX - Deprecated variable name support 860 # 861 case ${OSTYPE} in 862 FreeBSD) 863 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable" 864 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program" 865 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags" 866 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable" 867 [ -n "$xntpd_enable" ] && ntpd_enable="$xntpd_enable" 868 [ -n "$xntpd_program" ] && ntpd_program="$xntpd_program" 869 [ -n "$xntpd_flags" ] && ntpd_flags="$xntpd_flags" 870 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" 871 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" 872 ;; 873 esac 874 875} 876 877# 878# rc_usage commands 879# Print a usage string for $0, with `commands' being a list of 880# valid commands. 881# 882rc_usage() 883{ 884 echo -n 1>&2 "Usage: $0 [fast|force](" 885 886 _sep= 887 for _elem in $*; do 888 echo -n 1>&2 "$_sep$_elem" 889 _sep="|" 890 done 891 echo 1>&2 ")" 892 exit 1 893} 894 895# 896# err exitval message 897# Display message to stderr and log to the syslog, and exit with exitval. 898# 899err() 900{ 901 exitval=$1 902 shift 903 904 if [ -x /usr/bin/logger ]; then 905 logger "$0: ERROR: $*" 906 fi 907 echo 1>&2 "$0: ERROR: $*" 908 exit $exitval 909} 910 911# 912# warn message 913# Display message to stderr and log to the syslog. 914# 915warn() 916{ 917 if [ -x /usr/bin/logger ]; then 918 logger "$0: WARNING: $*" 919 fi 920 echo 1>&2 "$0: WARNING: $*" 921} 922 923# 924# info message 925# Display informational message to stdout and log to syslog. 926# 927info() 928{ 929 case ${rc_info} in 930 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 931 if [ -x /usr/bin/logger ]; then 932 logger "$0: INFO: $*" 933 fi 934 echo "$0: INFO: $*" 935 ;; 936 esac 937} 938 939# 940# debug message 941# If debugging is enabled in rc.conf output message to stderr. 942# BEWARE that you don't call any subroutine that itself calls this 943# function. 944# 945debug() 946{ 947 case ${rc_debug} in 948 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 949 if [ -x /usr/bin/logger ]; then 950 logger "$0: INFO: $*" 951 fi 952 echo 1>&2 "$0: DEBUG: $*" 953 ;; 954 esac 955} 956 957# 958# backup_file action file cur backup 959# Make a backup copy of `file' into `cur', and save the previous 960# version of `cur' as `backup' or use rcs for archiving. 961# 962# This routine checks the value of the backup_uses_rcs variable, 963# which can be either YES or NO. 964# 965# The `action' keyword can be one of the following: 966# 967# add `file' is now being backed up (and is possibly 968# being reentered into the backups system). `cur' 969# is created and RCS files, if necessary, are 970# created as well. 971# 972# update `file' has changed and needs to be backed up. 973# If `cur' exists, it is copied to to `back' or 974# checked into RCS (if the repository file is old), 975# and then `file' is copied to `cur'. Another RCS 976# check in done here if RCS is being used. 977# 978# remove `file' is no longer being tracked by the backups 979# system. If RCS is not being used, `cur' is moved 980# to `back', otherwise an empty file is checked in, 981# and then `cur' is removed. 982# 983# 984backup_file() 985{ 986 _action=$1 987 _file=$2 988 _cur=$3 989 _back=$4 990 991 if checkyesno backup_uses_rcs; then 992 _msg0="backup archive" 993 _msg1="update" 994 995 # ensure that history file is not locked 996 if [ -f $_cur,v ]; then 997 rcs -q -u -U -M $_cur 998 fi 999 1000 # ensure after switching to rcs that the 1001 # current backup is not lost 1002 if [ -f $_cur ]; then 1003 # no archive, or current newer than archive 1004 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 1005 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1006 rcs -q -kb -U $_cur 1007 co -q -f -u $_cur 1008 fi 1009 fi 1010 1011 case $_action in 1012 add|update) 1013 cp -p $_file $_cur 1014 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1015 rcs -q -kb -U $_cur 1016 co -q -f -u $_cur 1017 chown root:wheel $_cur $_cur,v 1018 ;; 1019 remove) 1020 cp /dev/null $_cur 1021 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1022 rcs -q -kb -U $_cur 1023 chown root:wheel $_cur $_cur,v 1024 rm $_cur 1025 ;; 1026 esac 1027 else 1028 case $_action in 1029 add|update) 1030 if [ -f $_cur ]; then 1031 cp -p $_cur $_back 1032 fi 1033 cp -p $_file $_cur 1034 chown root:wheel $_cur 1035 ;; 1036 remove) 1037 mv -f $_cur $_back 1038 ;; 1039 esac 1040 fi 1041} 1042 1043# make_symlink src link 1044# Make a symbolic link 'link' to src from basedir. If the 1045# directory in which link is to be created does not exist 1046# a warning will be displayed and an error will be returned. 1047# Returns 0 on sucess, 1 otherwise. 1048# 1049make_symlink() 1050{ 1051 local src link linkdir _me 1052 src="$1" 1053 link="$2" 1054 linkdir="`dirname $link`" 1055 _me="make_symlink()" 1056 1057 if [ -z "$src" -o -z "$link" ]; then 1058 warn "$_me: requires two arguments." 1059 return 1 1060 fi 1061 if [ ! -d "$linkdir" ]; then 1062 warn "$_me: the directory $linkdir does not exist" 1063 return 1 1064 fi 1065 if ! ln -sf $src $link ; then 1066 warn "$_me: unable to make a symbolic link from $link to $src" 1067 return 1 1068 fi 1069 return 0 1070} 1071 1072# devfs_rulesets_from_file file 1073# Reads a set of devfs commands from file, and creates 1074# the specified rulesets with their rules. Returns non-zero 1075# if there was an error. 1076# 1077devfs_rulesets_from_file() 1078{ 1079 local file _err _me 1080 file="$1" 1081 _me="devfs_rulesets_from_file" 1082 _err=0 1083 1084 if [ -z "$file" ]; then 1085 warn "$_me: you must specify a file" 1086 return 1 1087 fi 1088 if [ ! -e "$file" ]; then 1089 debug "$_me: no such file ($file)" 1090 return 0 1091 fi 1092 debug "reading rulesets from file ($file)" 1093 { while read line 1094 do 1095 case $line in 1096 \#*) 1097 continue 1098 ;; 1099 \[*\]*) 1100 rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"` 1101 if [ -z "$rulenum" ]; then 1102 warn "$_me: cannot extract rule number ($line)" 1103 _err=1 1104 break 1105 fi 1106 rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"` 1107 if [ -z "$rulename" ]; then 1108 warn "$_me: cannot extract rule name ($line)" 1109 _err=1 1110 break; 1111 fi 1112 eval $rulename=\$rulenum 1113 debug "found ruleset: $rulename=$rulenum" 1114 if ! /sbin/devfs rule -s $rulenum delset ; then 1115 _err=1 1116 break 1117 fi 1118 ;; 1119 *) 1120 rulecmd="${line%%"\#*"}" 1121 # evaluate the command incase it includes 1122 # other rules 1123 if [ -n "$rulecmd" ]; then 1124 debug "adding rule ($rulecmd)" 1125 if ! eval /sbin/devfs rule -s $rulenum $rulecmd 1126 then 1127 _err=1 1128 break 1129 fi 1130 fi 1131 ;; 1132 esac 1133 if [ $_err -ne 0 ]; then 1134 debug "error in $_me" 1135 break 1136 fi 1137 done } < $file 1138 return $_err 1139} 1140 1141# devfs_init_rulesets 1142# Initializes rulesets from configuration files. Returns 1143# non-zero if there was an error. 1144# 1145devfs_init_rulesets() 1146{ 1147 local file _me 1148 _me="devfs_init_rulesets" 1149 1150 # Go through this only once 1151 if [ -n "$devfs_rulesets_init" ]; then 1152 debug "$_me: devfs rulesets already initialized" 1153 return 1154 fi 1155 for file in $devfs_rulesets ; do 1156 devfs_rulesets_from_file $file || return 1 1157 done 1158 devfs_rulesets_init=1 1159 debug "$_me: devfs rulesets initialized" 1160 return 0 1161} 1162 1163# devfs_set_ruleset ruleset [dir] 1164# Sets the default ruleset of dir to ruleset. The ruleset arguement 1165# must be a ruleset name as specified in devfs.rules(5) file. 1166# Returns non-zero if it could not set it successfully. 1167# 1168devfs_set_ruleset() 1169{ 1170 local devdir rs _me 1171 [ -n "$1" ] && eval rs=\$$1 || rs= 1172 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1173 _me="devfs_set_ruleset" 1174 1175 if [ -z "$rs" ]; then 1176 warn "$_me: you must specify a ruleset number" 1177 return 1 1178 fi 1179 debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })" 1180 if ! /sbin/devfs $devdir ruleset $rs ; then 1181 warn "$_me: unable to set ruleset $rs to ${devdir#-m }" 1182 return 1 1183 fi 1184 return 0 1185} 1186 1187# devfs_apply_ruleset ruleset [dir] 1188# Apply ruleset number $ruleset to the devfs mountpoint $dir. 1189# The ruleset argument must be a ruleset name as specified 1190# in a devfs.rules(5) file. Returns 0 on success or non-zero 1191# if it could not apply the ruleset. 1192# 1193devfs_apply_ruleset() 1194{ 1195 local devdir rs _me 1196 [ -n "$1" ] && eval rs=\$$1 || rs= 1197 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1198 _me="devfs_apply_ruleset" 1199 1200 if [ -z "$rs" ]; then 1201 warn "$_me: you must specify a ruleset" 1202 return 1 1203 fi 1204 debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })" 1205 if ! /sbin/devfs $devdir rule -s $rs applyset ; then 1206 warn "$_me: unable to apply ruleset $rs to ${devdir#-m }" 1207 return 1 1208 fi 1209 return 0 1210} 1211 1212# devfs_domount dir [ruleset] 1213# Mount devfs on dir. If ruleset is specified it is set 1214# on the mount-point. It must also be a ruleset name as specified 1215# in a devfs.rules(5) file. Returns 0 on success. 1216# 1217devfs_domount() 1218{ 1219 local devdir rs _me 1220 devdir="$1" 1221 [ -n "$2" ] && rs=$2 || rs= 1222 _me="devfs_domount()" 1223 1224 if [ -z "$devdir" ]; then 1225 warn "$_me: you must specify a mount-point" 1226 return 1 1227 fi 1228 debug "$_me: mount-point is ($devdir), ruleset is ($rs)" 1229 if ! mount -t devfs dev "$devdir" ; then 1230 warn "$_me: Unable to mount devfs on $devdir" 1231 return 1 1232 fi 1233 if [ -n "$rs" ]; then 1234 devfs_init_rulesets 1235 devfs_set_ruleset $rs $devdir 1236 devfs -m $devdir rule applyset 1237 fi 1238 return 0 1239} 1240 1241# devfs_mount_jail dir [ruleset] 1242# Mounts a devfs file system appropriate for jails 1243# on the directory dir. If ruleset is specified, the ruleset 1244# it names will be used instead. If present, ruleset must 1245# be the name of a ruleset as defined in a devfs.rules(5) file. 1246# This function returns non-zero if an error occurs. 1247# 1248devfs_mount_jail() 1249{ 1250 local jdev rs _me 1251 jdev="$1" 1252 [ -n "$2" ] && rs=$2 || rs="devfsrules_jail" 1253 _me="devfs_mount_jail" 1254 1255 devfs_init_rulesets 1256 if ! devfs_domount "$jdev" $rs ; then 1257 warn "$_me: devfs was not mounted on $jdev" 1258 return 1 1259 fi 1260 return 0 1261} 1262