rc.subr revision 119166
1# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $ 2# $FreeBSD: head/etc/rc.subr 119166 2003-08-20 06:15:18Z mtm $ 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 46SYSCTL="/sbin/sysctl" 47SYSCTL_N="${SYSCTL} -n" 48CMD_OSTYPE="${SYSCTL_N} kern.ostype" 49OSTYPE=`${CMD_OSTYPE}` 50 51case ${OSTYPE} in 52FreeBSD) 53 SYSCTL_W="${SYSCTL}" 54 ;; 55NetBSD) 56 SYSCTL_W="${SYSCTL} -w" 57 ;; 58esac 59 60# 61# functions 62# --------- 63 64# 65# set_rcvar base_var 66# Set the variable name enabling a specific service. 67# FreeBSD uses ${service}_enable, while NetBSD uses 68# just the name of the service. For example: 69# FreeBSD: sendmail_enable="YES" 70# NetBSD : sendmail="YES" 71# $1 - if $name is not the base to work of off, specify 72# a different one 73# 74set_rcvar() 75{ 76 if [ -z "$1" ]; then 77 base_var=${name} 78 else 79 base_var="$1" 80 fi 81 82 case ${OSTYPE} in 83 FreeBSD) 84 echo ${base_var}_enable 85 ;; 86 NetBSD) 87 echo ${base_var} 88 ;; 89 *) 90 echo 'XXX' 91 ;; 92 esac 93} 94 95# 96# force_depend script 97# Force a service to start. Intended for use by services 98# to resolve dependency issues. It is assumed the caller 99# has check to make sure this call is necessary 100# $1 - filename of script, in /etc/rc.d, to run 101# 102force_depend() 103{ 104 _depend="$1" 105 106 info "${name} depends on ${_depend}, which will be forced to start." 107 if ! /etc/rc.d/${_depend} forcestart ; then 108 warn "Unable to force ${_depend}. It may already be running." 109 return 1 110 fi 111 return 0 112} 113 114# 115# checkyesno var 116# Test $1 variable, and warn if not set to YES or NO. 117# Return 0 if it's "yes" (et al), nonzero otherwise. 118# 119checkyesno() 120{ 121 eval _value=\$${1} 122 debug "checkyesno: $1 is set to $_value." 123 case $_value in 124 125 # "yes", "true", "on", or "1" 126 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 127 return 0 128 ;; 129 130 # "no", "false", "off", or "0" 131 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 132 return 1 133 ;; 134 *) 135 warn "\$${1} is not set properly - see rc.conf(5)." 136 return 1 137 ;; 138 esac 139} 140 141# reverse_list list 142# print the list in reverse order 143# 144reverse_list() 145{ 146 _revlist= 147 for _revfile in $*; do 148 _revlist="$_revfile $_revlist" 149 done 150 echo $_revlist 151} 152 153# 154# mount_critical_filesystems type 155# Go through the list of critical filesystems as provided in 156# the rc.conf(5) variable $critical_filesystems_${type}, checking 157# each one to see if it is mounted, and if it is not, mounting it. 158# 159mount_critical_filesystems() 160{ 161 eval _fslist=\$critical_filesystems_${1} 162 for _fs in $_fslist; do 163 mount | ( 164 _ismounted=no 165 while read what _on on _type type; do 166 if [ $on = $_fs ]; then 167 _ismounted=yes 168 fi 169 done 170 if [ $_ismounted = no ]; then 171 mount $_fs >/dev/null 2>&1 172 fi 173 ) 174 done 175} 176 177# 178# check_pidfile pidfile procname [interpreter] 179# Parses the first line of pidfile for a PID, and ensures 180# that the process is running and matches procname. 181# Prints the matching PID upon success, nothing otherwise. 182# interpreter is optional; see _find_processes() for details. 183# 184check_pidfile() 185{ 186 _pidfile=$1 187 _procname=$2 188 _interpreter=$3 189 if [ -z "$_pidfile" -o -z "$_procname" ]; then 190 err 3 'USAGE: check_pidfile pidfile procname [interpreter]' 191 fi 192 if [ ! -f $_pidfile ]; then 193 debug "pid file {$_pidfile): not readable." 194 return 195 fi 196 read _pid _junk < $_pidfile 197 if [ -z "$_pid" ]; then 198 debug "pid file {$_pidfile): no pid in file." 199 return 200 fi 201 _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" 202} 203 204# 205# check_process procname [interpreter] 206# Ensures that a process (or processes) named procname is running. 207# Prints a list of matching PIDs. 208# interpreter is optional; see _find_processes() for details. 209# 210check_process() 211{ 212 _procname=$1 213 _interpreter=$2 214 if [ -z "$_procname" ]; then 215 err 3 'USAGE: check_process procname [interpreter]' 216 fi 217 _find_processes $_procname ${_interpreter:-.} '-ax' 218} 219 220# 221# _find_processes procname interpreter psargs 222# Search for procname in the output of ps generated by psargs. 223# Prints the PIDs of any matching processes, space separated. 224# 225# If interpreter == ".", check the following variations of procname 226# against the first word of each command: 227# procname 228# `basename procname` 229# `basename procname` + ":" 230# "(" + `basename procname` + ")" 231# 232# If interpreter != ".", read the first line of procname, remove the 233# leading #!, normalise whitespace, append procname, and attempt to 234# match that against each command, either as is, or with extra words 235# at the end. 236# 237_find_processes() 238{ 239 if [ $# -ne 3 ]; then 240 err 3 'USAGE: _find_processes procname interpreter psargs' 241 fi 242 _procname=$1 243 _interpreter=$2 244 _psargs=$3 245 246 _pref= 247 if [ $_interpreter != "." ]; then # an interpreted script 248 read _interp < $_procname # read interpreter name 249 _interp=${_interp#\#!} # strip #! 250 set -- $_interp 251 if [ $_interpreter != $1 ]; then 252 warn "\$command_interpreter $_interpreter != $1" 253 fi 254 _interp="$* $_procname" # cleanup spaces, add _procname 255 _fp_args='_argv' 256 _fp_match='case "$_argv" in 257 ${_interp}|"${_interp} "*)' 258 else # a normal daemon 259 _procnamebn=${_procname##*/} 260 _fp_args='_arg0 _argv' 261 _fp_match='case "$_arg0" in 262 $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")' 263 fi 264 265 _proccheck=' 266 ps -o "pid,command" '"$_psargs"' | 267 while read _npid '"$_fp_args"'; do 268 case "$_npid" in 269 PID) 270 continue ;; 271 esac ; '"$_fp_match"' 272 echo -n "$_pref$_npid" ; 273 _pref=" " 274 ;; 275 esac 276 done' 277 278# debug "in _find_processes: proccheck is ($_proccheck)." 279 eval $_proccheck 280} 281 282# 283# wait_for_pids pid [pid ...] 284# spins until none of the pids exist 285# 286wait_for_pids() 287{ 288 _list=$* 289 if [ -z "$_list" ]; then 290 return 291 fi 292 _prefix= 293 while true; do 294 _nlist=""; 295 for _j in $_list; do 296 if kill -0 $_j 2>/dev/null; then 297 _nlist="${_nlist}${_nlist:+ }$_j" 298 fi 299 done 300 if [ -z "$_nlist" ]; then 301 break 302 fi 303 _list=$_nlist 304 echo -n ${_prefix:-"Waiting for PIDS: "}$_list 305 _prefix=", " 306 sleep 2 307 done 308 if [ -n "$_prefix" ]; then 309 echo "." 310 fi 311} 312 313# 314# run_rc_command argument 315# Search for argument in the list of supported commands, which is: 316# "start stop restart rcvar status poll ${extra_commands}" 317# If there's a match, run ${argument}_cmd or the default method 318# (see below). 319# 320# If argument has a given prefix, then change the operation as follows: 321# Prefix Operation 322# ------ --------- 323# fast Skip the pid check, and set rc_fast=yes 324# force Set ${rcvar} to YES, and set rc_force=yes 325# 326# The following globals are used: 327# 328# Name Needed Purpose 329# ---- ------ ------- 330# name y Name of script. 331# 332# command n Full path to command. 333# Not needed if ${rc_arg}_cmd is set for 334# each keyword. 335# 336# command_args n Optional args/shell directives for command. 337# 338# command_interpreter n If not empty, command is interpreted, so 339# call check_{pidfile,process}() appropriately. 340# 341# extra_commands n List of extra commands supported. 342# 343# pidfile n If set, use check_pidfile $pidfile $command, 344# otherwise use check_process $command. 345# In either case, only check if $command is set. 346# 347# procname n Process name to check for instead of $command. 348# 349# rcvar n This is checked with checkyesno to determine 350# if the action should be run. 351# 352# ${name}_chroot n Directory to chroot to before running ${command} 353# Requires /usr to be mounted. 354# 355# ${name}_chdir n Directory to cd to before running ${command} 356# (if not using ${name}_chroot). 357# 358# ${name}_flags n Arguments to call ${command} with. 359# NOTE: $flags from the parent environment 360# can be used to override this. 361# 362# ${name}_nice n Nice level to run ${command} at. 363# 364# ${name}_user n User to run ${command} as, using su(1) if not 365# using ${name}_chroot. 366# Requires /usr to be mounted. 367# 368# ${name}_group n Group to run chrooted ${command} as. 369# Requires /usr to be mounted. 370# 371# ${name}_groups n Comma separated list of supplementary groups 372# to run the chrooted ${command} with. 373# Requires /usr to be mounted. 374# 375# ${rc_arg}_cmd n If set, use this as the method when invoked; 376# Otherwise, use default command (see below) 377# 378# ${rc_arg}_precmd n If set, run just before performing the 379# ${rc_arg}_cmd method in the default 380# operation (i.e, after checking for required 381# bits and process (non)existence). 382# If this completes with a non-zero exit code, 383# don't run ${rc_arg}_cmd. 384# 385# ${rc_arg}_postcmd n If set, run just after performing the 386# ${rc_arg}_cmd method, if that method 387# returned a zero exit code. 388# 389# required_dirs n If set, check for the existence of the given 390# directories before running the default 391# (re)start command. 392# 393# required_files n If set, check for the readability of the given 394# files before running the default (re)start 395# command. 396# 397# required_vars n If set, perform checkyesno on each of the 398# listed variables before running the default 399# (re)start command. 400# 401# Default behaviour for a given argument, if no override method is 402# provided: 403# 404# Argument Default behaviour 405# -------- ----------------- 406# start if !running && checkyesno ${rcvar} 407# ${command} 408# 409# stop if ${pidfile} 410# rc_pid=$(check_pidfile $pidfile $command) 411# else 412# rc_pid=$(check_process $command) 413# kill $sig_stop $rc_pid 414# wait_for_pids $rc_pid 415# ($sig_stop defaults to TERM.) 416# 417# reload Similar to stop, except use $sig_reload instead, 418# and doesn't wait_for_pids. 419# $sig_reload defaults to HUP. 420# 421# restart Run `stop' then `start'. 422# 423# status Show if ${command} is running, etc. 424# 425# poll Wait for ${command} to exit. 426# 427# rcvar Display what rc.conf variable is used (if any). 428# 429# Variables available to methods, and after run_rc_command() has 430# completed: 431# 432# Variable Purpose 433# -------- ------- 434# rc_arg Argument to command, after fast/force processing 435# performed 436# 437# rc_flags Flags to start the default command with. 438# Defaults to ${name}_flags, unless overridden 439# by $flags from the environment. 440# This variable may be changed by the precmd method. 441# 442# rc_pid PID of command (if appropriate) 443# 444# rc_fast Not empty if "fast" was provided (q.v.) 445# 446# rc_force Not empty if "force" was provided (q.v.) 447# 448# 449run_rc_command() 450{ 451 _return=0 452 rc_arg=$1 453 if [ -z "$name" ]; then 454 err 3 'run_rc_command: $name is not set.' 455 fi 456 457 case "$rc_arg" in 458 fast*) # "fast" prefix; don't check pid 459 rc_arg=${rc_arg#fast} 460 rc_fast=yes 461 ;; 462 force*) # "force prefix; always start 463 rc_arg=${rc_arg#force} 464 rc_force=yes 465 if [ -n "${rcvar}" ]; then 466 eval ${rcvar}=YES 467 fi 468 ;; 469 esac 470 471 eval _overide_command=\$${name}_program 472 if [ -n "$_overide_command" ]; then 473 command=$_overide_command 474 fi 475 476 _keywords="start stop restart rcvar $extra_commands" 477 rc_pid= 478 _pidcmd= 479 _procname=${procname:-${command}} 480 481 # setup pid check command if not fast 482 if [ -z "$rc_fast" -a -n "$_procname" ]; then 483 if [ -n "$pidfile" ]; then 484 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 485 else 486 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 487 fi 488 if [ -n "$_pidcmd" ]; then 489 _keywords="${_keywords} status poll" 490 fi 491 fi 492 493 if [ -z "$rc_arg" ]; then 494 rc_usage "$_keywords" 495 fi 496 497 if [ -n "$flags" ]; then # allow override from environment 498 rc_flags=$flags 499 else 500 eval rc_flags=\$${name}_flags 501 fi 502 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 503 _nice=\$${name}_nice _user=\$${name}_user \ 504 _group=\$${name}_group _groups=\$${name}_groups 505 506 if [ -n "$_user" ]; then # unset $_user if running as that user 507 if [ "$_user" = "$(id -un)" ]; then 508 unset _user 509 fi 510 fi 511 512 # if ${rcvar} is set, and $1 is not 513 # "rcvar", then run 514 # checkyesno ${rcvar} 515 # and return if that failed 516 # 517 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then 518 if ! checkyesno ${rcvar}; then 519 return 0 520 fi 521 fi 522 523 eval $_pidcmd # determine the pid if necessary 524 525 for _elem in $_keywords; do 526 if [ "$_elem" != "$rc_arg" ]; then 527 continue 528 fi 529 530 # if there's a custom ${XXX_cmd}, 531 # run that instead of the default 532 # 533 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 534 _postcmd=\$${rc_arg}_postcmd 535 if [ -n "$_cmd" ]; then 536 # if the precmd failed and force 537 # isn't set, exit 538 # 539 if [ -n "$_precmd" ]; then 540 debug "run_rc_command: evaluating ${_precmd}()." 541 eval $_precmd 542 _return=$? 543 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 544 return 1 545 fi 546 547 if [ -n "$_cmd" ]; then 548 debug "run_rc_command: evaluating ${_cmd}()." 549 eval $_cmd 550 _return=$? 551 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 552 return 1 553 fi 554 555 if [ -n "$_postcmd" ]; then 556 debug "run_rc_command: evaluating ${_postcmd}()." 557 eval $_postcmd 558 _return=$? 559 fi 560 return $_return 561 fi 562 563 case "$rc_arg" in # default operations... 564 565 status) 566 if [ -n "$rc_pid" ]; then 567 echo "${name} is running as pid $rc_pid." 568 else 569 echo "${name} is not running." 570 return 1 571 fi 572 ;; 573 574 start) 575 if [ -n "$rc_pid" ]; then 576 echo "${name} already running? (pid=$rc_pid)." 577 exit 1 578 fi 579 580 if [ ! -x $command ]; then 581 info "run_rc_command: cannot run ($command)." 582 return 0 583 fi 584 585 # check for required variables, 586 # directories, and files 587 # 588 for _f in $required_vars; do 589 if ! checkyesno $_f; then 590 warn "\$${_f} is not set." 591 if [ -z "$rc_force" ]; then 592 return 1 593 fi 594 fi 595 done 596 for _f in $required_dirs; do 597 if [ ! -d "${_f}/." ]; then 598 warn "${_f} is not a directory." 599 if [ -z "$rc_force" ]; then 600 return 1 601 fi 602 fi 603 done 604 for _f in $required_files; do 605 if [ ! -r "${_f}" ]; then 606 warn "${_f} is not readable." 607 if [ -z "$rc_force" ]; then 608 return 1 609 fi 610 fi 611 done 612 613 # if the precmd failed and force 614 # isn't set, exit 615 # 616 if [ -n "${_precmd}" ]; then 617 debug "run_rc_command: evaluating ${_precmd}()." 618 eval $_precmd 619 _return=$? 620 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 621 return 1 622 fi 623 624 # setup the command to run, and run it 625 # 626 echo "Starting ${name}." 627 if [ -n "$_chroot" ]; then 628 _doit="\ 629${_nice:+nice -n $_nice }\ 630chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 631$_chroot $command $rc_flags $command_args" 632 else 633 _doit="\ 634${_chdir:+cd $_chdir; }\ 635${_nice:+nice -n $_nice }\ 636$command $rc_flags $command_args" 637 if [ -n "$_user" ]; then 638 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 639 fi 640 fi 641 642 # if the cmd failed and force 643 # isn't set, exit 644 # 645 debug "run_rc_command: _doit: $_doit" 646 eval $_doit 647 _return=$? 648 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 649 650 # finally, run postcmd 651 # 652 if [ -n "${_postcmd}" ]; then 653 debug "run_rc_command: evaluating ${_postcmd}()." 654 eval $_postcmd 655 fi 656 ;; 657 658 stop) 659 if [ -z "$rc_pid" ]; then 660 if [ -n "$pidfile" ]; then 661 echo \ 662 "${name} not running? (check $pidfile)." 663 else 664 echo "${name} not running?" 665 fi 666 exit 1 667 fi 668 669 # if the precmd failed and force 670 # isn't set, exit 671 # 672 if [ -n "$_precmd" ]; then 673 eval $_precmd 674 _return=$? 675 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 676 return 1 677 fi 678 679 # send the signal to stop 680 # 681 echo "Stopping ${name}." 682 _doit="kill -${sig_stop:-TERM} $rc_pid" 683 if [ -n "$_user" ]; then 684 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 685 fi 686 687 # if the stop cmd failed and force 688 # isn't set, exit 689 # 690 eval $_doit 691 _return=$? 692 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 693 694 # wait for the command to exit, 695 # and run postcmd. 696 wait_for_pids $rc_pid 697 if [ -n "$_postcmd" ]; then 698 eval $_postcmd 699 _return=$? 700 fi 701 ;; 702 703 reload) 704 if [ -z "$rc_pid" ]; then 705 if [ -n "$pidfile" ]; then 706 echo \ 707 "${name} not running? (check $pidfile)." 708 else 709 echo "${name} not running?" 710 fi 711 exit 1 712 fi 713 echo "Reloading ${name} config files." 714 if [ -n "$_precmd" ]; then 715 eval $_precmd 716 _return=$? 717 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 718 return 1 719 fi 720 _doit="kill -${sig_reload:-HUP} $rc_pid" 721 if [ -n "$_user" ]; then 722 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 723 fi 724 eval $_doit 725 _return=$? 726 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 727 if [ -n "$_postcmd" ]; then 728 eval $_postcmd 729 _return=$? 730 fi 731 ;; 732 733 restart) 734 if [ -n "$_precmd" ]; then 735 eval $_precmd 736 _return=$? 737 [ $_return -ne 0 ] && [ -z "$rc_force" ] && 738 return 1 739 fi 740 # prevent restart being called more 741 # than once by any given script 742 # 743 if [ -n "$_rc_restart_done" ]; then 744 return 0 745 fi 746 _rc_restart_done=YES 747 748 ( $0 ${rc_force:+force}stop ) 749 $0 ${rc_force:+force}start 750 751 if [ -n "$_postcmd" ]; then 752 eval $_postcmd 753 _return=$? 754 fi 755 ;; 756 757 poll) 758 if [ -n "$rc_pid" ]; then 759 wait_for_pids $rc_pid 760 fi 761 ;; 762 763 rcvar) 764 echo "# $name" 765 if [ -n "$rcvar" ]; then 766 if checkyesno ${rcvar}; then 767 echo "\$${rcvar}=YES" 768 else 769 echo "\$${rcvar}=NO" 770 fi 771 fi 772 ;; 773 774 *) 775 rc_usage "$_keywords" 776 ;; 777 778 esac 779 return $_return 780 done 781 782 echo 1>&2 "$0: unknown directive '$rc_arg'." 783 rc_usage "$_keywords" 784 exit 1 785} 786 787# 788# run_rc_script file arg 789# Start the script `file' with `arg', and correctly handle the 790# return value from the script. If `file' ends with `.sh', it's 791# sourced into the current environment. If `file' appears to be 792# a backup or scratch file, ignore it. Otherwise if it's 793# executable run as a child process. 794# 795run_rc_script() 796{ 797 _file=$1 798 _arg=$2 799 if [ -z "$_file" -o -z "$_arg" ]; then 800 err 3 'USAGE: run_rc_script file arg' 801 fi 802 803 trap "echo 'Reboot interrupted'; exit 1" 3 804 805 unset name command command_args command_interpreter \ 806 extra_commands pidfile procname \ 807 rcvar required_dirs required_files required_vars 808 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 809 810 case "$_file" in 811 *.sh) # run in current shell 812 set $_arg ; . $_file 813 ;; 814 *[~#]|*.OLD|*.orig) # scratch file; skip 815 warn "Ignoring scratch file $_file" 816 ;; 817 *) # run in subshell 818 if [ -x $_file ]; then 819 if [ -n "$rc_fast_and_loose" ]; then 820 set $_arg ; . $_file 821 else 822 ( trap "echo 'Reboot interrupted'; exit 1" 3 823 set $_arg ; . $_file ) 824 fi 825 fi 826 ;; 827 esac 828} 829 830# 831# load_rc_config 832# Source in the configuration file for a given command. 833# 834load_rc_config() 835{ 836 _command=$1 837 if [ -z "$_command" ]; then 838 err 3 'USAGE: load_rc_config command' 839 fi 840 841 if [ -z "$_rc_conf_loaded" ]; then 842 if [ -r /etc/defaults/rc.conf ]; then 843 debug "Sourcing /etc/defaults/rc.conf" 844 . /etc/defaults/rc.conf 845 source_rc_confs 846 elif [ -r /etc/rc.conf ]; then 847 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 848 . /etc/rc.conf 849 fi 850 _rc_conf_loaded=YES 851 fi 852 if [ -f /etc/rc.conf.d/"$_command" ]; then 853 debug "Sourcing /etc/rc.conf.d/${_command}" 854 . /etc/rc.conf.d/"$_command" 855 fi 856 857 # XXX - Deprecated variable name support 858 # 859 case ${OSTYPE} in 860 FreeBSD) 861 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable" 862 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program" 863 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags" 864 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable" 865 [ -n "$xntpd_enable" ] && ntpd_enable="$xntpd_enable" 866 [ -n "$xntpd_program" ] && ntpd_program="$xntpd_program" 867 [ -n "$xntpd_flags" ] && ntpd_flags="$xntpd_flags" 868 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program" 869 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags" 870 ;; 871 esac 872 873} 874 875# 876# rc_usage commands 877# Print a usage string for $0, with `commands' being a list of 878# valid commands. 879# 880rc_usage() 881{ 882 echo -n 1>&2 "Usage: $0 [fast|force](" 883 884 _sep= 885 for _elem in $*; do 886 echo -n 1>&2 "$_sep$_elem" 887 _sep="|" 888 done 889 echo 1>&2 ")" 890 exit 1 891} 892 893# 894# err exitval message 895# Display message to stderr and log to the syslog, and exit with exitval. 896# 897err() 898{ 899 exitval=$1 900 shift 901 902 if [ -x /usr/bin/logger ]; then 903 logger "$0: ERROR: $*" 904 fi 905 echo 1>&2 "$0: ERROR: $*" 906 exit $exitval 907} 908 909# 910# warn message 911# Display message to stderr and log to the syslog. 912# 913warn() 914{ 915 if [ -x /usr/bin/logger ]; then 916 logger "$0: WARNING: $*" 917 fi 918 echo 1>&2 "$0: WARNING: $*" 919} 920 921# 922# info message 923# Display informational message to stdout and log to syslog. 924# 925info() 926{ 927 if [ -x /usr/bin/logger ]; then 928 logger "$0: INFO: $*" 929 fi 930 echo "$0: INFO: $*" 931} 932 933# 934# debug message 935# If debugging is enabled in rc.conf output message to stderr. 936# BEWARE that you don't call any subroutine that itself calls this 937# function. 938# 939debug() 940{ 941 case ${rc_debug} in 942 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 943 if [ -x /usr/bin/logger ]; then 944 logger "$0: INFO: $*" 945 fi 946 echo 1>&2 "$0: DEBUG: $*" 947 ;; 948 esac 949} 950 951# 952# backup_file action file cur backup 953# Make a backup copy of `file' into `cur', and save the previous 954# version of `cur' as `backup' or use rcs for archiving. 955# 956# This routine checks the value of the backup_uses_rcs variable, 957# which can be either YES or NO. 958# 959# The `action' keyword can be one of the following: 960# 961# add `file' is now being backed up (and is possibly 962# being reentered into the backups system). `cur' 963# is created and RCS files, if necessary, are 964# created as well. 965# 966# update `file' has changed and needs to be backed up. 967# If `cur' exists, it is copied to to `back' or 968# checked into RCS (if the repository file is old), 969# and then `file' is copied to `cur'. Another RCS 970# check in done here if RCS is being used. 971# 972# remove `file' is no longer being tracked by the backups 973# system. If RCS is not being used, `cur' is moved 974# to `back', otherwise an empty file is checked in, 975# and then `cur' is removed. 976# 977# 978backup_file() 979{ 980 _action=$1 981 _file=$2 982 _cur=$3 983 _back=$4 984 985 if checkyesno backup_uses_rcs; then 986 _msg0="backup archive" 987 _msg1="update" 988 989 # ensure that history file is not locked 990 if [ -f $_cur,v ]; then 991 rcs -q -u -U -M $_cur 992 fi 993 994 # ensure after switching to rcs that the 995 # current backup is not lost 996 if [ -f $_cur ]; then 997 # no archive, or current newer than archive 998 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 999 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1000 rcs -q -kb -U $_cur 1001 co -q -f -u $_cur 1002 fi 1003 fi 1004 1005 case $_action in 1006 add|update) 1007 cp -p $_file $_cur 1008 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1009 rcs -q -kb -U $_cur 1010 co -q -f -u $_cur 1011 chown root:wheel $_cur $_cur,v 1012 ;; 1013 remove) 1014 cp /dev/null $_cur 1015 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1016 rcs -q -kb -U $_cur 1017 chown root:wheel $_cur $_cur,v 1018 rm $_cur 1019 ;; 1020 esac 1021 else 1022 case $_action in 1023 add|update) 1024 if [ -f $_cur ]; then 1025 cp -p $_cur $_back 1026 fi 1027 cp -p $_file $_cur 1028 chown root:wheel $_cur 1029 ;; 1030 remove) 1031 mv -f $_cur $_back 1032 ;; 1033 esac 1034 fi 1035} 1036 1037# devfs_link dir src link 1038# Make a symbolic link 'link' to src in chroot/dev. 1039# Returns 0 on sucess. 1040# 1041devfs_link() 1042{ 1043 local dir src link _me 1044 dir="$1" 1045 src="$2" 1046 link="$3" 1047 _me="devfs_link" 1048 1049 if [ -z "$dir" -o -z "$src" -o -z "$link" ]; then 1050 warn "devfs_link(): requires three arguments." 1051 return 1 1052 fi 1053 if [ -z "$dir" ]; then 1054 warn "$_me: the directory ($dir) does not exist" 1055 return 1 1056 fi 1057 cd ${chroot}/dev 1058 if ! ln -sf $src $link ; then 1059 warn "$_me: unable to link $link --> $src in $dir" 1060 return 1 1061 fi 1062 return 0 1063} 1064 1065# devfs_rulesets_from_file file 1066# Reads a set of devfs commands from file, and creates 1067# the specified rulesets with their rules. Returns non-zero 1068# if there was an error. 1069# 1070devfs_rulesets_from_file() 1071{ 1072 local file _err _me 1073 file="$1" 1074 _me="devfs_rulesets_from_file" 1075 _err=0 1076 1077 if [ -z "$file" ]; then 1078 warn "$_me: you must specify a file" 1079 return 1 1080 fi 1081 if [ ! -e "$file" ]; then 1082 debug "$_me: no such file ($file)" 1083 return 0 1084 fi 1085 debug "reading rulesets from file ($file)" 1086 { while read line 1087 do 1088 case $line in 1089 \#*) 1090 continue 1091 ;; 1092 \[*\]*) 1093 rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"` 1094 if [ -z "$rulenum" ]; then 1095 warn "$_me: cannot extract rule number ($line)" 1096 _err=1 1097 break 1098 fi 1099 rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"` 1100 if [ -z "$rulename" ]; then 1101 warn "$_me: cannot extract rule name ($line)" 1102 _err=1 1103 break; 1104 fi 1105 eval $rulename=\$rulenum 1106 debug "found ruleset: $rulename=$rulenum" 1107 if ! /sbin/devfs rule -s $rulenum delset ; then 1108 _err=1 1109 break 1110 fi 1111 ;; 1112 *) 1113 rulecmd="${line%%"\#*"}" 1114 # evaluate the command incase it includes 1115 # other rules 1116 if [ -n "$rulecmd" ]; then 1117 debug "adding rule ($rulecmd)" 1118 if ! eval /sbin/devfs rule -s $rulenum $rulecmd 1119 then 1120 _err=1 1121 break 1122 fi 1123 fi 1124 ;; 1125 esac 1126 if [ $_err -ne 0 ]; then 1127 debug "error in $_me" 1128 break 1129 fi 1130 done } < $file 1131 return $_err 1132} 1133 1134# devfs_init_rulesets 1135# Initializes rulesets from configuration files. Returns 1136# non-zero if there was an error. 1137# 1138devfs_init_rulesets() 1139{ 1140 local file _me 1141 _me="devfs_init_rulesets" 1142 1143 # Go through this only once 1144 if [ -n "$devfs_rulesets_init" ]; then 1145 debug "$_me: devfs rulesets already initialized" 1146 return 1147 fi 1148 for file in $devfs_rulesets ; do 1149 devfs_rulesets_from_file $file || return 1 1150 done 1151 devfs_rulesets_init=1 1152 debug "$_me: devfs rulesets initialized" 1153 return 0 1154} 1155 1156# devfs_set_ruleset ruleset [dir] 1157# Sets the default ruleset of dir to ruleset. The ruleset arguement 1158# must be a ruleset name as specified in devfs.rules(5) file. 1159# Returns non-zero if it could not set it successfully. 1160# 1161devfs_set_ruleset() 1162{ 1163 local devdir rs _me 1164 [ -n "$1" ] && eval rs=\$$1 || rs= 1165 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1166 _me="devfs_set_ruleset" 1167 1168 if [ -z "$rs" ]; then 1169 warn "$_me: you must specify a ruleset number" 1170 return 1 1171 fi 1172 debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })" 1173 if ! /sbin/devfs $devdir ruleset $rs ; then 1174 warn "$_me: unable to set ruleset $rs to ${devdir#-m }" 1175 return 1 1176 fi 1177 return 0 1178} 1179 1180# devfs_apply_ruleset ruleset [dir] 1181# Apply ruleset number $ruleset to the devfs mountpoint $dir. 1182# The ruleset argument must be a ruleset name as specified 1183# in a devfs.rules(5) file. Returns 0 on success or non-zero 1184# if it could not apply the ruleset. 1185# 1186devfs_apply_ruleset() 1187{ 1188 local devdir rs _me 1189 [ -n "$1" ] && eval rs=\$$1 || rs= 1190 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1191 _me="devfs_apply_ruleset" 1192 1193 if [ -z "$rs" ]; then 1194 warn "$_me: you must specify a ruleset" 1195 return 1 1196 fi 1197 debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })" 1198 if ! /sbin/devfs $devdir rule -s $rs applyset ; then 1199 warn "$_me: unable to apply ruleset $rs to ${devdir#-m }" 1200 return 1 1201 fi 1202 return 0 1203} 1204 1205# devfs_domount dir [ruleset] 1206# Mount devfs on dir. If ruleset is specified it is set 1207# on the mount-point. It must also be a ruleset name as specified 1208# in a devfs.rules(5) file. Returns 0 on success. 1209# 1210devfs_domount() 1211{ 1212 local devdir rs _me 1213 devdir="$1" 1214 [ -n "$2" ] && rs=$2 || rs= 1215 _me="devfs_domount()" 1216 1217 if [ -z "$devdir" ]; then 1218 warn "$_me: you must specify a mount-point" 1219 return 1 1220 fi 1221 debug "$_me: mount-point is ($devdir), ruleset is ($rs)" 1222 if ! mount -t devfs dev "$devdir" ; then 1223 warn "$_me: Unable to mount devfs on $devdir" 1224 return 1 1225 fi 1226 if [ -n "$rs" ]; then 1227 devfs_init_rulesets 1228 devfs_set_ruleset $rs $devdir 1229 fi 1230 return 0 1231} 1232 1233# devfs_mount_jail dir [ruleset] 1234# Mounts a devfs file system appropriate for jails 1235# on the directory dir. If ruleset is specified, the ruleset 1236# it names will be used instead. If present, ruleset must 1237# be the name of a ruleset as defined in a devfs.rules(5) file. 1238# This function returns non-zero if an error occurs. 1239# 1240devfs_mount_jail() 1241{ 1242 local jdev rs _me 1243 jdev="$1" 1244 [ -n "$2" ] && rs=$2 || rs="devfsrules_jail" 1245 _me="devfs_mount_jail" 1246 1247 devfs_init_rulesets 1248 if ! devfs_domount "$jdev" $rs ; then 1249 warn "$_me: devfs was not mounted on $jdev" 1250 return 1 1251 fi 1252 return 0 1253} 1254