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