1# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $ 2# $FreeBSD: src/etc/rc.subr,v 1.13 2003/06/09 17:31:06 mtm Exp $ 3# 4# Copyright (c) 1997-2002 The NetBSD Foundation, Inc. 5# All rights reserved. 6# 7# This code is derived from software contributed to The NetBSD Foundation 8# by Luke Mewburn. 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions 12# are met: 13# 1. Redistributions of source code must retain the above copyright 14# notice, this list of conditions and the following disclaimer. 15# 2. Redistributions in binary form must reproduce the above copyright 16# notice, this list of conditions and the following disclaimer in the 17# documentation and/or other materials provided with the distribution. 18# 3. All advertising materials mentioning features or use of this software 19# must display the following acknowledgement: 20# This product includes software developed by the NetBSD 21# Foundation, Inc. and its contributors. 22# 4. Neither the name of The NetBSD Foundation nor the names of its 23# contributors may be used to endorse or promote products derived 24# from this software without specific prior written permission. 25# 26# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36# POSSIBILITY OF SUCH DAMAGE. 37# 38# rc.subr 39# functions used by various rc scripts 40# 41 42# 43# Operating System dependent/independent variables 44# 45 46if [ "X$_file" = "X" ]; then 47 _file=$0 48fi 49 50provide_list=`rcorder -p $_file` 51 52SYSCTL="/sbin/sysctl" 53SYSCTL_N="${SYSCTL} -n" 54CMD_OSTYPE="${SYSCTL_N} kern.ostype" 55OSTYPE=`${CMD_OSTYPE}` 56 57RC_RUNNING=0 58RC_FAILED=1 59RC_DISABLED=2 60RC_IRRELEVANT=3 61RC_CONFIGURED=4 62RC_STOPPED=5 63SYSCTL_W="${SYSCTL}" 64 65# 66# functions 67# --------- 68 69# 70# set_rcvar base_var 71# Set the variable name enabling a specific service. 72# FreeBSD uses ${service}_enable, while NetBSD uses 73# just the name of the service. For example: 74# FreeBSD: sendmail_enable="YES" 75# NetBSD : sendmail="YES" 76# $1 - if $name is not the base to work of off, specify 77# a different one 78# 79set_rcvar() 80{ 81 if [ -z "$1" ]; then 82 base_var=${name} 83 else 84 base_var="$1" 85 fi 86 87 echo ${base_var} 88} 89 90# set_provide_list 91# 92# $1 should be $rc_arg (start, stop, restart, reload, etc) 93# $2 return value $RC_* 94# 95# Set the rcng_* variables associated with elements in provide_list 96# based on $1 and $2. 97# 98# Returns non-zero when early termination should occur, in which 99# case the caller should return with a value of $? - 1 100# 101set_provide_list() 102{ 103 # Remember, plret is set to the early termination return code + 1, 104 # or 0 if we want to continue the operation. 105 # 106 for i in $provide_list; do 107 case $1$2 in 108 start$RC_RUNNING|restart$RC_RUNNING) 109 varsym -s rcng_$i=running 110 ;; 111 start$RC_FAILED|restart$RC_FAILED) 112 varsym -s rcng_$i=failed 113 ;; 114 start$RC_DISABLED|restart$RC_DISABLED|reload$RC_DISABLED) 115 varsym -s rcng_$i=disabled 116 ;; 117 start$RC_IRRELEVANT|restart$RC_IRRELEVANT|reload$RC_IRRELEVANT) 118 varsym -s rcng_$i=irrelevant 119 ;; 120 start$RC_CONFIGURED|restart$RC_CONFIGURED) 121 varsym -s rcng_$i=configured 122 ;; 123 stop$RC_DISABLED) 124 varsym -s rcng_$i=disabled 125 ;; 126 stop$RC_IRRELEVANT) 127 varsym -s rcng_$i=irrelevant 128 ;; 129 stop*) 130 varsym -s rcng_$i=stopped 131 ;; 132 *) 133 ;; 134 esac 135 done 136} 137 138# check_early_term 139# $1 should be $rc_arg (start, stop, restart, reload, etc) 140# $2 return value $RC_* 141# $3 $rc_force "" not to force, "anything" to force. 142# 143# The return code is 0 if early termination is not to occur, non-zero if 144# it is to occur. When early termination is to occur the caller should 145# return check_early_term()'s return code - 1. That is, early termination 146# can occur with or without an error. 147# 148# The provide list will be adjusted when early termination occurs. 149# 150check_early_term() 151{ 152 case $2 in 153 $RC_RUNNING) 154 return 0 155 ;; 156 $RC_FAILED) 157 set_provide_list $1 $2 158 [ -z "$3" ] || return 0 159 return 2 160 ;; 161 $RC_DISABLED) 162 set_provide_list $1 $2 163 [ -z "$3" ] || return 0 164 return 1 165 ;; 166 $RC_IRRELEVANT) 167 set_provide_list $1 $2 168 [ -z "$3" ] || return 0 169 return 1 170 ;; 171 $RC_CONFIGURED) 172 return 0 173 ;; 174 $RC_STOPPED) 175 return 0 176 ;; 177 esac 178 set_provide_list $1 $2 179 [ -z "$3" ] || return 0 180 return 2 181} 182 183# adjust_return_code $1 184# 185# Convert the return code to an exit code of 0 (success) or 1 (failure) 186# 187adjust_return_code() 188{ 189 if [ $1 = $RC_FAILED ]; then 190 return 1 191 fi 192 return 0 193} 194 195# 196# force_depend script 197# Force a service to start. Intended for use by services 198# to resolve dependency issues. It is assumed the caller 199# has check to make sure this call is necessary 200# $1 - filename of script, in /etc/rc.d, to run 201# 202force_depend() 203{ 204 _depend="$1" 205 206 info "${name} depends on ${_depend}, which will be forced to start." 207 if ! /etc/rc.d/${_depend} forcestart ; then 208 warn "Unable to force ${_depend}. It may already be running." 209 return 1 210 fi 211 return 0 212} 213 214# 215# checkyesno var 216# Test $1 variable, and warn if not set to YES or NO. 217# Return 0 if it's "yes" (et al), nonzero otherwise. 218# 219checkyesno() 220{ 221 # try foo 222 eval _value=\$${1%_enable} 223 # try foo_enable 224 if [ -z $_value ] 225 then 226 eval _value=\$${1%_enable}_enable; 227 fi 228 debug "checkyesno: $1 is set to $_value." 229 case $_value in 230 231 # "yes", "true", "on", or "1" 232 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 233 return 0 234 ;; 235 236 # "no", "false", "off", or "0" 237 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 238 return 1 239 ;; 240 *) 241 warn "\$${1} is not set properly - see rc.conf(5)." 242 return 1 243 ;; 244 esac 245} 246 247# reverse_list list 248# print the list in reverse order 249# 250reverse_list() 251{ 252 _revlist= 253 for _revfile in $*; do 254 _revlist="$_revfile $_revlist" 255 done 256 echo $_revlist 257} 258 259# 260# mount_critical_filesystems type 261# Go through the list of critical filesystems as provided in 262# the rc.conf(5) variable $critical_filesystems_${type}, checking 263# each one to see if it is mounted, and if it is not, mounting it. 264# 265mount_critical_filesystems() 266{ 267 eval _fslist=\$critical_filesystems_${1} 268 for _fs in $_fslist; do 269 mount | ( 270 _ismounted=no 271 while read what _on on _type type; do 272 if [ $on = $_fs ]; then 273 _ismounted=yes 274 fi 275 done 276 if [ $_ismounted = no ]; then 277 mount $_fs >/dev/null 2>&1 278 fi 279 ) 280 done 281} 282 283# 284# check_pidfile pidfile procname [interpreter] 285# Parses the first line of pidfile for a PID, and ensures 286# that the process is running and matches procname. 287# Prints the matching PID upon success, nothing otherwise. 288# interpreter is optional; see _find_processes() for details. 289# 290check_pidfile() 291{ 292 _pidfile=$1 293 _procname=$2 294 _interpreter=$3 295 if [ -z "$_pidfile" -o -z "$_procname" ]; then 296 err 3 'USAGE: check_pidfile pidfile procname [interpreter]' 297 fi 298 if [ ! -f $_pidfile ]; then 299 debug "pid file {$_pidfile): not readable." 300 return 301 fi 302 read _pid _junk < $_pidfile 303 if [ -z "$_pid" ]; then 304 debug "pid file {$_pidfile): no pid in file." 305 return 306 fi 307 _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" 308} 309 310# 311# check_process procname [interpreter] 312# Ensures that a process (or processes) named procname is running. 313# Prints a list of matching PIDs. 314# interpreter is optional; see _find_processes() for details. 315# 316check_process() 317{ 318 _procname=$1 319 _interpreter=$2 320 if [ -z "$_procname" ]; then 321 err 3 'USAGE: check_process procname [interpreter]' 322 fi 323 _find_processes $_procname ${_interpreter:-.} '-ax' 324} 325 326# 327# _find_processes procname interpreter psargs 328# Search for procname in the output of ps generated by psargs. 329# Prints the PIDs of any matching processes, space separated. 330# 331# If interpreter == ".", check the following variations of procname 332# against the first word of each command: 333# procname 334# `basename procname` 335# `basename procname` + ":" 336# "(" + `basename procname` + ")" 337# 338# If interpreter != ".", read the first line of procname, remove the 339# leading #!, normalise whitespace, append procname, and attempt to 340# match that against each command, either as is, or with extra words 341# at the end. 342# 343_find_processes() 344{ 345 if [ $# -ne 3 ]; then 346 err 3 'USAGE: _find_processes procname interpreter psargs' 347 fi 348 _procname=$1 349 _interpreter=$2 350 _psargs=$3 351 352 _pref= 353 if [ $_interpreter != "." ]; then # an interpreted script 354 read _interp < $_procname # read interpreter name 355 _interp=${_interp#\#!} # strip #! 356 set -- $_interp 357 if [ $_interpreter != $1 ]; then 358 warn "\$command_interpreter $_interpreter != $1" 359 fi 360 _interp="$* $_procname" # cleanup spaces, add _procname 361 _interpbn="$1" # the interpreter binary 362 _fp_args='_argv' 363 _fp_match='case "$_argv" in 364 "${_interpbn##*/}: "$_procname*|${_interp}|"${_interp} "*)' 365 else # a normal daemon 366 _procnamebn=${_procname##*/} 367 _fp_args='_arg0 _argv' 368 _fp_match='case "$_arg0" in 369 $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")' 370 fi 371 372 _proccheck=' 373 ps -o "pid,command" '"$_psargs"' | 374 while read _npid '"$_fp_args"'; do 375 case "$_npid" in 376 PID) 377 continue ;; 378 esac ; '"$_fp_match"' 379 echo -n "$_pref$_npid" ; 380 _pref=" " 381 ;; 382 esac 383 done' 384 385# debug "in _find_processes: proccheck is ($_proccheck)." 386 eval $_proccheck 387} 388 389# 390# wait_for_pids pid [pid ...] 391# spins until none of the pids exist 392# 393wait_for_pids() 394{ 395 _list=$* 396 if [ -z "$_list" ]; then 397 return 398 fi 399 _prefix= 400 while true; do 401 _nlist=""; 402 for _j in $_list; do 403 if kill -0 $_j 2>/dev/null; then 404 _nlist="${_nlist}${_nlist:+ }$_j" 405 fi 406 done 407 if [ -z "$_nlist" ]; then 408 break 409 fi 410 _list=$_nlist 411 echo -n ${_prefix:-"Waiting for PIDS: "}$_list 412 _prefix=", " 413 sleep 2 414 done 415 if [ -n "$_prefix" ]; then 416 echo "." 417 fi 418} 419 420# 421# get_pidfile_from_conf string file 422# 423# Takes a string to search for in the specified file. 424# Ignores lines with traditional comment characters. 425# 426# Example: 427# 428# if get_pidfile_from_conf string file; then 429# pidfile="$_pidfile_from_conf" 430# else 431# pidfile='appropriate default' 432# fi 433# 434get_pidfile_from_conf() 435{ 436 if [ -z "$1" -o -z "$2" ]; then 437 err 3 "USAGE: get_pidfile_from_conf string file ($name)" 438 fi 439 440 local string file line 441 442 string="$1" ; file="$2" 443 444 if [ ! -s "$file" ]; then 445 err 3 "get_pidfile_from_conf: $file does not exist ($name)" 446 fi 447 448 while read line; do 449 case "$line" in 450 *[#\;]*${string}*) continue ;; 451 *${string}*) break ;; 452 esac 453 done < $file 454 455 if [ -n "$line" ]; then 456 line=${line#*/} 457 _pidfile_from_conf="/${line%%[\"\;]*}" 458 else 459 return 1 460 fi 461} 462 463# 464# check_startmsgs 465# If rc_quiet is set (usually as a result of using faststart at 466# boot time) check if rc_startmsgs is enabled. 467# 468check_startmsgs() 469{ 470 if [ -n "$rc_quiet" ]; then 471 checkyesno rc_startmsgs 472 else 473 return 0 474 fi 475} 476 477# 478# run_rc_command argument 479# Search for argument in the list of supported commands, which is: 480# "start stop restart rcvar status poll ${extra_commands}" 481# If there's a match, run ${argument}_cmd or the default method 482# (see below). 483# 484# If argument has a given prefix, then change the operation as follows: 485# Prefix Operation 486# ------ --------- 487# fast Skip the pid check, and set rc_fast=yes, rc_quiet=yes 488# force Set ${rcvar} to YES, and set rc_force=yes 489# one Set ${rcvar} to YES 490# quiet Don't output some diagnostics, and set rc_quiet=yes 491# 492# The following globals are used: 493# 494# Name Needed Purpose 495# ---- ------ ------- 496# provide_list (gen) list of keywords provided by current rcng file 497# 498# name y Name of script. 499# 500# command n Full path to command. 501# Not needed if ${rc_arg}_cmd is set for 502# each keyword. 503# 504# command_args n Optional args/shell directives for command. 505# 506# command_interpreter n If not empty, command is interpreted, so 507# call check_{pidfile,process}() appropriately. 508# 509# extra_commands n List of extra commands supported. 510# 511# pidfile n If set, use check_pidfile $pidfile $command, 512# otherwise use check_process $command. 513# In either case, only check if $command is set. 514# 515# procname n Process name to check for instead of $command. 516# 517# rcvar n This is checked with checkyesno to determine 518# if the action should be run. 519# 520# ${name}_chroot n Directory to chroot to before running ${command} 521# Requires /usr to be mounted. 522# 523# ${name}_chdir n Directory to cd to before running ${command} 524# (if not using ${name}_chroot). 525# 526# ${name}_flags n Arguments to call ${command} with. 527# NOTE: $flags from the parent environment 528# can be used to override this. 529# 530# ${name}_nice n Nice level to run ${command} at. 531# 532# ${name}_user n User to run ${command} as, using su(1) if not 533# using ${name}_chroot. 534# Requires /usr to be mounted. 535# 536# ${name}_group n Group to run chrooted ${command} as. 537# Requires /usr to be mounted. 538# 539# ${name}_groups n Comma separated list of supplementary groups 540# to run the chrooted ${command} with. 541# Requires /usr to be mounted. 542# 543# ${rc_arg}_cmd n If set, use this as the method when invoked; 544# Otherwise, use default command (see below) 545# 546# ${rc_arg}_precmd n If set, run just before performing the 547# ${rc_arg}_cmd method in the default 548# operation (i.e, after checking for required 549# bits and process (non)existence). 550# If this completes with a non-zero exit code, 551# don't run ${rc_arg}_cmd. 552# 553# ${rc_arg}_postcmd n If set, run just after performing the 554# ${rc_arg}_cmd method, if that method 555# returned a zero exit code. 556# 557# required_dirs n If set, check for the existence of the given 558# directories before running the default 559# (re)start command. 560# 561# required_files n If set, check for the readability of the given 562# files before running the default (re)start 563# command. 564# 565# required_modules n If set, ensure the given kernel modules are 566# loaded before running a (re)start command. 567# The check and possible loads are actually 568# done after start_precmd so that the modules 569# aren't loaded in vain, should the precmd 570# return a non-zero status to indicate a error. 571# If a word in the list looks like "foo:bar", 572# "foo" is the KLD file name and "bar" is the 573# module name. If a word looks like "foo~bar", 574# "foo" is the KLD file name and "bar" is a 575# egrep(1) pattern matching the module name. 576# Otherwise the module name is assumed to be 577# the same as the KLD file name, which is most 578# common. See load_kld(). 579# 580# required_vars n If set, perform checkyesno on each of the 581# listed variables before running the default 582# (re)start command. 583# 584# Default behaviour for a given argument, if no override method is 585# provided: 586# 587# Argument Default behaviour 588# -------- ----------------- 589# start if !running && checkyesno ${rcvar} 590# ${command} 591# 592# stop if ${pidfile} 593# rc_pid=$(check_pidfile $pidfile $command) 594# else 595# rc_pid=$(check_process $command) 596# kill $sig_stop $rc_pid 597# wait_for_pids $rc_pid 598# ($sig_stop defaults to TERM.) 599# 600# reload Similar to stop, except use $sig_reload instead, 601# and doesn't wait_for_pids. 602# $sig_reload defaults to HUP. 603# 604# restart Run `stop' then `start'. 605# 606# status Show if ${command} is running, etc. 607# 608# poll Wait for ${command} to exit. 609# 610# rcvar Display what rc.conf variable is used (if any). 611# 612# Variables available to methods, and after run_rc_command() has 613# completed: 614# 615# Variable Purpose 616# -------- ------- 617# rc_arg Argument to command, after fast/force/one processing 618# performed 619# 620# rc_flags Flags to start the default command with. 621# Defaults to ${name}_flags, unless overridden 622# by $flags from the environment. 623# This variable may be changed by the precmd method. 624# 625# rc_pid PID of command (if appropriate) 626# 627# rc_fast Not empty if "fast" was provided (q.v.) 628# 629# rc_force Not empty if "force" was provided (q.v.) 630# 631# rc_quiet Not empty if "quiet" was provided 632# 633# 634dummy_rc_command() 635{ 636 rc_arg=$1 637 638 case "$rc_arg" in 639 fast*) # "fast" prefix; don't check pid 640 rc_arg=${rc_arg#fast} 641 ;; 642 force*) # "force" prefix; always start 643 rc_arg=${rc_arg#force} 644 ;; 645 one*) # "one" prefix; set ${rcvar}=yes 646 rc_arg=${rc_arg#one} 647 ;; 648 esac 649 set_provide_list $rc_arg $RC_CONFIGURED 650 return 0 651} 652 653run_rc_command() 654{ 655 _return=0 656 rc_arg=$1 657 if [ -z "$name" ]; then 658 err 3 'run_rc_command: $name is not set.' 659 fi 660 661 # Don't repeat the first argument when passing additional command- 662 # line arguments to the command subroutines. 663 # 664 shift 1 665 rc_extra_args="$*" 666 667 case "$rc_arg" in 668 fast*) # "fast" prefix; don't check pid 669 rc_arg=${rc_arg#fast} 670 rc_fast=yes 671 rc_quiet=yes 672 ;; 673 force*) # "force" prefix; always start 674 rc_arg=${rc_arg#force} 675 rc_force=yes 676 if [ -n "${rcvar}" ]; then 677 eval ${rcvar}=YES 678 fi 679 ;; 680 one*) # "one" prefix; set ${rcvar}=yes 681 rc_arg=${rc_arg#one} 682 if [ -n "${rcvar}" ]; then 683 eval ${rcvar}=YES 684 fi 685 ;; 686 quiet*) # "quiet" prefix; omit some messages 687 _rc_prefix=quiet 688 rc_arg=${rc_arg#${_rc_prefix}} 689 rc_quiet=yes 690 ;; 691 esac 692 693 eval _override_command=\$${name}_program 694 if [ -n "$_override_command" ]; then 695 command=$_override_command 696 fi 697 698 _keywords="start stop restart rcvar $extra_commands" 699 rc_pid= 700 _pidcmd= 701 _procname=${procname:-${command}} 702 703 # setup pid check command if not fast 704 if [ -z "$rc_fast" -a -n "$_procname" ]; then 705 if [ -n "$pidfile" ]; then 706 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 707 else 708 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 709 fi 710 if [ -n "$_pidcmd" ]; then 711 _keywords="${_keywords} status poll" 712 fi 713 fi 714 715 if [ -z "$rc_arg" ]; then 716 rc_usage "$_keywords" 717 fi 718 719 if [ -n "$flags" ]; then # allow override from environment 720 rc_flags=$flags 721 else 722 eval rc_flags=\$${name}_flags 723 fi 724 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 725 _nice=\$${name}_nice _user=\$${name}_user \ 726 _group=\$${name}_group _groups=\$${name}_groups 727 728 if [ -n "$_user" ]; then # unset $_user if running as that user 729 if [ "$_user" = "$(id -un)" ]; then 730 unset _user 731 fi 732 fi 733 734 # if ${rcvar} is set, and $1 is not 735 # "rcvar", then run 736 # checkyesno ${rcvar} 737 # and return if that failed 738 # 739 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then 740 if ! checkyesno ${rcvar}; then 741 set_provide_list $rc_arg $RC_DISABLED 742 return 0 743 fi 744 fi 745 746 eval $_pidcmd # determine the pid if necessary 747 748 for _elem in $_keywords; do 749 if [ "$_elem" != "$rc_arg" ]; then 750 continue 751 fi 752 753 # if there's a custom ${XXX_cmd}, 754 # run that instead of the default 755 # 756 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 757 _postcmd=\$${rc_arg}_postcmd 758 if [ -n "$_cmd" ]; then 759 # if the precmd failed and force 760 # isn't set, exit 761 # 762 if [ -n "$_precmd" ]; then 763 debug "run_rc_command: evaluating ${_precmd}()." 764 eval $_precmd $rc_extra_args 765 766 _return=$? 767 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 768 fi 769 770 if [ -n "$_cmd" ]; then 771 debug "run_rc_command: evaluating ${_cmd}()." 772 eval $_cmd $rc_extra_args 773 _return=$? 774 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 775 fi 776 777 if [ -n "$_postcmd" ]; then 778 debug "run_rc_command: evaluating ${_postcmd}()." 779 eval $_postcmd $rc_extra_args 780 _return=$? 781 check_early_term $rc_arg $_return "" || return $(($?-1)) 782 fi 783 set_provide_list $rc_arg $_return 784 adjust_return_code $_return 785 return $? 786 fi 787 788 case "$rc_arg" in # default operations... 789 790 status) 791 if [ -n "$rc_pid" ]; then 792 echo "${name} is running as pid $rc_pid." 793 else 794 echo "${name} is not running." 795 return 1 796 fi 797 ;; 798 799 start) 800 if [ -n "$rc_pid" ]; then 801 if [ -z "$rc_quiet" ]; then 802 echo "${name} already running? (pid=$rc_pid)." 803 fi 804 exit 1 805 fi 806 807 if [ ! -x $command ]; then 808 info "run_rc_command: cannot run ($command)." 809 set_provide_list $rc_arg $RC_FAILED 810 adjust_return_code $RC_FAILED 811 return $? 812 fi 813 814 # check for required variables, 815 # directories, and files 816 # 817 for _f in $required_vars; do 818 if ! checkyesno $_f; then 819 warn "\$${_f} is not set." 820 if [ -z "$rc_force" ]; then 821 set_provide_list $rc_arg $RC_FAILED 822 adjust_return_code $RC_FAILED 823 return $? 824 fi 825 fi 826 done 827 for _f in $required_dirs; do 828 if [ ! -d "${_f}/." ]; then 829 warn "${_f} is not a directory." 830 if [ -z "$rc_force" ]; then 831 set_provide_list $rc_arg $RC_FAILED 832 adjust_return_code $RC_FAILED 833 return $? 834 fi 835 fi 836 done 837 for _f in $required_files; do 838 if [ ! -r "${_f}" ]; then 839 warn "${_f} is not readable." 840 if [ -z "$rc_force" ]; then 841 set_provide_list $rc_arg $RC_FAILED 842 adjust_return_code $RC_FAILED 843 return $? 844 fi 845 fi 846 done 847 for _f in $required_modules; do 848 case "${_f}" in 849 *~*) _args="-e ${_f#*~} ${_f%%~*}" ;; 850 *:*) _args="-m ${_f#*:} ${_f%%:*}" ;; 851 *) _args="${_f}" ;; 852 esac 853 if ! load_kld ${_args}; then 854 if [ -z "$rc_force" ]; then 855 set_provide_list $rc_arg $RC_FAILED 856 adjust_return_code $RC_FAILED 857 return $? 858 fi 859 fi 860 done 861 862 # if the precmd failed and force 863 # isn't set, exit 864 # 865 if [ -n "${_precmd}" ]; then 866 debug "run_rc_command: evaluating ${_precmd}()." 867 eval $_precmd 868 _return=$? 869 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 870 fi 871 872 # setup the command to run, and run it 873 # 874 echo "Starting ${name}." 875 if [ -n "$_chroot" ]; then 876 _doit="\ 877${_nice:+nice -n $_nice }\ 878chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 879$_chroot $command $rc_flags $command_args" 880 else 881 _doit="\ 882${_chdir:+cd $_chdir; }\ 883${_nice:+nice -n $_nice }\ 884$command $rc_flags $command_args" 885 if [ -n "$_user" ]; then 886 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 887 fi 888 fi 889 890 # if the cmd failed and force 891 # isn't set, exit 892 # 893 debug "run_rc_command: _doit: $_doit" 894 eval $_doit 895 _return=$? 896 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 897 # finally, run postcmd 898 # 899 if [ -n "${_postcmd}" ]; then 900 debug "run_rc_command: evaluating ${_postcmd}()." 901 eval $_postcmd 902 fi 903 ;; 904 905 stop) 906 if [ -z "$rc_pid" ]; then 907 if [ -n "$pidfile" ]; then 908 echo \ 909 "${name} not running? (check $pidfile)." 910 else 911 echo "${name} not running?" 912 fi 913 set_provide_list $rc_arg $RC_STOPPED 914 exit 1 915 fi 916 917 # if the precmd failed and force 918 # isn't set, exit 919 # 920 if [ -n "$_precmd" ]; then 921 eval $_precmd 922 _return=$? 923 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 924 fi 925 926 # send the signal to stop 927 # 928 echo "Stopping ${name}." 929 _doit="kill -${sig_stop:-TERM} $rc_pid" 930 if [ -n "$_user" ]; then 931 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 932 fi 933 934 # if the stop cmd failed and force 935 # isn't set, exit 936 # 937 eval $_doit 938 _return=$? 939 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 940 # wait for the command to exit, 941 # and run postcmd. 942 sleep 0.1 943 wait_for_pids $rc_pid 944 if [ -n "$_postcmd" ]; then 945 eval $_postcmd 946 _return=$? 947 fi 948 ;; 949 950 reload) 951 if [ -z "$rc_pid" ]; then 952 if [ -n "$pidfile" ]; then 953 echo \ 954 "${name} not running? (check $pidfile)." 955 else 956 echo "${name} not running?" 957 fi 958 set_provide_list $rc_arg $RC_FAILED 959 exit 1 960 fi 961 echo "Reloading ${name} config files." 962 if [ -n "$_precmd" ]; then 963 eval $_precmd 964 _return=$? 965 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 966 fi 967 _doit="kill -${sig_reload:-HUP} $rc_pid" 968 if [ -n "$_user" ]; then 969 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 970 fi 971 eval $_doit 972 _return=$? 973 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 974 if [ -n "$_postcmd" ]; then 975 eval $_postcmd 976 _return=$? 977 fi 978 ;; 979 980 restart) 981 if [ -n "$_precmd" ]; then 982 eval $_precmd $rc_extra_args 983 _return=$? 984 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 985 fi 986 # prevent restart being called more 987 # than once by any given script 988 # 989 if [ -n "$_rc_restart_done" ]; then 990 return 0 991 fi 992 _rc_restart_done=YES 993 994 ( $0 ${rc_force:+force}stop $rc_extra_args ) 995 $0 ${rc_force:+force}start $rc_extra_args 996 _return=$? 997 998 if [ -n "$_postcmd" ]; then 999 eval $_postcmd $rc_extra_args 1000 adjust_return_code $? 1001 _return=$? 1002 fi 1003 # Do not set_provide_list(), the start command above 1004 # will have done it for us and we do not know the 1005 # actual RC code to base a setting on here. 1006 # 1007 return $_return 1008 ;; 1009 1010 poll) 1011 if [ -n "$rc_pid" ]; then 1012 wait_for_pids $rc_pid 1013 fi 1014 ;; 1015 1016 rcvar) 1017 echo "# $name" 1018 if [ -n "$rcvar" ]; then 1019 if checkyesno ${rcvar}; then 1020 echo "\$${rcvar}=YES" 1021 else 1022 echo "\$${rcvar}=NO" 1023 fi 1024 fi 1025 ;; 1026 1027 *) 1028 rc_usage "$_keywords" 1029 ;; 1030 1031 esac 1032 set_provide_list $rc_arg $_return 1033 adjust_return_code $_return 1034 return $? 1035 done 1036 1037 echo 1>&2 "$0: unknown directive '$rc_arg'." 1038 rc_usage "$_keywords" 1039 exit 1 1040} 1041 1042# 1043# run_rc_script file arg 1044# Start the script `file' with `arg', and correctly handle the 1045# return value from the script. If `file' ends with `.sh', it's 1046# sourced into the current environment. If `file' appears to be 1047# a backup or scratch file, ignore it. Otherwise if it's 1048# executable run as a child process. 1049# 1050run_rc_script() 1051{ 1052 _file=$1 1053 _arg=$2 1054 if [ -z "$_file" -o -z "$_arg" ]; then 1055 err 3 'USAGE: run_rc_script file arg' 1056 fi 1057 1058 trap "echo 'Reboot interrupted'; exit 1" 3 1059 1060 unset name command command_args command_interpreter \ 1061 extra_commands pidfile procname \ 1062 rcvar required_dirs required_files required_vars 1063 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 1064 1065 case "$_file" in 1066 *.sh) # run in current shell 1067 set $_arg ; . $_file 1068 ;; 1069 *[~#]|*.OLD|*.orig) # scratch file; skip 1070 warn "Ignoring scratch file $_file" 1071 ;; 1072 *) # run in subshell 1073 if [ -x $_file ]; then 1074 if [ -n "$rc_fast_and_loose" ]; then 1075 set $_arg ; . $_file 1076 else 1077 ( trap "echo 'Reboot interrupted'; exit 1" 3 1078 set $_arg ; . $_file ) 1079 fi 1080 fi 1081 ;; 1082 esac 1083} 1084 1085# Code common to scripts that need to load a kernel module 1086# if it isn't in the kernel yet. Syntax: 1087# load_kld [-e regex] [-m module] file 1088# where -e or -m chooses the way to check if the module 1089# is already loaded: 1090# regex is egrep'd in the output from `kldstat -v', 1091# module is passed to `kldstat -m'. 1092# The default way is as though `-m file' were specified. 1093load_kld() 1094{ 1095 local _loaded _mod _opt _re 1096 1097 while getopts "e:m:" _opt; do 1098 case "$_opt" in 1099 e) _re="$OPTARG" ;; 1100 m) _mod="$OPTARG" ;; 1101 *) err 3 'USAGE: load_kld [-e regex] [-m module] file' ;; 1102 esac 1103 done 1104 shift $(($OPTIND - 1)) 1105 if [ $# -ne 1 ]; then 1106 err 3 'USAGE: load_kld [-e regex] [-m module] file' 1107 fi 1108 _mod=${_mod:-$1} 1109 _loaded=false 1110 if [ -n "$_re" ]; then 1111 if kldstat -v | egrep -q -e "$_re"; then 1112 _loaded=true 1113 fi 1114 else 1115 if kldstat -q -m "$_mod"; then 1116 _loaded=true 1117 fi 1118 fi 1119 if ! $_loaded; then 1120 if ! kldload "$1"; then 1121 warn "Unable to load kernel module $1" 1122 return 1 1123 else 1124 info "$1 kernel module loaded." 1125 fi 1126 else 1127 debug "load_kld: $1 kernel module already loaded." 1128 fi 1129 return 0 1130} 1131 1132 1133# ltr str src dst 1134# Change every $src in $str to $dst. 1135# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor 1136# awk(1). 1137ltr() 1138{ 1139 local _str _src _dst _out _com 1140 _str=$1 1141 _src=$2 1142 _dst=$3 1143 _out="" 1144 1145 IFS=${_src} 1146 for _com in ${_str}; do 1147 if [ -z "${_out}" ]; then 1148 _out="${_com}" 1149 else 1150 _out="${_out}${_dst}${_com}" 1151 fi 1152 done 1153 echo "${_out}" 1154} 1155 1156# 1157# load_rc_config 1158# Source in the configuration file for a given command. 1159# 1160load_rc_config() 1161{ 1162 _command=$1 1163 if [ -z "$_command" ]; then 1164 err 3 'USAGE: load_rc_config command' 1165 fi 1166 1167 if [ -z "$_rc_conf_loaded" ]; then 1168 if [ -r /etc/defaults/rc.conf ]; then 1169 debug "Sourcing /etc/defaults/rc.conf" 1170 . /etc/defaults/rc.conf 1171 source_rc_confs 1172 elif [ -r /etc/rc.conf ]; then 1173 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 1174 . /etc/rc.conf 1175 fi 1176 _rc_conf_loaded=YES 1177 fi 1178 if [ -f /etc/rc.conf.d/"$_command" ]; then 1179 debug "Sourcing /etc/rc.conf.d/${_command}" 1180 . /etc/rc.conf.d/"$_command" 1181 fi 1182 1183 # XXX - Deprecated variable name support 1184 # 1185 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable" 1186 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program" 1187 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags" 1188 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable" 1189 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" 1190 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" 1191 1192} 1193 1194# 1195# rc_usage commands 1196# Print a usage string for $0, with `commands' being a list of 1197# valid commands. 1198# 1199rc_usage() 1200{ 1201 echo -n 1>&2 "Usage: $0 [fast|force|one|quiet](" 1202 1203 _sep= 1204 for _elem in $*; do 1205 echo -n 1>&2 "$_sep$_elem" 1206 _sep="|" 1207 done 1208 echo 1>&2 ")" 1209 exit 1 1210} 1211 1212# 1213# err exitval message 1214# Display message to stderr and log to the syslog, and exit with exitval. 1215# 1216err() 1217{ 1218 exitval=$1 1219 shift 1220 1221 if [ -x /usr/bin/logger ]; then 1222 logger "$0: ERROR: $*" 1223 fi 1224 echo 1>&2 "$0: ERROR: $*" 1225 exit $exitval 1226} 1227 1228# 1229# warn message 1230# Display message to stderr and log to the syslog. 1231# 1232warn() 1233{ 1234 if [ -x /usr/bin/logger ]; then 1235 logger "$0: WARNING: $*" 1236 fi 1237 echo 1>&2 "$0: WARNING: $*" 1238} 1239 1240# 1241# info message 1242# Display informational message to stdout and log to syslog. 1243# 1244info() 1245{ 1246 case ${rc_info} in 1247 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1248 if [ -x /usr/bin/logger ]; then 1249 logger "$0: INFO: $*" 1250 fi 1251 echo "$0: INFO: $*" 1252 ;; 1253 esac 1254} 1255 1256# 1257# debug message 1258# If debugging is enabled in rc.conf output message to stderr. 1259# BEWARE that you don't call any subroutine that itself calls this 1260# function. 1261# 1262debug() 1263{ 1264 case ${rc_debug} in 1265 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1266 if [ -x /usr/bin/logger ]; then 1267 logger "$0: INFO: $*" 1268 fi 1269 echo 1>&2 "$0: DEBUG: $*" 1270 ;; 1271 esac 1272} 1273 1274# 1275# backup_file action file cur backup 1276# Make a backup copy of `file' into `cur', and save the previous 1277# version of `cur' as `backup' or use rcs for archiving. 1278# 1279# This routine checks the value of the backup_uses_rcs variable, 1280# which can be either YES or NO. 1281# 1282# The `action' keyword can be one of the following: 1283# 1284# add `file' is now being backed up (and is possibly 1285# being reentered into the backups system). `cur' 1286# is created and RCS files, if necessary, are 1287# created as well. 1288# 1289# update `file' has changed and needs to be backed up. 1290# If `cur' exists, it is copied to to `back' or 1291# checked into RCS (if the repository file is old), 1292# and then `file' is copied to `cur'. Another RCS 1293# check in done here if RCS is being used. 1294# 1295# remove `file' is no longer being tracked by the backups 1296# system. If RCS is not being used, `cur' is moved 1297# to `back', otherwise an empty file is checked in, 1298# and then `cur' is removed. 1299# 1300# 1301backup_file() 1302{ 1303 _action=$1 1304 _cpfile=$2 1305 _cur=$3 1306 _back=$4 1307 1308 if checkyesno backup_uses_rcs; then 1309 _msg0="backup archive" 1310 _msg1="update" 1311 1312 # ensure that history file is not locked 1313 if [ -f $_cur,v ]; then 1314 rcs -q -u -U -M $_cur 1315 fi 1316 1317 # ensure after switching to rcs that the 1318 # current backup is not lost 1319 if [ -f $_cur ]; then 1320 # no archive, or current newer than archive 1321 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 1322 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1323 rcs -q -kb -U $_cur 1324 co -q -f -u $_cur 1325 fi 1326 fi 1327 1328 case $_action in 1329 add|update) 1330 cp -p $_cpfile $_cur 1331 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1332 rcs -q -kb -U $_cur 1333 co -q -f -u $_cur 1334 chown root:wheel $_cur $_cur,v 1335 ;; 1336 remove) 1337 cp /dev/null $_cur 1338 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1339 rcs -q -kb -U $_cur 1340 chown root:wheel $_cur $_cur,v 1341 rm $_cur 1342 ;; 1343 esac 1344 else 1345 case $_action in 1346 add|update) 1347 if [ -f $_cur ]; then 1348 cp -p $_cur $_back 1349 fi 1350 cp -p $_cpfile $_cur 1351 chown root:wheel $_cur 1352 ;; 1353 remove) 1354 mv -f $_cur $_back 1355 ;; 1356 esac 1357 fi 1358} 1359 1360# devfs_mount_jail dir 1361# Mounts a devfs file system appropriate for jails 1362# on the directory dir. 1363# This function returns non-zero if an error occurs. 1364# 1365devfs_mount_jail() 1366{ 1367 local jdev _me 1368 jdev="$1" 1369 _me="devfs_mount_jail" 1370 1371 if ! devfs_domount "$jdev" $rs; then 1372 warn "$_me: devfs was not mounted on $jdev" 1373 return 1 1374 fi 1375 return 0 1376} 1377 1378# devfs_domount dir 1379# Mount devfs on dir. 1380# Returns 0 on success. 1381# 1382devfs_domount() 1383{ 1384 local devdir _me 1385 devdir="$1" 1386 _me="devfs_domount()" 1387 1388 if [ -z "$devdir" ]; then 1389 warn "$_me: you must specify a mount-point" 1390 return 1 1391 fi 1392 1393 debug "$_me: mount-point is ($devdir)" 1394 if ! mount -t devfs devfs "$devdir"; then 1395 warn "$_me: Unable to mount devfs on $devdir" 1396 return 1 1397 fi 1398 1399return 0 1400} 1401 1402# Find scripts in local_startup directories. 1403find_local_scripts() { 1404 local_rc='' 1405 for dir in ${local_startup}; do 1406 if [ -d "${dir}" ]; then 1407 for file in `grep -l '^# PROVIDE:' ${dir}/* 2>/dev/null`; do 1408 case "$file" in 1409 *.sample) ;; 1410 *) if [ -x "$file" ]; then 1411 local_rc="${local_rc} ${file}" 1412 fi 1413 ;; 1414 esac 1415 done 1416 fi 1417 done 1418} 1419