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_vars n If set, perform checkyesno on each of the 566# listed variables before running the default 567# (re)start command. 568# 569# Default behaviour for a given argument, if no override method is 570# provided: 571# 572# Argument Default behaviour 573# -------- ----------------- 574# start if !running && checkyesno ${rcvar} 575# ${command} 576# 577# stop if ${pidfile} 578# rc_pid=$(check_pidfile $pidfile $command) 579# else 580# rc_pid=$(check_process $command) 581# kill $sig_stop $rc_pid 582# wait_for_pids $rc_pid 583# ($sig_stop defaults to TERM.) 584# 585# reload Similar to stop, except use $sig_reload instead, 586# and doesn't wait_for_pids. 587# $sig_reload defaults to HUP. 588# 589# restart Run `stop' then `start'. 590# 591# status Show if ${command} is running, etc. 592# 593# poll Wait for ${command} to exit. 594# 595# rcvar Display what rc.conf variable is used (if any). 596# 597# Variables available to methods, and after run_rc_command() has 598# completed: 599# 600# Variable Purpose 601# -------- ------- 602# rc_arg Argument to command, after fast/force/one processing 603# performed 604# 605# rc_flags Flags to start the default command with. 606# Defaults to ${name}_flags, unless overridden 607# by $flags from the environment. 608# This variable may be changed by the precmd method. 609# 610# rc_pid PID of command (if appropriate) 611# 612# rc_fast Not empty if "fast" was provided (q.v.) 613# 614# rc_force Not empty if "force" was provided (q.v.) 615# 616# rc_quiet Not empty if "quiet" was provided 617# 618# 619dummy_rc_command() 620{ 621 rc_arg=$1 622 623 case "$rc_arg" in 624 fast*) # "fast" prefix; don't check pid 625 rc_arg=${rc_arg#fast} 626 ;; 627 force*) # "force" prefix; always start 628 rc_arg=${rc_arg#force} 629 ;; 630 one*) # "one" prefix; set ${rcvar}=yes 631 rc_arg=${rc_arg#one} 632 ;; 633 esac 634 set_provide_list $rc_arg $RC_CONFIGURED 635 return 0 636} 637 638run_rc_command() 639{ 640 _return=0 641 rc_arg=$1 642 if [ -z "$name" ]; then 643 err 3 'run_rc_command: $name is not set.' 644 fi 645 646 # Don't repeat the first argument when passing additional command- 647 # line arguments to the command subroutines. 648 # 649 shift 1 650 rc_extra_args="$*" 651 652 case "$rc_arg" in 653 fast*) # "fast" prefix; don't check pid 654 rc_arg=${rc_arg#fast} 655 rc_fast=yes 656 rc_quiet=yes 657 ;; 658 force*) # "force" prefix; always start 659 rc_arg=${rc_arg#force} 660 rc_force=yes 661 if [ -n "${rcvar}" ]; then 662 eval ${rcvar}=YES 663 fi 664 ;; 665 one*) # "one" prefix; set ${rcvar}=yes 666 rc_arg=${rc_arg#one} 667 if [ -n "${rcvar}" ]; then 668 eval ${rcvar}=YES 669 fi 670 ;; 671 quiet*) # "quiet" prefix; omit some messages 672 _rc_prefix=quiet 673 rc_arg=${rc_arg#${_rc_prefix}} 674 rc_quiet=yes 675 ;; 676 esac 677 678 eval _override_command=\$${name}_program 679 if [ -n "$_override_command" ]; then 680 command=$_override_command 681 fi 682 683 _keywords="start stop restart rcvar $extra_commands" 684 rc_pid= 685 _pidcmd= 686 _procname=${procname:-${command}} 687 688 # setup pid check command if not fast 689 if [ -z "$rc_fast" -a -n "$_procname" ]; then 690 if [ -n "$pidfile" ]; then 691 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 692 else 693 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 694 fi 695 if [ -n "$_pidcmd" ]; then 696 _keywords="${_keywords} status poll" 697 fi 698 fi 699 700 if [ -z "$rc_arg" ]; then 701 rc_usage "$_keywords" 702 fi 703 704 if [ -n "$flags" ]; then # allow override from environment 705 rc_flags=$flags 706 else 707 eval rc_flags=\$${name}_flags 708 fi 709 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 710 _nice=\$${name}_nice _user=\$${name}_user \ 711 _group=\$${name}_group _groups=\$${name}_groups 712 713 if [ -n "$_user" ]; then # unset $_user if running as that user 714 if [ "$_user" = "$(id -un)" ]; then 715 unset _user 716 fi 717 fi 718 719 # if ${rcvar} is set, and $1 is not 720 # "rcvar", then run 721 # checkyesno ${rcvar} 722 # and return if that failed 723 # 724 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then 725 if ! checkyesno ${rcvar}; then 726 set_provide_list $rc_arg $RC_DISABLED 727 return 0 728 fi 729 fi 730 731 eval $_pidcmd # determine the pid if necessary 732 733 for _elem in $_keywords; do 734 if [ "$_elem" != "$rc_arg" ]; then 735 continue 736 fi 737 738 # if there's a custom ${XXX_cmd}, 739 # run that instead of the default 740 # 741 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 742 _postcmd=\$${rc_arg}_postcmd 743 if [ -n "$_cmd" ]; then 744 # if the precmd failed and force 745 # isn't set, exit 746 # 747 if [ -n "$_precmd" ]; then 748 debug "run_rc_command: evaluating ${_precmd}()." 749 eval $_precmd $rc_extra_args 750 751 _return=$? 752 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 753 fi 754 755 if [ -n "$_cmd" ]; then 756 debug "run_rc_command: evaluating ${_cmd}()." 757 eval $_cmd $rc_extra_args 758 _return=$? 759 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 760 fi 761 762 if [ -n "$_postcmd" ]; then 763 debug "run_rc_command: evaluating ${_postcmd}()." 764 eval $_postcmd $rc_extra_args 765 _return=$? 766 check_early_term $rc_arg $_return "" || return $(($?-1)) 767 fi 768 set_provide_list $rc_arg $_return 769 adjust_return_code $_return 770 return $? 771 fi 772 773 case "$rc_arg" in # default operations... 774 775 status) 776 if [ -n "$rc_pid" ]; then 777 echo "${name} is running as pid $rc_pid." 778 else 779 echo "${name} is not running." 780 return 1 781 fi 782 ;; 783 784 start) 785 if [ -n "$rc_pid" ]; then 786 if [ -z "$rc_quiet" ]; then 787 echo "${name} already running? (pid=$rc_pid)." 788 fi 789 exit 1 790 fi 791 792 if [ ! -x $command ]; then 793 info "run_rc_command: cannot run ($command)." 794 set_provide_list $rc_arg $RC_FAILED 795 adjust_return_code $RC_FAILED 796 return $? 797 fi 798 799 # check for required variables, 800 # directories, and files 801 # 802 for _f in $required_vars; do 803 if ! checkyesno $_f; then 804 warn "\$${_f} is not set." 805 if [ -z "$rc_force" ]; then 806 set_provide_list $rc_arg $RC_FAILED 807 adjust_return_code $RC_FAILED 808 return $? 809 fi 810 fi 811 done 812 for _f in $required_dirs; do 813 if [ ! -d "${_f}/." ]; then 814 warn "${_f} is not a directory." 815 if [ -z "$rc_force" ]; then 816 set_provide_list $rc_arg $RC_FAILED 817 adjust_return_code $RC_FAILED 818 return $? 819 fi 820 fi 821 done 822 for _f in $required_files; do 823 if [ ! -r "${_f}" ]; then 824 warn "${_f} is not readable." 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 833 # if the precmd failed and force 834 # isn't set, exit 835 # 836 if [ -n "${_precmd}" ]; then 837 debug "run_rc_command: evaluating ${_precmd}()." 838 eval $_precmd 839 _return=$? 840 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 841 fi 842 843 # setup the command to run, and run it 844 # 845 echo "Starting ${name}." 846 if [ -n "$_chroot" ]; then 847 _doit="\ 848${_nice:+nice -n $_nice }\ 849chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 850$_chroot $command $rc_flags $command_args" 851 else 852 _doit="\ 853${_chdir:+cd $_chdir; }\ 854${_nice:+nice -n $_nice }\ 855$command $rc_flags $command_args" 856 if [ -n "$_user" ]; then 857 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 858 fi 859 fi 860 861 # if the cmd failed and force 862 # isn't set, exit 863 # 864 debug "run_rc_command: _doit: $_doit" 865 eval $_doit 866 _return=$? 867 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 868 # finally, run postcmd 869 # 870 if [ -n "${_postcmd}" ]; then 871 debug "run_rc_command: evaluating ${_postcmd}()." 872 eval $_postcmd 873 fi 874 ;; 875 876 stop) 877 if [ -z "$rc_pid" ]; then 878 if [ -n "$pidfile" ]; then 879 echo \ 880 "${name} not running? (check $pidfile)." 881 else 882 echo "${name} not running?" 883 fi 884 set_provide_list $rc_arg $RC_STOPPED 885 exit 1 886 fi 887 888 # if the precmd failed and force 889 # isn't set, exit 890 # 891 if [ -n "$_precmd" ]; then 892 eval $_precmd 893 _return=$? 894 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 895 fi 896 897 # send the signal to stop 898 # 899 echo "Stopping ${name}." 900 _doit="kill -${sig_stop:-TERM} $rc_pid" 901 if [ -n "$_user" ]; then 902 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 903 fi 904 905 # if the stop cmd failed and force 906 # isn't set, exit 907 # 908 eval $_doit 909 _return=$? 910 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 911 # wait for the command to exit, 912 # and run postcmd. 913 sleep 0.1 914 wait_for_pids $rc_pid 915 if [ -n "$_postcmd" ]; then 916 eval $_postcmd 917 _return=$? 918 fi 919 ;; 920 921 reload) 922 if [ -z "$rc_pid" ]; then 923 if [ -n "$pidfile" ]; then 924 echo \ 925 "${name} not running? (check $pidfile)." 926 else 927 echo "${name} not running?" 928 fi 929 set_provide_list $rc_arg $RC_FAILED 930 exit 1 931 fi 932 echo "Reloading ${name} config files." 933 if [ -n "$_precmd" ]; then 934 eval $_precmd 935 _return=$? 936 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 937 fi 938 _doit="kill -${sig_reload:-HUP} $rc_pid" 939 if [ -n "$_user" ]; then 940 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 941 fi 942 eval $_doit 943 _return=$? 944 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 945 if [ -n "$_postcmd" ]; then 946 eval $_postcmd 947 _return=$? 948 fi 949 ;; 950 951 restart) 952 if [ -n "$_precmd" ]; then 953 eval $_precmd $rc_extra_args 954 _return=$? 955 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1)) 956 fi 957 # prevent restart being called more 958 # than once by any given script 959 # 960 if [ -n "$_rc_restart_done" ]; then 961 return 0 962 fi 963 _rc_restart_done=YES 964 965 ( $0 ${rc_force:+force}stop $rc_extra_args ) 966 $0 ${rc_force:+force}start $rc_extra_args 967 _return=$? 968 969 if [ -n "$_postcmd" ]; then 970 eval $_postcmd $rc_extra_args 971 adjust_return_code $? 972 _return=$? 973 fi 974 # Do not set_provide_list(), the start command above 975 # will have done it for us and we do not know the 976 # actual RC code to base a setting on here. 977 # 978 return $_return 979 ;; 980 981 poll) 982 if [ -n "$rc_pid" ]; then 983 wait_for_pids $rc_pid 984 fi 985 ;; 986 987 rcvar) 988 echo "# $name" 989 if [ -n "$rcvar" ]; then 990 if checkyesno ${rcvar}; then 991 echo "\$${rcvar}=YES" 992 else 993 echo "\$${rcvar}=NO" 994 fi 995 fi 996 ;; 997 998 *) 999 rc_usage "$_keywords" 1000 ;; 1001 1002 esac 1003 set_provide_list $rc_arg $_return 1004 adjust_return_code $_return 1005 return $? 1006 done 1007 1008 echo 1>&2 "$0: unknown directive '$rc_arg'." 1009 rc_usage "$_keywords" 1010 exit 1 1011} 1012 1013# 1014# run_rc_script file arg 1015# Start the script `file' with `arg', and correctly handle the 1016# return value from the script. If `file' ends with `.sh', it's 1017# sourced into the current environment. If `file' appears to be 1018# a backup or scratch file, ignore it. Otherwise if it's 1019# executable run as a child process. 1020# 1021run_rc_script() 1022{ 1023 _file=$1 1024 _arg=$2 1025 if [ -z "$_file" -o -z "$_arg" ]; then 1026 err 3 'USAGE: run_rc_script file arg' 1027 fi 1028 1029 trap "echo 'Reboot interrupted'; exit 1" 3 1030 1031 unset name command command_args command_interpreter \ 1032 extra_commands pidfile procname \ 1033 rcvar required_dirs required_files required_vars 1034 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 1035 1036 case "$_file" in 1037 *.sh) # run in current shell 1038 set $_arg ; . $_file 1039 ;; 1040 *[~#]|*.OLD|*.orig) # scratch file; skip 1041 warn "Ignoring scratch file $_file" 1042 ;; 1043 *) # run in subshell 1044 if [ -x $_file ]; then 1045 if [ -n "$rc_fast_and_loose" ]; then 1046 set $_arg ; . $_file 1047 else 1048 ( trap "echo 'Reboot interrupted'; exit 1" 3 1049 set $_arg ; . $_file ) 1050 fi 1051 fi 1052 ;; 1053 esac 1054} 1055 1056# ltr str src dst 1057# Change every $src in $str to $dst. 1058# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor 1059# awk(1). 1060ltr() 1061{ 1062 local _str _src _dst _out _com 1063 _str=$1 1064 _src=$2 1065 _dst=$3 1066 _out="" 1067 1068 IFS=${_src} 1069 for _com in ${_str}; do 1070 if [ -z "${_out}" ]; then 1071 _out="${_com}" 1072 else 1073 _out="${_out}${_dst}${_com}" 1074 fi 1075 done 1076 echo "${_out}" 1077} 1078 1079# 1080# load_rc_config 1081# Source in the configuration file for a given command. 1082# 1083load_rc_config() 1084{ 1085 _command=$1 1086 if [ -z "$_command" ]; then 1087 err 3 'USAGE: load_rc_config command' 1088 fi 1089 1090 if [ -z "$_rc_conf_loaded" ]; then 1091 if [ -r /etc/defaults/rc.conf ]; then 1092 debug "Sourcing /etc/defaults/rc.conf" 1093 . /etc/defaults/rc.conf 1094 source_rc_confs 1095 elif [ -r /etc/rc.conf ]; then 1096 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 1097 . /etc/rc.conf 1098 fi 1099 _rc_conf_loaded=YES 1100 fi 1101 if [ -f /etc/rc.conf.d/"$_command" ]; then 1102 debug "Sourcing /etc/rc.conf.d/${_command}" 1103 . /etc/rc.conf.d/"$_command" 1104 fi 1105 1106 # XXX - Deprecated variable name support 1107 # 1108 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable" 1109 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program" 1110 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags" 1111 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable" 1112 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" 1113 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" 1114 1115} 1116 1117# 1118# rc_usage commands 1119# Print a usage string for $0, with `commands' being a list of 1120# valid commands. 1121# 1122rc_usage() 1123{ 1124 echo -n 1>&2 "Usage: $0 [fast|force|one|quiet](" 1125 1126 _sep= 1127 for _elem in $*; do 1128 echo -n 1>&2 "$_sep$_elem" 1129 _sep="|" 1130 done 1131 echo 1>&2 ")" 1132 exit 1 1133} 1134 1135# 1136# err exitval message 1137# Display message to stderr and log to the syslog, and exit with exitval. 1138# 1139err() 1140{ 1141 exitval=$1 1142 shift 1143 1144 if [ -x /usr/bin/logger ]; then 1145 logger "$0: ERROR: $*" 1146 fi 1147 echo 1>&2 "$0: ERROR: $*" 1148 exit $exitval 1149} 1150 1151# 1152# warn message 1153# Display message to stderr and log to the syslog. 1154# 1155warn() 1156{ 1157 if [ -x /usr/bin/logger ]; then 1158 logger "$0: WARNING: $*" 1159 fi 1160 echo 1>&2 "$0: WARNING: $*" 1161} 1162 1163# 1164# info message 1165# Display informational message to stdout and log to syslog. 1166# 1167info() 1168{ 1169 case ${rc_info} in 1170 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1171 if [ -x /usr/bin/logger ]; then 1172 logger "$0: INFO: $*" 1173 fi 1174 echo "$0: INFO: $*" 1175 ;; 1176 esac 1177} 1178 1179# 1180# debug message 1181# If debugging is enabled in rc.conf output message to stderr. 1182# BEWARE that you don't call any subroutine that itself calls this 1183# function. 1184# 1185debug() 1186{ 1187 case ${rc_debug} in 1188 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1189 if [ -x /usr/bin/logger ]; then 1190 logger "$0: INFO: $*" 1191 fi 1192 echo 1>&2 "$0: DEBUG: $*" 1193 ;; 1194 esac 1195} 1196 1197# 1198# backup_file action file cur backup 1199# Make a backup copy of `file' into `cur', and save the previous 1200# version of `cur' as `backup' or use rcs for archiving. 1201# 1202# This routine checks the value of the backup_uses_rcs variable, 1203# which can be either YES or NO. 1204# 1205# The `action' keyword can be one of the following: 1206# 1207# add `file' is now being backed up (and is possibly 1208# being reentered into the backups system). `cur' 1209# is created and RCS files, if necessary, are 1210# created as well. 1211# 1212# update `file' has changed and needs to be backed up. 1213# If `cur' exists, it is copied to to `back' or 1214# checked into RCS (if the repository file is old), 1215# and then `file' is copied to `cur'. Another RCS 1216# check in done here if RCS is being used. 1217# 1218# remove `file' is no longer being tracked by the backups 1219# system. If RCS is not being used, `cur' is moved 1220# to `back', otherwise an empty file is checked in, 1221# and then `cur' is removed. 1222# 1223# 1224backup_file() 1225{ 1226 _action=$1 1227 _cpfile=$2 1228 _cur=$3 1229 _back=$4 1230 1231 if checkyesno backup_uses_rcs; then 1232 _msg0="backup archive" 1233 _msg1="update" 1234 1235 # ensure that history file is not locked 1236 if [ -f $_cur,v ]; then 1237 rcs -q -u -U -M $_cur 1238 fi 1239 1240 # ensure after switching to rcs that the 1241 # current backup is not lost 1242 if [ -f $_cur ]; then 1243 # no archive, or current newer than archive 1244 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 1245 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1246 rcs -q -kb -U $_cur 1247 co -q -f -u $_cur 1248 fi 1249 fi 1250 1251 case $_action in 1252 add|update) 1253 cp -p $_cpfile $_cur 1254 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1255 rcs -q -kb -U $_cur 1256 co -q -f -u $_cur 1257 chown root:wheel $_cur $_cur,v 1258 ;; 1259 remove) 1260 cp /dev/null $_cur 1261 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1262 rcs -q -kb -U $_cur 1263 chown root:wheel $_cur $_cur,v 1264 rm $_cur 1265 ;; 1266 esac 1267 else 1268 case $_action in 1269 add|update) 1270 if [ -f $_cur ]; then 1271 cp -p $_cur $_back 1272 fi 1273 cp -p $_cpfile $_cur 1274 chown root:wheel $_cur 1275 ;; 1276 remove) 1277 mv -f $_cur $_back 1278 ;; 1279 esac 1280 fi 1281} 1282 1283# devfs_mount_jail dir 1284# Mounts a devfs file system appropriate for jails 1285# on the directory dir. 1286# This function returns non-zero if an error occurs. 1287# 1288devfs_mount_jail() 1289{ 1290 local jdev _me 1291 jdev="$1" 1292 _me="devfs_mount_jail" 1293 1294 if ! devfs_domount "$jdev" $rs; then 1295 warn "$_me: devfs was not mounted on $jdev" 1296 return 1 1297 fi 1298 return 0 1299} 1300 1301# devfs_domount dir 1302# Mount devfs on dir. 1303# Returns 0 on success. 1304# 1305devfs_domount() 1306{ 1307 local devdir _me 1308 devdir="$1" 1309 _me="devfs_domount()" 1310 1311 if [ -z "$devdir" ]; then 1312 warn "$_me: you must specify a mount-point" 1313 return 1 1314 fi 1315 1316 debug "$_me: mount-point is ($devdir)" 1317 if ! mount -t devfs devfs "$devdir"; then 1318 warn "$_me: Unable to mount devfs on $devdir" 1319 return 1 1320 fi 1321 1322return 0 1323} 1324