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