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