1# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $ 2# $FreeBSD: head/etc/rc.subr 275359 2014-12-01 12:17:42Z des $ 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}_env n Environment variables to run ${command} with. 531# 532# ${name}_nice n Nice level to run ${command} at. 533# 534# ${name}_user n User to run ${command} as, using su(1) if not 535# using ${name}_chroot. 536# Requires /usr to be mounted. 537# 538# ${name}_group n Group to run chrooted ${command} as. 539# Requires /usr to be mounted. 540# 541# ${name}_groups n Comma separated list of supplementary groups 542# to run the chrooted ${command} with. 543# Requires /usr to be mounted. 544# 545# ${name}_prepend n Command added before ${command}. 546# 547# ${rc_arg}_cmd n If set, use this as the method when invoked; 548# Otherwise, use default command (see below) 549# 550# ${rc_arg}_precmd n If set, run just before performing the 551# ${rc_arg}_cmd method in the default 552# operation (i.e, after checking for required 553# bits and process (non)existence). 554# If this completes with a non-zero exit code, 555# don't run ${rc_arg}_cmd. 556# 557# ${rc_arg}_postcmd n If set, run just after performing the 558# ${rc_arg}_cmd method, if that method 559# returned a zero exit code. 560# 561# required_dirs n If set, check for the existence of the given 562# directories before running the default 563# (re)start command. 564# 565# required_files n If set, check for the readability of the given 566# files before running the default (re)start 567# command. 568# 569# required_modules n If set, ensure the given kernel modules are 570# loaded before running a (re)start command. 571# The check and possible loads are actually 572# done after start_precmd so that the modules 573# aren't loaded in vain, should the precmd 574# return a non-zero status to indicate a error. 575# If a word in the list looks like "foo:bar", 576# "foo" is the KLD file name and "bar" is the 577# module name. If a word looks like "foo~bar", 578# "foo" is the KLD file name and "bar" is a 579# egrep(1) pattern matching the module name. 580# Otherwise the module name is assumed to be 581# the same as the KLD file name, which is most 582# common. See load_kld(). 583# 584# required_vars n If set, perform checkyesno on each of the 585# listed variables before running the default 586# (re)start command. 587# 588# Default behaviour for a given argument, if no override method is 589# provided: 590# 591# Argument Default behaviour 592# -------- ----------------- 593# start if !running && checkyesno ${rcvar} 594# ${command} 595# 596# stop if ${pidfile} 597# rc_pid=$(check_pidfile $pidfile $command) 598# else 599# rc_pid=$(check_process $command) 600# kill $sig_stop $rc_pid 601# wait_for_pids $rc_pid 602# ($sig_stop defaults to TERM.) 603# 604# reload Similar to stop, except use $sig_reload instead, 605# and doesn't wait_for_pids. 606# $sig_reload defaults to HUP. 607# 608# restart Run `stop' then `start'. 609# 610# status Show if ${command} is running, etc. 611# 612# poll Wait for ${command} to exit. 613# 614# rcvar Display what rc.conf variable is used (if any). 615# 616# Variables available to methods, and after run_rc_command() has 617# completed: 618# 619# Variable Purpose 620# -------- ------- 621# rc_arg Argument to command, after fast/force/one processing 622# performed 623# 624# rc_flags Flags to start the default command with. 625# Defaults to ${name}_flags, unless overridden 626# by $flags from the environment. 627# This variable may be changed by the precmd method. 628# 629# rc_pid PID of command (if appropriate) 630# 631# rc_fast Not empty if "fast" was provided (q.v.) 632# 633# rc_force Not empty if "force" was provided (q.v.) 634# 635# rc_quiet Not empty if "quiet" was provided 636# 637# 638dummy_rc_command() 639{ 640 rc_arg=$1 641 642 case "$rc_arg" in 643 fast*) # "fast" prefix; don't check pid 644 rc_arg=${rc_arg#fast} 645 ;; 646 force*) # "force" prefix; always start 647 rc_arg=${rc_arg#force} 648 ;; 649 one*) # "one" prefix; set ${rcvar}=yes 650 rc_arg=${rc_arg#one} 651 ;; 652 esac 653 set_provide_list $rc_arg $RC_CONFIGURED 654 return 0 655} 656 657run_rc_command() 658{ 659 _return=0 660 rc_arg=$1 661 if [ -z "$name" ]; then 662 err 3 'run_rc_command: $name is not set.' 663 fi 664 665 # Don't repeat the first argument when passing additional command- 666 # line arguments to the command subroutines. 667 # 668 shift 1 669 rc_extra_args="$*" 670 671 case "$rc_arg" in 672 fast*) # "fast" prefix; don't check pid 673 rc_arg=${rc_arg#fast} 674 rc_fast=yes 675 rc_quiet=yes 676 ;; 677 force*) # "force" prefix; always start 678 rc_arg=${rc_arg#force} 679 rc_force=yes 680 if [ -n "${rcvar}" ]; then 681 eval ${rcvar}=YES 682 fi 683 ;; 684 one*) # "one" prefix; set ${rcvar}=yes 685 rc_arg=${rc_arg#one} 686 if [ -n "${rcvar}" ]; then 687 eval ${rcvar}=YES 688 fi 689 ;; 690 quiet*) # "quiet" prefix; omit some messages 691 _rc_prefix=quiet 692 rc_arg=${rc_arg#${_rc_prefix}} 693 rc_quiet=yes 694 ;; 695 esac 696 697 eval _override_command=\$${name}_program 698 if [ -n "$_override_command" ]; then 699 command=$_override_command 700 fi 701 702 _keywords="start stop restart rcvar $extra_commands" 703 rc_pid= 704 _pidcmd= 705 _procname=${procname:-${command}} 706 707 # setup pid check command if not fast 708 if [ -z "$rc_fast" -a -n "$_procname" ]; then 709 if [ -n "$pidfile" ]; then 710 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 711 else 712 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 713 fi 714 if [ -n "$_pidcmd" ]; then 715 _keywords="${_keywords} status poll" 716 fi 717 fi 718 719 if [ -z "$rc_arg" ]; then 720 rc_usage "$_keywords" 721 fi 722 723 if [ -n "$flags" ]; then # allow override from environment 724 rc_flags=$flags 725 else 726 eval rc_flags=\$${name}_flags 727 fi 728 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 729 _nice=\$${name}_nice _user=\$${name}_user \ 730 _group=\$${name}_group _groups=\$${name}_groups \ 731 _env=\$${name}_env _prepend=\$${name}_prepend 732 733 if [ -n "$_user" ]; then # unset $_user if running as that user 734 if [ "$_user" = "$(id -un)" ]; then 735 unset _user 736 fi 737 fi 738 739 # if ${rcvar} is set, and $1 is not 740 # "rcvar", then run 741 # checkyesno ${rcvar} 742 # and return if that failed 743 # 744 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then 745 if ! checkyesno ${rcvar}; then 746 set_provide_list $rc_arg $RC_DISABLED 747 return 0 748 fi 749 fi 750 751 eval $_pidcmd # determine the pid if necessary 752 753 for _elem in $_keywords; do 754 if [ "$_elem" != "$rc_arg" ]; then 755 continue 756 fi 757 758 # if there's a custom ${XXX_cmd}, 759 # run that instead of the default 760 # 761 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 762 _postcmd=\$${rc_arg}_postcmd 763 if [ -n "$_cmd" ]; then 764 # if the precmd failed and force 765 # isn't set, exit 766 # 767 if [ -n "$_precmd" ]; then 768 debug "run_rc_command: evaluating ${_precmd}()." 769 eval $_precmd $rc_extra_args 770 771 _return=$? 772 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 773 fi 774 775 if [ -n "$_cmd" ]; then 776 debug "run_rc_command: evaluating ${_cmd}()." 777 eval $_cmd $rc_extra_args 778 _return=$? 779 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 780 fi 781 782 if [ -n "$_postcmd" ]; then 783 debug "run_rc_command: evaluating ${_postcmd}()." 784 eval $_postcmd $rc_extra_args 785 _return=$? 786 check_early_term $rc_arg $_return "" || return $(($?-1)) 787 fi 788 set_provide_list $rc_arg $_return 789 adjust_return_code $_return 790 return $? 791 fi 792 793 case "$rc_arg" in # default operations... 794 795 status) 796 if [ -n "$rc_pid" ]; then 797 echo "${name} is running as pid $rc_pid." 798 else 799 echo "${name} is not running." 800 return 1 801 fi 802 ;; 803 804 start) 805 if [ -n "$rc_pid" ]; then 806 if [ -z "$rc_quiet" ]; then 807 echo "${name} already running? (pid=$rc_pid)." 808 fi 809 exit 1 810 fi 811 812 if [ ! -x $command ]; then 813 info "run_rc_command: cannot run ($command)." 814 set_provide_list $rc_arg $RC_FAILED 815 adjust_return_code $RC_FAILED 816 return $? 817 fi 818 819 # check for required variables, 820 # directories, and files 821 # 822 for _f in $required_vars; do 823 if ! checkyesno $_f; then 824 warn "\$${_f} is not set." 825 if [ -z "$rc_force" ]; then 826 set_provide_list $rc_arg $RC_FAILED 827 adjust_return_code $RC_FAILED 828 return $? 829 fi 830 fi 831 done 832 for _f in $required_dirs; do 833 if [ ! -d "${_f}/." ]; then 834 warn "${_f} is not a directory." 835 if [ -z "$rc_force" ]; then 836 set_provide_list $rc_arg $RC_FAILED 837 adjust_return_code $RC_FAILED 838 return $? 839 fi 840 fi 841 done 842 for _f in $required_files; do 843 if [ ! -r "${_f}" ]; then 844 warn "${_f} is not readable." 845 if [ -z "$rc_force" ]; then 846 set_provide_list $rc_arg $RC_FAILED 847 adjust_return_code $RC_FAILED 848 return $? 849 fi 850 fi 851 done 852 for _f in $required_modules; do 853 case "${_f}" in 854 *~*) _args="-e ${_f#*~} ${_f%%~*}" ;; 855 *:*) _args="-m ${_f#*:} ${_f%%:*}" ;; 856 *) _args="${_f}" ;; 857 esac 858 if ! load_kld ${_args}; then 859 if [ -z "$rc_force" ]; then 860 set_provide_list $rc_arg $RC_FAILED 861 adjust_return_code $RC_FAILED 862 return $? 863 fi 864 fi 865 done 866 867 # if the precmd failed and force 868 # isn't set, exit 869 # 870 if [ -n "${_precmd}" ]; then 871 debug "run_rc_command: evaluating ${_precmd}()." 872 eval $_precmd 873 _return=$? 874 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 875 fi 876 877 # setup the command to run, and run it 878 # 879 echo "Starting ${name}." 880 if [ -n "$_chroot" ]; then 881 _doit="\ 882${_nice:+nice -n $_nice }\ 883${_env:+env $_env }\ 884chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 885$_chroot $command $rc_flags $command_args" 886 else 887 _doit="\ 888${_chdir:+cd $_chdir; }\ 889${_nice:+nice -n $_nice }\ 890${_env:+env $_env }\ 891$command $rc_flags $command_args" 892 if [ -n "$_user" ]; then 893 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 894 fi 895 if [ -n "$_prepend" ]; then 896 _doit="$_prepend $_doit" 897 fi 898 fi 899 900 # if the cmd failed and force 901 # isn't set, exit 902 # 903 debug "run_rc_command: _doit: $_doit" 904 eval $_doit 905 _return=$? 906 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 907 # finally, run postcmd 908 # 909 if [ -n "${_postcmd}" ]; then 910 debug "run_rc_command: evaluating ${_postcmd}()." 911 eval $_postcmd 912 fi 913 ;; 914 915 stop) 916 if [ -z "$rc_pid" ]; then 917 if [ -n "$pidfile" ]; then 918 echo \ 919 "${name} not running? (check $pidfile)." 920 else 921 echo "${name} not running?" 922 fi 923 set_provide_list $rc_arg $RC_STOPPED 924 exit 1 925 fi 926 927 # if the precmd failed and force 928 # isn't set, exit 929 # 930 if [ -n "$_precmd" ]; then 931 eval $_precmd 932 _return=$? 933 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 934 fi 935 936 # send the signal to stop 937 # 938 echo "Stopping ${name}." 939 _doit="kill -${sig_stop:-TERM} $rc_pid" 940 if [ -n "$_user" ]; then 941 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 942 fi 943 944 # if the stop cmd failed and force 945 # isn't set, exit 946 # 947 eval $_doit 948 _return=$? 949 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 950 # wait for the command to exit, 951 # and run postcmd. 952 sleep 0.1 953 wait_for_pids $rc_pid 954 if [ -n "$_postcmd" ]; then 955 eval $_postcmd 956 _return=$? 957 fi 958 ;; 959 960 reload) 961 if [ -z "$rc_pid" ]; then 962 if [ -n "$pidfile" ]; then 963 echo \ 964 "${name} not running? (check $pidfile)." 965 else 966 echo "${name} not running?" 967 fi 968 set_provide_list $rc_arg $RC_FAILED 969 exit 1 970 fi 971 echo "Reloading ${name} config files." 972 if [ -n "$_precmd" ]; then 973 eval $_precmd 974 _return=$? 975 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 976 fi 977 _doit="kill -${sig_reload:-HUP} $rc_pid" 978 if [ -n "$_user" ]; then 979 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 980 fi 981 eval $_doit 982 _return=$? 983 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 984 if [ -n "$_postcmd" ]; then 985 eval $_postcmd 986 _return=$? 987 fi 988 ;; 989 990 restart) 991 if [ -n "$_precmd" ]; then 992 eval $_precmd $rc_extra_args 993 _return=$? 994 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 995 fi 996 # prevent restart being called more 997 # than once by any given script 998 # 999 if [ -n "$_rc_restart_done" ]; then 1000 return 0 1001 fi 1002 _rc_restart_done=YES 1003 1004 ( $0 ${rc_force:+force}stop $rc_extra_args ) 1005 $0 ${rc_force:+force}start $rc_extra_args 1006 _return=$? 1007 1008 if [ -n "$_postcmd" ]; then 1009 eval $_postcmd $rc_extra_args 1010 adjust_return_code $? 1011 _return=$? 1012 fi 1013 # Do not set_provide_list(), the start command above 1014 # will have done it for us and we do not know the 1015 # actual RC code to base a setting on here. 1016 # 1017 return $_return 1018 ;; 1019 1020 poll) 1021 if [ -n "$rc_pid" ]; then 1022 wait_for_pids $rc_pid 1023 fi 1024 ;; 1025 1026 rcvar) 1027 echo "# $name" 1028 if [ -n "$rcvar" ]; then 1029 if checkyesno ${rcvar}; then 1030 echo "\$${rcvar}=YES" 1031 else 1032 echo "\$${rcvar}=NO" 1033 fi 1034 fi 1035 ;; 1036 1037 *) 1038 rc_usage "$_keywords" 1039 ;; 1040 1041 esac 1042 set_provide_list $rc_arg $_return 1043 adjust_return_code $_return 1044 return $? 1045 done 1046 1047 echo 1>&2 "$0: unknown directive '$rc_arg'." 1048 rc_usage "$_keywords" 1049 exit 1 1050} 1051 1052# 1053# Helper functions for run_rc_command: common code. 1054# They use such global variables besides the exported rc_* ones: 1055# 1056# name R/W 1057# ------------------ 1058# _precmd R 1059# _postcmd R 1060# _return W 1061# 1062_run_rc_precmd() 1063{ 1064 check_required_before "$rc_arg" || return 1 1065 1066 if [ -n "$_precmd" ]; then 1067 debug "run_rc_command: ${rc_arg}_precmd: $_precmd $rc_extra_args" 1068 eval "$_precmd $rc_extra_args" 1069 _return=$? 1070 1071 # If precmd failed and force isn't set, request exit. 1072 if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then 1073 return 1 1074 fi 1075 fi 1076 1077 check_required_after "$rc_arg" || return 1 1078 1079 return 0 1080} 1081 1082_run_rc_postcmd() 1083{ 1084 if [ -n "$_postcmd" ]; then 1085 debug "run_rc_command: ${rc_arg}_postcmd: $_postcmd $rc_extra_args" 1086 eval "$_postcmd $rc_extra_args" 1087 _return=$? 1088 fi 1089 return 0 1090} 1091 1092_run_rc_doit() 1093{ 1094 debug "run_rc_command: doit: $*" 1095 eval "$@" 1096 _return=$? 1097 1098 # If command failed and force isn't set, request exit. 1099 if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then 1100 return 1 1101 fi 1102 1103 return 0 1104} 1105 1106_run_rc_notrunning() 1107{ 1108 local _pidmsg 1109 1110 if [ -n "$pidfile" ]; then 1111 _pidmsg=" (check $pidfile)." 1112 else 1113 _pidmsg= 1114 fi 1115 echo 1>&2 "${name} not running?${_pidmsg}" 1116} 1117 1118_run_rc_killcmd() 1119{ 1120 local _cmd 1121 1122 _cmd="kill -$1 $rc_pid" 1123 if [ -n "$_user" ]; then 1124 _cmd="su -m ${_user} -c 'sh -c \"${_cmd}\"'" 1125 fi 1126 echo "$_cmd" 1127} 1128 1129# 1130# run_rc_script file arg 1131# Start the script `file' with `arg', and correctly handle the 1132# return value from the script. If `file' ends with `.sh', it's 1133# sourced into the current environment. If `file' appears to be 1134# a backup or scratch file, ignore it. Otherwise if it's 1135# executable run as a child process. 1136# 1137run_rc_script() 1138{ 1139 _file=$1 1140 _arg=$2 1141 if [ -z "$_file" -o -z "$_arg" ]; then 1142 err 3 'USAGE: run_rc_script file arg' 1143 fi 1144 1145 trap "echo 'Reboot interrupted'; exit 1" 3 1146 1147 unset name command command_args command_interpreter \ 1148 extra_commands pidfile procname \ 1149 rcvar required_dirs required_files required_vars 1150 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 1151 1152 case "$_file" in 1153 *.sh) # run in current shell 1154 set $_arg ; . $_file 1155 ;; 1156 *[~#]|*.OLD|*.orig) # scratch file; skip 1157 warn "Ignoring scratch file $_file" 1158 ;; 1159 *) # run in subshell 1160 if [ -x $_file ]; then 1161 if [ -n "$rc_fast_and_loose" ]; then 1162 set $_arg ; . $_file 1163 else 1164 ( trap "echo 'Reboot interrupted'; exit 1" 3 1165 set $_arg ; . $_file ) 1166 fi 1167 fi 1168 ;; 1169 esac 1170} 1171 1172# Code common to scripts that need to load a kernel module 1173# if it isn't in the kernel yet. Syntax: 1174# load_kld [-e regex] [-m module] file 1175# where -e or -m chooses the way to check if the module 1176# is already loaded: 1177# regex is egrep'd in the output from `kldstat -v', 1178# module is passed to `kldstat -m'. 1179# The default way is as though `-m file' were specified. 1180load_kld() 1181{ 1182 local _loaded _mod _opt _re 1183 1184 while getopts "e:m:" _opt; do 1185 case "$_opt" in 1186 e) _re="$OPTARG" ;; 1187 m) _mod="$OPTARG" ;; 1188 *) err 3 'USAGE: load_kld [-e regex] [-m module] file' ;; 1189 esac 1190 done 1191 shift $(($OPTIND - 1)) 1192 if [ $# -ne 1 ]; then 1193 err 3 'USAGE: load_kld [-e regex] [-m module] file' 1194 fi 1195 _mod=${_mod:-$1} 1196 _loaded=false 1197 if [ -n "$_re" ]; then 1198 if kldstat -v | egrep -q -e "$_re"; then 1199 _loaded=true 1200 fi 1201 else 1202 if kldstat -q -m "$_mod"; then 1203 _loaded=true 1204 fi 1205 fi 1206 if ! $_loaded; then 1207 if ! kldload "$1"; then 1208 warn "Unable to load kernel module $1" 1209 return 1 1210 else 1211 info "$1 kernel module loaded." 1212 fi 1213 else 1214 debug "load_kld: $1 kernel module already loaded." 1215 fi 1216 return 0 1217} 1218 1219 1220# ltr str src dst 1221# Change every $src in $str to $dst. 1222# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor 1223# awk(1). 1224ltr() 1225{ 1226 local _str _src _dst _out _com 1227 _str=$1 1228 _src=$2 1229 _dst=$3 1230 _out="" 1231 1232 IFS=${_src} 1233 for _com in ${_str}; do 1234 if [ -z "${_out}" ]; then 1235 _out="${_com}" 1236 else 1237 _out="${_out}${_dst}${_com}" 1238 fi 1239 done 1240 echo "${_out}" 1241} 1242 1243# 1244# load_rc_config 1245# Source in the configuration file for a given command. 1246# 1247load_rc_config() 1248{ 1249 _command=$1 1250 if [ -z "$_command" ]; then 1251 err 3 'USAGE: load_rc_config command' 1252 fi 1253 1254 if [ -z "$_rc_conf_loaded" ]; then 1255 if [ -r /etc/defaults/rc.conf ]; then 1256 debug "Sourcing /etc/defaults/rc.conf" 1257 . /etc/defaults/rc.conf 1258 source_rc_confs 1259 elif [ -r /etc/rc.conf ]; then 1260 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 1261 . /etc/rc.conf 1262 fi 1263 _rc_conf_loaded=YES 1264 fi 1265 if [ -f /etc/rc.conf.d/"$_command" ]; then 1266 debug "Sourcing /etc/rc.conf.d/${_command}" 1267 . /etc/rc.conf.d/"$_command" 1268 fi 1269 1270 # XXX - Deprecated variable name support 1271 # 1272 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable" 1273 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program" 1274 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags" 1275 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable" 1276 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" 1277 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" 1278 1279} 1280 1281# 1282# rc_usage commands 1283# Print a usage string for $0, with `commands' being a list of 1284# valid commands. 1285# 1286rc_usage() 1287{ 1288 echo -n 1>&2 "Usage: $0 [fast|force|one|quiet](" 1289 1290 _sep= 1291 for _elem in $*; do 1292 echo -n 1>&2 "$_sep$_elem" 1293 _sep="|" 1294 done 1295 echo 1>&2 ")" 1296 exit 1 1297} 1298 1299# 1300# err exitval message 1301# Display message to stderr and log to the syslog, and exit with exitval. 1302# 1303err() 1304{ 1305 exitval=$1 1306 shift 1307 1308 if [ -x /usr/bin/logger ]; then 1309 logger "$0: ERROR: $*" 1310 fi 1311 echo 1>&2 "$0: ERROR: $*" 1312 exit $exitval 1313} 1314 1315# 1316# warn message 1317# Display message to stderr and log to the syslog. 1318# 1319warn() 1320{ 1321 if [ -x /usr/bin/logger ]; then 1322 logger "$0: WARNING: $*" 1323 fi 1324 echo 1>&2 "$0: WARNING: $*" 1325} 1326 1327# 1328# info message 1329# Display informational message to stdout and log to syslog. 1330# 1331info() 1332{ 1333 case ${rc_info} in 1334 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1335 if [ -x /usr/bin/logger ]; then 1336 logger "$0: INFO: $*" 1337 fi 1338 echo "$0: INFO: $*" 1339 ;; 1340 esac 1341} 1342 1343# 1344# debug message 1345# If debugging is enabled in rc.conf output message to stderr. 1346# BEWARE that you don't call any subroutine that itself calls this 1347# function. 1348# 1349debug() 1350{ 1351 case ${rc_debug} in 1352 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1353 if [ -x /usr/bin/logger ]; then 1354 logger "$0: INFO: $*" 1355 fi 1356 echo 1>&2 "$0: DEBUG: $*" 1357 ;; 1358 esac 1359} 1360 1361# 1362# backup_file action file cur backup 1363# Make a backup copy of `file' into `cur', and save the previous 1364# version of `cur' as `backup' or use rcs for archiving. 1365# 1366# This routine checks the value of the backup_uses_rcs variable, 1367# which can be either YES or NO. 1368# 1369# The `action' keyword can be one of the following: 1370# 1371# add `file' is now being backed up (and is possibly 1372# being reentered into the backups system). `cur' 1373# is created and RCS files, if necessary, are 1374# created as well. 1375# 1376# update `file' has changed and needs to be backed up. 1377# If `cur' exists, it is copied to to `back' or 1378# checked into RCS (if the repository file is old), 1379# and then `file' is copied to `cur'. Another RCS 1380# check in done here if RCS is being used. 1381# 1382# remove `file' is no longer being tracked by the backups 1383# system. If RCS is not being used, `cur' is moved 1384# to `back', otherwise an empty file is checked in, 1385# and then `cur' is removed. 1386# 1387# 1388backup_file() 1389{ 1390 _action=$1 1391 _cpfile=$2 1392 _cur=$3 1393 _back=$4 1394 1395 if checkyesno backup_uses_rcs; then 1396 _msg0="backup archive" 1397 _msg1="update" 1398 1399 # ensure that history file is not locked 1400 if [ -f $_cur,v ]; then 1401 rcs -q -u -U -M $_cur 1402 fi 1403 1404 # ensure after switching to rcs that the 1405 # current backup is not lost 1406 if [ -f $_cur ]; then 1407 # no archive, or current newer than archive 1408 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 1409 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1410 rcs -q -kb -U $_cur 1411 co -q -f -u $_cur 1412 fi 1413 fi 1414 1415 case $_action in 1416 add|update) 1417 cp -p $_cpfile $_cur 1418 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1419 rcs -q -kb -U $_cur 1420 co -q -f -u $_cur 1421 chown root:wheel $_cur $_cur,v 1422 ;; 1423 remove) 1424 cp /dev/null $_cur 1425 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1426 rcs -q -kb -U $_cur 1427 chown root:wheel $_cur $_cur,v 1428 rm $_cur 1429 ;; 1430 esac 1431 else 1432 case $_action in 1433 add|update) 1434 if [ -f $_cur ]; then 1435 cp -p $_cur $_back 1436 fi 1437 cp -p $_cpfile $_cur 1438 chown root:wheel $_cur 1439 ;; 1440 remove) 1441 mv -f $_cur $_back 1442 ;; 1443 esac 1444 fi 1445} 1446 1447# devfs_mount_jail dir 1448# Mounts a devfs file system appropriate for jails 1449# on the directory dir. 1450# This function returns non-zero if an error occurs. 1451# 1452devfs_mount_jail() 1453{ 1454 local jdev _me 1455 jdev="$1" 1456 _me="devfs_mount_jail" 1457 1458 if ! devfs_domount "$jdev" $rs; then 1459 warn "$_me: devfs was not mounted on $jdev" 1460 return 1 1461 fi 1462 return 0 1463} 1464 1465# devfs_domount dir 1466# Mount devfs on dir. 1467# Returns 0 on success. 1468# 1469devfs_domount() 1470{ 1471 local devdir _me 1472 devdir="$1" 1473 _me="devfs_domount()" 1474 1475 if [ -z "$devdir" ]; then 1476 warn "$_me: you must specify a mount-point" 1477 return 1 1478 fi 1479 1480 debug "$_me: mount-point is ($devdir)" 1481 if ! mount -t devfs devfs "$devdir"; then 1482 warn "$_me: Unable to mount devfs on $devdir" 1483 return 1 1484 fi 1485 1486return 0 1487} 1488 1489# Find scripts in local_startup directories. 1490find_local_scripts() { 1491 local_rc='' 1492 for dir in ${local_startup}; do 1493 if [ -d "${dir}" ]; then 1494 for file in `grep -l '^# PROVIDE:' ${dir}/* 2>/dev/null`; do 1495 case "$file" in 1496 *.sample) ;; 1497 *) if [ -x "$file" ]; then 1498 local_rc="${local_rc} ${file}" 1499 fi 1500 ;; 1501 esac 1502 done 1503 fi 1504 done 1505} 1506