1# $NetBSD: rc.subr,v 1.67 2006/10/07 11:25:15 elad Exp $ 2# $FreeBSD$ 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# 19# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29# POSSIBILITY OF SUCH DAMAGE. 30# 31# rc.subr 32# functions used by various rc scripts 33# 34 35: ${RC_PID:=$$}; export RC_PID 36 37# 38# Operating System dependent/independent variables 39# 40 41if [ -z "${_rc_subr_loaded}" ]; then 42 43_rc_subr_loaded="YES" 44 45SYSCTL="/sbin/sysctl" 46SYSCTL_N="${SYSCTL} -n" 47SYSCTL_W="${SYSCTL}" 48ID="/usr/bin/id" 49IDCMD="if [ -x $ID ]; then $ID -un; fi" 50PS="/bin/ps -ww" 51JID=`$PS -p $$ -o jid=` 52 53# 54# functions 55# --------- 56 57# list_vars pattern 58# List vars matching pattern. 59# 60list_vars() 61{ 62 set | { while read LINE; do 63 var="${LINE%%=*}" 64 case "$var" in 65 "$LINE"|*[!a-zA-Z0-9_]*) continue ;; 66 $1) echo $var 67 esac 68 done; } 69} 70 71# set_rcvar [var] [defval] [desc] 72# 73# Echo or define a rc.conf(5) variable name. Global variable 74# $rcvars is used. 75# 76# If no argument is specified, echo "${name}_enable". 77# 78# If only a var is specified, echo "${var}_enable". 79# 80# If var and defval are specified, the ${var} is defined as 81# rc.conf(5) variable and the default value is ${defvar}. An 82# optional argument $desc can also be specified to add a 83# description for that. 84# 85set_rcvar() 86{ 87 case $# in 88 0) 89 echo ${name}_enable 90 ;; 91 1) 92 echo ${1}_enable 93 ;; 94 *) 95 debug "rcvar_define: \$$1=$2 is added" \ 96 " as a rc.conf(5) variable." 97 98 local _var 99 _var=$1 100 rcvars="${rcvars# } $_var" 101 eval ${_var}_defval=\"$2\" 102 shift 2 103 # encode multiple lines of _desc 104 for l in "$@"; do 105 eval ${_var}_desc=\"\${${_var}_desc#^^}^^$l\" 106 done 107 eval ${_var}_desc=\"\${${_var}_desc#^^}\" 108 ;; 109 esac 110} 111 112# set_rcvar_obsolete oldvar [newvar] [msg] 113# Define obsolete variable. 114# Global variable $rcvars_obsolete is used. 115# 116set_rcvar_obsolete() 117{ 118 local _var 119 _var=$1 120 debug "rcvar_obsolete: \$$1(old) -> \$$2(new) is defined" 121 122 rcvars_obsolete="${rcvars_obsolete# } $1" 123 eval ${1}_newvar=\"$2\" 124 shift 2 125 eval ${_var}_obsolete_msg=\"$*\" 126} 127 128# 129# force_depend script [rcvar] 130# Force a service to start. Intended for use by services 131# to resolve dependency issues. 132# $1 - filename of script, in /etc/rc.d, to run 133# $2 - name of the script's rcvar (minus the _enable) 134# 135force_depend() 136{ 137 local _depend _dep_rcvar 138 139 _depend="$1" 140 _dep_rcvar="${2:-$1}_enable" 141 142 [ -n "$rc_fast" ] && ! checkyesno always_force_depends && 143 checkyesno $_dep_rcvar && return 0 144 145 /etc/rc.d/${_depend} forcestatus >/dev/null 2>&1 && return 0 146 147 info "${name} depends on ${_depend}, which will be forced to start." 148 if ! /etc/rc.d/${_depend} forcestart; then 149 warn "Unable to force ${_depend}. It may already be running." 150 return 1 151 fi 152} 153 154# 155# checkyesno var 156# Test $1 variable, and warn if not set to YES or NO. 157# Return 0 if it's "yes" (et al), nonzero otherwise. 158# 159checkyesno() 160{ 161 eval _value=\$${1} 162 debug "checkyesno: $1 is set to $_value." 163 case $_value in 164 165 # "yes", "true", "on", or "1" 166 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 167 return 0 168 ;; 169 170 # "no", "false", "off", or "0" 171 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 172 return 1 173 ;; 174 *) 175 warn "\$${1} is not set properly - see rc.conf(5)." 176 return 1 177 ;; 178 esac 179} 180 181# 182# reverse_list list 183# print the list in reverse order 184# 185reverse_list() 186{ 187 _revlist= 188 for _revfile; do 189 _revlist="$_revfile $_revlist" 190 done 191 echo $_revlist 192} 193 194# stop_boot always 195# If booting directly to multiuser or $always is enabled, 196# send SIGTERM to the parent (/etc/rc) to abort the boot. 197# Otherwise just exit. 198# 199stop_boot() 200{ 201 local always 202 203 case $1 in 204 # "yes", "true", "on", or "1" 205 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 206 always=true 207 ;; 208 *) 209 always=false 210 ;; 211 esac 212 if [ "$autoboot" = yes -o "$always" = true ]; then 213 echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!" 214 kill -TERM ${RC_PID} 215 fi 216 exit 1 217} 218 219# 220# mount_critical_filesystems type 221# Go through the list of critical filesystems as provided in 222# the rc.conf(5) variable $critical_filesystems_${type}, checking 223# each one to see if it is mounted, and if it is not, mounting it. 224# 225mount_critical_filesystems() 226{ 227 eval _fslist=\$critical_filesystems_${1} 228 for _fs in $_fslist; do 229 mount | ( 230 _ismounted=false 231 while read what _on on _type type; do 232 if [ $on = $_fs ]; then 233 _ismounted=true 234 fi 235 done 236 if $_ismounted; then 237 : 238 else 239 mount $_fs >/dev/null 2>&1 240 fi 241 ) 242 done 243} 244 245# 246# check_pidfile pidfile procname [interpreter] 247# Parses the first line of pidfile for a PID, and ensures 248# that the process is running and matches procname. 249# Prints the matching PID upon success, nothing otherwise. 250# interpreter is optional; see _find_processes() for details. 251# 252check_pidfile() 253{ 254 _pidfile=$1 255 _procname=$2 256 _interpreter=$3 257 if [ -z "$_pidfile" -o -z "$_procname" ]; then 258 err 3 'USAGE: check_pidfile pidfile procname [interpreter]' 259 fi 260 if [ ! -f $_pidfile ]; then 261 debug "pid file ($_pidfile): not readable." 262 return 263 fi 264 read _pid _junk < $_pidfile 265 if [ -z "$_pid" ]; then 266 debug "pid file ($_pidfile): no pid in file." 267 return 268 fi 269 _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" 270} 271 272# 273# check_process procname [interpreter] 274# Ensures that a process (or processes) named procname is running. 275# Prints a list of matching PIDs. 276# interpreter is optional; see _find_processes() for details. 277# 278check_process() 279{ 280 _procname=$1 281 _interpreter=$2 282 if [ -z "$_procname" ]; then 283 err 3 'USAGE: check_process procname [interpreter]' 284 fi 285 _find_processes $_procname ${_interpreter:-.} '-ax' 286} 287 288# 289# _find_processes procname interpreter psargs 290# Search for procname in the output of ps generated by psargs. 291# Prints the PIDs of any matching processes, space separated. 292# 293# If interpreter == ".", check the following variations of procname 294# against the first word of each command: 295# procname 296# `basename procname` 297# `basename procname` + ":" 298# "(" + `basename procname` + ")" 299# "[" + `basename procname` + "]" 300# 301# If interpreter != ".", read the first line of procname, remove the 302# leading #!, normalise whitespace, append procname, and attempt to 303# match that against each command, either as is, or with extra words 304# at the end. As an alternative, to deal with interpreted daemons 305# using perl, the basename of the interpreter plus a colon is also 306# tried as the prefix to procname. 307# 308_find_processes() 309{ 310 if [ $# -ne 3 ]; then 311 err 3 'USAGE: _find_processes procname interpreter psargs' 312 fi 313 _procname=$1 314 _interpreter=$2 315 _psargs=$3 316 317 _pref= 318 if [ $_interpreter != "." ]; then # an interpreted script 319 _script="${_chroot}${_chroot:+/}$_procname" 320 if [ -r "$_script" ]; then 321 read _interp < $_script # read interpreter name 322 case "$_interp" in 323 \#!*) 324 _interp=${_interp#\#!} # strip #! 325 set -- $_interp 326 case $1 in 327 */bin/env) 328 shift # drop env to get real name 329 ;; 330 esac 331 if [ $_interpreter != $1 ]; then 332 warn "\$command_interpreter $_interpreter != $1" 333 fi 334 ;; 335 *) 336 warn "no shebang line in $_script" 337 set -- $_interpreter 338 ;; 339 esac 340 else 341 warn "cannot read shebang line from $_script" 342 set -- $_interpreter 343 fi 344 _interp="$* $_procname" # cleanup spaces, add _procname 345 _interpbn=${1##*/} 346 _fp_args='_argv' 347 _fp_match='case "$_argv" in 348 ${_interp}|"${_interp} "*|"[${_interpbn}]"|"${_interpbn}: ${_procname}"*)' 349 else # a normal daemon 350 _procnamebn=${_procname##*/} 351 _fp_args='_arg0 _argv' 352 _fp_match='case "$_arg0" in 353 $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})"|"[${_procnamebn}]")' 354 fi 355 356 _proccheck="\ 357 $PS 2>/dev/null -o pid= -o jid= -o command= $_psargs"' | 358 while read _npid _jid '"$_fp_args"'; do 359 '"$_fp_match"' 360 if [ "$JID" -eq "$_jid" ]; 361 then echo -n "$_pref$_npid"; 362 _pref=" "; 363 fi 364 ;; 365 esac 366 done' 367 368# debug "in _find_processes: proccheck is ($_proccheck)." 369 eval $_proccheck 370} 371 372# sort_lite [-b] [-n] [-k POS] [-t SEP] 373# A lite version of sort(1) (supporting a few options) that can be used 374# before the real sort(1) is available (e.g., in scripts that run prior 375# to mountcritremote). Requires only shell built-in functionality. 376# 377sort_lite() 378{ 379 local funcname=sort_lite 380 local sort_sep="$IFS" sort_ignore_leading_space= 381 local sort_field=0 sort_strict_fields= sort_numeric= 382 local nitems=0 skip_leading=0 trim= 383 384 local OPTIND flag 385 while getopts bnk:t: flag; do 386 case "$flag" in 387 b) sort_ignore_leading_space=1 ;; 388 n) sort_numeric=1 sort_ignore_leading_space=1 ;; 389 k) sort_field="${OPTARG%%,*}" ;; # only up to first comma 390 # NB: Unlike sort(1) only one POS allowed 391 t) sort_sep="$OPTARG" 392 if [ ${#sort_sep} -gt 1 ]; then 393 echo "$funcname: multi-character tab \`$sort_sep'" >&2 394 return 1 395 fi 396 sort_strict_fields=1 397 ;; 398 \?) return 1 ;; 399 esac 400 done 401 shift $(( $OPTIND - 1 )) 402 403 # Create transformation pattern to trim leading text if desired 404 case "$sort_field" in 405 ""|[!0-9]*|*[!0-9.]*) 406 echo "$funcname: invalid sort field \`$sort_field'" >&2 407 return 1 408 ;; 409 *.*) 410 skip_leading=${sort_field#*.} sort_field=${sort_field%%.*} 411 while [ ${skip_leading:-0} -gt 1 ] 2> /dev/null; do 412 trim="$trim?" skip_leading=$(( $skip_leading - 1 )) 413 done 414 esac 415 416 # Copy input to series of local numbered variables 417 # NB: IFS of NULL preserves leading whitespace 418 local LINE 419 while IFS= read -r LINE || [ "$LINE" ]; do 420 nitems=$(( $nitems + 1 )) 421 local src_$nitems="$LINE" 422 done 423 424 # 425 # Sort numbered locals using insertion sort 426 # 427 local curitem curitem_orig curitem_mod curitem_haskey 428 local dest dest_orig dest_mod dest_haskey 429 local d gt n 430 local i=1 431 while [ $i -le $nitems ]; do 432 curitem_haskey=1 # Assume sort field (-k POS) exists 433 eval curitem=\"\$src_$i\" 434 curitem_mod="$curitem" # for modified comparison 435 curitem_orig="$curitem" # for original comparison 436 437 # Trim leading whitespace if desired 438 if [ "$sort_ignore_leading_space" ]; then 439 while case "$curitem_orig" in 440 [$IFS]*) : ;; *) false; esac 441 do 442 curitem_orig="${curitem_orig#?}" 443 done 444 curitem_mod="$curitem_orig" 445 fi 446 447 # Shift modified comparison value if sort field (-k POS) is > 1 448 n=$sort_field 449 while [ $n -gt 1 ]; do 450 case "$curitem_mod" in 451 *[$sort_sep]*) 452 # Cut text up-to (and incl.) first separator 453 curitem_mod="${curitem_mod#*[$sort_sep]}" 454 455 # Skip NULLs unless strict field splitting 456 [ "$sort_strict_fields" ] || 457 [ "${curitem_mod%%[$sort_sep]*}" ] || 458 [ $n -eq 2 ] || 459 continue 460 ;; 461 *) 462 # Asked for a field that doesn't exist 463 curitem_haskey= break 464 esac 465 n=$(( $n - 1 )) 466 done 467 468 # Trim trailing words if sort field >= 1 469 [ $sort_field -ge 1 -a "$sort_numeric" ] && 470 curitem_mod="${curitem_mod%%[$sort_sep]*}" 471 472 # Apply optional trim (-k POS.TRIM) to cut leading characters 473 curitem_mod="${curitem_mod#$trim}" 474 475 # Determine the type of modified comparison to use initially 476 # NB: Prefer numerical if requested but fallback to standard 477 case "$curitem_mod" in 478 ""|[!0-9]*) # NULL or begins with non-number 479 gt=">" 480 [ "$sort_numeric" ] && curitem_mod=0 481 ;; 482 *) 483 if [ "$sort_numeric" ]; then 484 gt="-gt" 485 curitem_mod="${curitem_mod%%[!0-9]*}" 486 # NB: trailing non-digits removed 487 # otherwise numeric comparison fails 488 else 489 gt=">" 490 fi 491 esac 492 493 # If first time through, short-circuit below position-search 494 if [ $i -le 1 ]; then 495 d=0 496 else 497 d=1 498 fi 499 500 # 501 # Find appropriate element position 502 # 503 while [ $d -gt 0 ] 504 do 505 dest_haskey=$curitem_haskey 506 eval dest=\"\$dest_$d\" 507 dest_mod="$dest" # for modified comparison 508 dest_orig="$dest" # for original comparison 509 510 # Trim leading whitespace if desired 511 if [ "$sort_ignore_leading_space" ]; then 512 while case "$dest_orig" in 513 [$IFS]*) : ;; *) false; esac 514 do 515 dest_orig="${dest_orig#?}" 516 done 517 dest_mod="$dest_orig" 518 fi 519 520 # Shift modified value if sort field (-k POS) is > 1 521 n=$sort_field 522 while [ $n -gt 1 ]; do 523 case "$dest_mod" in 524 *[$sort_sep]*) 525 # Cut text up-to (and incl.) 1st sep 526 dest_mod="${dest_mod#*[$sort_sep]}" 527 528 # Skip NULLs unless strict fields 529 [ "$sort_strict_fields" ] || 530 [ "${dest_mod%%[$sort_sep]*}" ] || 531 [ $n -eq 2 ] || 532 continue 533 ;; 534 *) 535 # Asked for a field that doesn't exist 536 dest_haskey= break 537 esac 538 n=$(( $n - 1 )) 539 done 540 541 # Trim trailing words if sort field >= 1 542 [ $sort_field -ge 1 -a "$sort_numeric" ] && 543 dest_mod="${dest_mod%%[$sort_sep]*}" 544 545 # Apply optional trim (-k POS.TRIM), cut leading chars 546 dest_mod="${dest_mod#$trim}" 547 548 # Determine type of modified comparison to use 549 # NB: Prefer numerical if requested, fallback to std 550 case "$dest_mod" in 551 ""|[!0-9]*) # NULL or begins with non-number 552 gt=">" 553 [ "$sort_numeric" ] && dest_mod=0 554 ;; 555 *) 556 if [ "$sort_numeric" ]; then 557 gt="-gt" 558 dest_mod="${dest_mod%%[!0-9]*}" 559 # NB: kill trailing non-digits 560 # for numeric comparison safety 561 else 562 gt=">" 563 fi 564 esac 565 566 # Break if we've found the proper element position 567 if [ "$curitem_haskey" -a "$dest_haskey" ]; then 568 if [ "$dest_mod" = "$curitem_mod" ]; then 569 [ "$dest_orig" ">" "$curitem_orig" ] && 570 break 571 elif [ "$dest_mod" $gt "$curitem_mod" ] \ 572 2> /dev/null 573 then 574 break 575 fi 576 else 577 [ "$dest_orig" ">" "$curitem_orig" ] && break 578 fi 579 580 # Break if we've hit the end 581 [ $d -ge $i ] && break 582 583 d=$(( $d + 1 )) 584 done 585 586 # Shift remaining positions forward, making room for new item 587 n=$i 588 while [ $n -ge $d ]; do 589 # Shift destination item forward one placement 590 eval dest_$(( $n + 1 ))=\"\$dest_$n\" 591 n=$(( $n - 1 )) 592 done 593 594 # Place the element 595 if [ $i -eq 1 ]; then 596 local dest_1="$curitem" 597 else 598 local dest_$d="$curitem" 599 fi 600 601 i=$(( $i + 1 )) 602 done 603 604 # Print sorted results 605 d=1 606 while [ $d -le $nitems ]; do 607 eval echo \"\$dest_$d\" 608 d=$(( $d + 1 )) 609 done 610} 611 612# 613# wait_for_pids pid [pid ...] 614# spins until none of the pids exist 615# 616wait_for_pids() 617{ 618 local _list _prefix _nlist _j 619 620 _list="$@" 621 if [ -z "$_list" ]; then 622 return 623 fi 624 _prefix= 625 while true; do 626 _nlist=""; 627 for _j in $_list; do 628 if kill -0 $_j 2>/dev/null; then 629 _nlist="${_nlist}${_nlist:+ }$_j" 630 [ -n "$_prefix" ] && sleep 1 631 fi 632 done 633 if [ -z "$_nlist" ]; then 634 break 635 fi 636 _list=$_nlist 637 echo -n ${_prefix:-"Waiting for PIDS: "}$_list 638 _prefix=", " 639 pwait $_list 2>/dev/null 640 done 641 if [ -n "$_prefix" ]; then 642 echo "." 643 fi 644} 645 646# 647# get_pidfile_from_conf string file 648# 649# Takes a string to search for in the specified file. 650# Ignores lines with traditional comment characters. 651# 652# Example: 653# 654# if get_pidfile_from_conf string file; then 655# pidfile="$_pidfile_from_conf" 656# else 657# pidfile='appropriate default' 658# fi 659# 660get_pidfile_from_conf() 661{ 662 if [ -z "$1" -o -z "$2" ]; then 663 err 3 "USAGE: get_pidfile_from_conf string file ($name)" 664 fi 665 666 local string file line 667 668 string="$1" ; file="$2" 669 670 if [ ! -s "$file" ]; then 671 err 3 "get_pidfile_from_conf: $file does not exist ($name)" 672 fi 673 674 while read line; do 675 case "$line" in 676 *[#\;]*${string}*) continue ;; 677 *${string}*) break ;; 678 esac 679 done < $file 680 681 if [ -n "$line" ]; then 682 line=${line#*/} 683 _pidfile_from_conf="/${line%%[\"\;]*}" 684 else 685 return 1 686 fi 687} 688 689# 690# check_startmsgs 691# If rc_quiet is set (usually as a result of using faststart at 692# boot time) check if rc_startmsgs is enabled. 693# 694check_startmsgs() 695{ 696 if [ -n "$rc_quiet" ]; then 697 checkyesno rc_startmsgs 698 else 699 return 0 700 fi 701} 702 703# 704# run_rc_command argument 705# Search for argument in the list of supported commands, which is: 706# "start stop restart rcvar status poll ${extra_commands}" 707# If there's a match, run ${argument}_cmd or the default method 708# (see below). 709# 710# If argument has a given prefix, then change the operation as follows: 711# Prefix Operation 712# ------ --------- 713# fast Skip the pid check, and set rc_fast=yes, rc_quiet=yes 714# force Set ${rcvar} to YES, and set rc_force=yes 715# one Set ${rcvar} to YES 716# quiet Don't output some diagnostics, and set rc_quiet=yes 717# 718# The following globals are used: 719# 720# Name Needed Purpose 721# ---- ------ ------- 722# name y Name of script. 723# 724# command n Full path to command. 725# Not needed if ${rc_arg}_cmd is set for 726# each keyword. 727# 728# command_args n Optional args/shell directives for command. 729# 730# command_interpreter n If not empty, command is interpreted, so 731# call check_{pidfile,process}() appropriately. 732# 733# desc n Description of script. 734# 735# extra_commands n List of extra commands supported. 736# 737# pidfile n If set, use check_pidfile $pidfile $command, 738# otherwise use check_process $command. 739# In either case, only check if $command is set. 740# 741# procname n Process name to check for instead of $command. 742# 743# rcvar n This is checked with checkyesno to determine 744# if the action should be run. 745# 746# ${name}_program n Full path to command. 747# Meant to be used in /etc/rc.conf to override 748# ${command}. 749# 750# ${name}_chroot n Directory to chroot to before running ${command} 751# Requires /usr to be mounted. 752# 753# ${name}_chdir n Directory to cd to before running ${command} 754# (if not using ${name}_chroot). 755# 756# ${name}_flags n Arguments to call ${command} with. 757# NOTE: $flags from the parent environment 758# can be used to override this. 759# 760# ${name}_fib n Routing table number to run ${command} with. 761# 762# ${name}_nice n Nice level to run ${command} at. 763# 764# ${name}_user n User to run ${command} as, using su(1) if not 765# using ${name}_chroot. 766# Requires /usr to be mounted. 767# 768# ${name}_group n Group to run chrooted ${command} as. 769# Requires /usr to be mounted. 770# 771# ${name}_groups n Comma separated list of supplementary groups 772# to run the chrooted ${command} with. 773# Requires /usr to be mounted. 774# 775# ${rc_arg}_cmd n If set, use this as the method when invoked; 776# Otherwise, use default command (see below) 777# 778# ${rc_arg}_precmd n If set, run just before performing the 779# ${rc_arg}_cmd method in the default 780# operation (i.e, after checking for required 781# bits and process (non)existence). 782# If this completes with a non-zero exit code, 783# don't run ${rc_arg}_cmd. 784# 785# ${rc_arg}_postcmd n If set, run just after performing the 786# ${rc_arg}_cmd method, if that method 787# returned a zero exit code. 788# 789# required_dirs n If set, check for the existence of the given 790# directories before running a (re)start command. 791# 792# required_files n If set, check for the readability of the given 793# files before running a (re)start command. 794# 795# required_modules n If set, ensure the given kernel modules are 796# loaded before running a (re)start command. 797# The check and possible loads are actually 798# done after start_precmd so that the modules 799# aren't loaded in vain, should the precmd 800# return a non-zero status to indicate a error. 801# If a word in the list looks like "foo:bar", 802# "foo" is the KLD file name and "bar" is the 803# module name. If a word looks like "foo~bar", 804# "foo" is the KLD file name and "bar" is a 805# egrep(1) pattern matching the module name. 806# Otherwise the module name is assumed to be 807# the same as the KLD file name, which is most 808# common. See load_kld(). 809# 810# required_vars n If set, perform checkyesno on each of the 811# listed variables before running the default 812# (re)start command. 813# 814# Default behaviour for a given argument, if no override method is 815# provided: 816# 817# Argument Default behaviour 818# -------- ----------------- 819# start if !running && checkyesno ${rcvar} 820# ${command} 821# 822# stop if ${pidfile} 823# rc_pid=$(check_pidfile $pidfile $command) 824# else 825# rc_pid=$(check_process $command) 826# kill $sig_stop $rc_pid 827# wait_for_pids $rc_pid 828# ($sig_stop defaults to TERM.) 829# 830# reload Similar to stop, except use $sig_reload instead, 831# and doesn't wait_for_pids. 832# $sig_reload defaults to HUP. 833# Note that `reload' isn't provided by default, 834# it should be enabled via $extra_commands. 835# 836# restart Run `stop' then `start'. 837# 838# status Show if ${command} is running, etc. 839# 840# poll Wait for ${command} to exit. 841# 842# rcvar Display what rc.conf variable is used (if any). 843# 844# Variables available to methods, and after run_rc_command() has 845# completed: 846# 847# Variable Purpose 848# -------- ------- 849# rc_arg Argument to command, after fast/force/one processing 850# performed 851# 852# rc_flags Flags to start the default command with. 853# Defaults to ${name}_flags, unless overridden 854# by $flags from the environment. 855# This variable may be changed by the precmd method. 856# 857# rc_pid PID of command (if appropriate) 858# 859# rc_fast Not empty if "fast" was provided (q.v.) 860# 861# rc_force Not empty if "force" was provided (q.v.) 862# 863# rc_quiet Not empty if "quiet" was provided 864# 865# 866run_rc_command() 867{ 868 _return=0 869 rc_arg=$1 870 if [ -z "$name" ]; then 871 err 3 'run_rc_command: $name is not set.' 872 fi 873 874 # Don't repeat the first argument when passing additional command- 875 # line arguments to the command subroutines. 876 # 877 shift 1 878 rc_extra_args="$*" 879 880 _rc_prefix= 881 case "$rc_arg" in 882 fast*) # "fast" prefix; don't check pid 883 rc_arg=${rc_arg#fast} 884 rc_fast=yes 885 rc_quiet=yes 886 ;; 887 force*) # "force" prefix; always run 888 rc_force=yes 889 _rc_prefix=force 890 rc_arg=${rc_arg#${_rc_prefix}} 891 if [ -n "${rcvar}" ]; then 892 eval ${rcvar}=YES 893 fi 894 ;; 895 one*) # "one" prefix; set ${rcvar}=yes 896 _rc_prefix=one 897 rc_arg=${rc_arg#${_rc_prefix}} 898 if [ -n "${rcvar}" ]; then 899 eval ${rcvar}=YES 900 fi 901 ;; 902 quiet*) # "quiet" prefix; omit some messages 903 _rc_prefix=quiet 904 rc_arg=${rc_arg#${_rc_prefix}} 905 rc_quiet=yes 906 ;; 907 esac 908 909 eval _override_command=\$${name}_program 910 command=${_override_command:-$command} 911 912 _keywords="start stop restart rcvar $extra_commands" 913 rc_pid= 914 _pidcmd= 915 _procname=${procname:-${command}} 916 917 # setup pid check command 918 if [ -n "$_procname" ]; then 919 if [ -n "$pidfile" ]; then 920 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 921 else 922 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 923 fi 924 if [ -n "$_pidcmd" ]; then 925 _keywords="${_keywords} status poll" 926 fi 927 fi 928 929 if [ -z "$rc_arg" ]; then 930 rc_usage $_keywords 931 fi 932 933 if [ -n "$flags" ]; then # allow override from environment 934 rc_flags=$flags 935 else 936 eval rc_flags=\$${name}_flags 937 fi 938 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 939 _nice=\$${name}_nice _user=\$${name}_user \ 940 _group=\$${name}_group _groups=\$${name}_groups \ 941 _fib=\$${name}_fib 942 943 if [ -n "$_user" ]; then # unset $_user if running as that user 944 if [ "$_user" = "$(eval $IDCMD)" ]; then 945 unset _user 946 fi 947 fi 948 949 [ -z "$autoboot" ] && eval $_pidcmd # determine the pid if necessary 950 951 for _elem in $_keywords; do 952 if [ "$_elem" != "$rc_arg" ]; then 953 continue 954 fi 955 # if ${rcvar} is set, $1 is not "rcvar" 956 # and ${rc_pid} is not set, then run 957 # checkyesno ${rcvar} 958 # and return if that failed 959 # 960 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" -a "$rc_arg" != "stop" ] || 961 [ -n "${rcvar}" -a "$rc_arg" = "stop" -a -z "${rc_pid}" ]; then 962 if ! checkyesno ${rcvar}; then 963 if [ -n "${rc_quiet}" ]; then 964 return 0 965 fi 966 echo -n "Cannot '${rc_arg}' $name. Set ${rcvar} to " 967 echo -n "YES in /etc/rc.conf or use 'one${rc_arg}' " 968 echo "instead of '${rc_arg}'." 969 return 0 970 fi 971 fi 972 973 # if there's a custom ${XXX_cmd}, 974 # run that instead of the default 975 # 976 eval _cmd=\$${rc_arg}_cmd \ 977 _precmd=\$${rc_arg}_precmd \ 978 _postcmd=\$${rc_arg}_postcmd 979 980 if [ -n "$_cmd" ]; then 981 _run_rc_precmd || return 1 982 _run_rc_doit "$_cmd $rc_extra_args" || return 1 983 _run_rc_postcmd 984 return $_return 985 fi 986 987 case "$rc_arg" in # default operations... 988 989 status) 990 _run_rc_precmd || return 1 991 if [ -n "$rc_pid" ]; then 992 echo "${name} is running as pid $rc_pid." 993 else 994 echo "${name} is not running." 995 return 1 996 fi 997 _run_rc_postcmd 998 ;; 999 1000 start) 1001 if [ -z "$rc_fast" -a -n "$rc_pid" ]; then 1002 if [ -z "$rc_quiet" ]; then 1003 echo 1>&2 "${name} already running? " \ 1004 "(pid=$rc_pid)." 1005 fi 1006 return 1 1007 fi 1008 1009 if [ ! -x "${_chroot}${_chroot:+/}${command}" ]; then 1010 warn "run_rc_command: cannot run $command" 1011 return 1 1012 fi 1013 1014 if ! _run_rc_precmd; then 1015 warn "failed precmd routine for ${name}" 1016 return 1 1017 fi 1018 1019 # setup the full command to run 1020 # 1021 check_startmsgs && echo "Starting ${name}." 1022 if [ -n "$_chroot" ]; then 1023 _doit="\ 1024${_nice:+nice -n $_nice }\ 1025${_fib:+setfib -F $_fib }\ 1026chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 1027$_chroot $command $rc_flags $command_args" 1028 else 1029 _doit="\ 1030${_chdir:+cd $_chdir && }\ 1031${_fib:+setfib -F $_fib }\ 1032$command $rc_flags $command_args" 1033 if [ -n "$_user" ]; then 1034 _doit="su -m $_user -c 'sh -c \"$_doit\"'" 1035 fi 1036 if [ -n "$_nice" ]; then 1037 if [ -z "$_user" ]; then 1038 _doit="sh -c \"$_doit\"" 1039 fi 1040 _doit="nice -n $_nice $_doit" 1041 fi 1042 fi 1043 1044 # run the full command 1045 # 1046 if ! _run_rc_doit "$_doit"; then 1047 warn "failed to start ${name}" 1048 return 1 1049 fi 1050 1051 # finally, run postcmd 1052 # 1053 _run_rc_postcmd 1054 ;; 1055 1056 stop) 1057 if [ -z "$rc_pid" ]; then 1058 [ -n "$rc_fast" ] && return 0 1059 _run_rc_notrunning 1060 return 1 1061 fi 1062 1063 _run_rc_precmd || return 1 1064 1065 # send the signal to stop 1066 # 1067 echo "Stopping ${name}." 1068 _doit=$(_run_rc_killcmd "${sig_stop:-TERM}") 1069 _run_rc_doit "$_doit" || return 1 1070 1071 # wait for the command to exit, 1072 # and run postcmd. 1073 wait_for_pids $rc_pid 1074 1075 _run_rc_postcmd 1076 ;; 1077 1078 reload) 1079 if [ -z "$rc_pid" ]; then 1080 _run_rc_notrunning 1081 return 1 1082 fi 1083 1084 _run_rc_precmd || return 1 1085 1086 _doit=$(_run_rc_killcmd "${sig_reload:-HUP}") 1087 _run_rc_doit "$_doit" || return 1 1088 1089 _run_rc_postcmd 1090 ;; 1091 1092 restart) 1093 # prevent restart being called more 1094 # than once by any given script 1095 # 1096 if ${_rc_restart_done:-false}; then 1097 return 0 1098 fi 1099 _rc_restart_done=true 1100 1101 _run_rc_precmd || return 1 1102 1103 # run those in a subshell to keep global variables 1104 ( run_rc_command ${_rc_prefix}stop $rc_extra_args ) 1105 ( run_rc_command ${_rc_prefix}start $rc_extra_args ) 1106 _return=$? 1107 [ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1 1108 1109 _run_rc_postcmd 1110 ;; 1111 1112 poll) 1113 _run_rc_precmd || return 1 1114 if [ -n "$rc_pid" ]; then 1115 wait_for_pids $rc_pid 1116 fi 1117 _run_rc_postcmd 1118 ;; 1119 1120 rcvar) 1121 echo -n "# $name" 1122 if [ -n "$desc" ]; then 1123 echo " : $desc" 1124 else 1125 echo "" 1126 fi 1127 echo "#" 1128 # Get unique vars in $rcvar $rcvars 1129 for _v in $rcvar $rcvars; do 1130 case $v in 1131 $_v\ *|\ *$_v|*\ $_v\ *) ;; 1132 *) v="${v# } $_v" ;; 1133 esac 1134 done 1135 1136 # Display variables. 1137 for _v in $v; do 1138 if [ -z "$_v" ]; then 1139 continue 1140 fi 1141 1142 eval _desc=\$${_v}_desc 1143 eval _defval=\$${_v}_defval 1144 _h="-" 1145 1146 eval echo \"$_v=\\\"\$$_v\\\"\" 1147 # decode multiple lines of _desc 1148 while [ -n "$_desc" ]; do 1149 case $_desc in 1150 *^^*) 1151 echo "# $_h ${_desc%%^^*}" 1152 _desc=${_desc#*^^} 1153 _h=" " 1154 ;; 1155 *) 1156 echo "# $_h ${_desc}" 1157 break 1158 ;; 1159 esac 1160 done 1161 echo "# (default: \"$_defval\")" 1162 done 1163 echo "" 1164 ;; 1165 1166 *) 1167 rc_usage $_keywords 1168 ;; 1169 1170 esac 1171 return $_return 1172 done 1173 1174 echo 1>&2 "$0: unknown directive '$rc_arg'." 1175 rc_usage $_keywords 1176 # not reached 1177} 1178 1179# 1180# Helper functions for run_rc_command: common code. 1181# They use such global variables besides the exported rc_* ones: 1182# 1183# name R/W 1184# ------------------ 1185# _precmd R 1186# _postcmd R 1187# _return W 1188# 1189_run_rc_precmd() 1190{ 1191 check_required_before "$rc_arg" || return 1 1192 1193 if [ -n "$_precmd" ]; then 1194 debug "run_rc_command: ${rc_arg}_precmd: $_precmd $rc_extra_args" 1195 eval "$_precmd $rc_extra_args" 1196 _return=$? 1197 1198 # If precmd failed and force isn't set, request exit. 1199 if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then 1200 return 1 1201 fi 1202 fi 1203 1204 check_required_after "$rc_arg" || return 1 1205 1206 return 0 1207} 1208 1209_run_rc_postcmd() 1210{ 1211 if [ -n "$_postcmd" ]; then 1212 debug "run_rc_command: ${rc_arg}_postcmd: $_postcmd $rc_extra_args" 1213 eval "$_postcmd $rc_extra_args" 1214 _return=$? 1215 fi 1216 return 0 1217} 1218 1219_run_rc_doit() 1220{ 1221 debug "run_rc_command: doit: $*" 1222 eval "$@" 1223 _return=$? 1224 1225 # If command failed and force isn't set, request exit. 1226 if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then 1227 return 1 1228 fi 1229 1230 return 0 1231} 1232 1233_run_rc_notrunning() 1234{ 1235 local _pidmsg 1236 1237 if [ -n "$pidfile" ]; then 1238 _pidmsg=" (check $pidfile)." 1239 else 1240 _pidmsg= 1241 fi 1242 echo 1>&2 "${name} not running?${_pidmsg}" 1243} 1244 1245_run_rc_killcmd() 1246{ 1247 local _cmd 1248 1249 _cmd="kill -$1 $rc_pid" 1250 if [ -n "$_user" ]; then 1251 _cmd="su -m ${_user} -c 'sh -c \"${_cmd}\"'" 1252 fi 1253 echo "$_cmd" 1254} 1255 1256# 1257# run_rc_script file arg 1258# Start the script `file' with `arg', and correctly handle the 1259# return value from the script. 1260# If `file' ends with `.sh', it's sourced into the current environment 1261# when $rc_fast_and_loose is set, otherwise it is run as a child process. 1262# If `file' appears to be a backup or scratch file, ignore it. 1263# Otherwise if it is executable run as a child process. 1264# 1265run_rc_script() 1266{ 1267 _file=$1 1268 _arg=$2 1269 if [ -z "$_file" -o -z "$_arg" ]; then 1270 err 3 'USAGE: run_rc_script file arg' 1271 fi 1272 1273 unset name command command_args command_interpreter \ 1274 extra_commands pidfile procname \ 1275 rcvar rcvars rcvars_obsolete required_dirs required_files \ 1276 required_vars 1277 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 1278 1279 case "$_file" in 1280 /etc/rc.d/*.sh) # no longer allowed in the base 1281 warn "Ignoring old-style startup script $_file" 1282 ;; 1283 *[~#]|*.OLD|*.bak|*.orig|*,v) # scratch file; skip 1284 warn "Ignoring scratch file $_file" 1285 ;; 1286 *) # run in subshell 1287 if [ -x $_file ]; then 1288 if [ -n "$rc_fast_and_loose" ]; then 1289 set $_arg; . $_file 1290 else 1291 ( trap "echo Script $_file interrupted >&2 ; kill -QUIT $$" 3 1292 trap "echo Script $_file interrupted >&2 ; exit 1" 2 1293 trap "echo Script $_file running >&2" 29 1294 set $_arg; . $_file ) 1295 fi 1296 fi 1297 ;; 1298 esac 1299} 1300 1301# 1302# load_rc_config name 1303# Source in the configuration file for a given name. 1304# 1305load_rc_config() 1306{ 1307 local _name _var _defval _v _msg _new 1308 _name=$1 1309 if [ -z "$_name" ]; then 1310 err 3 'USAGE: load_rc_config name' 1311 fi 1312 1313 if ${_rc_conf_loaded:-false}; then 1314 : 1315 else 1316 if [ -r /etc/defaults/rc.conf ]; then 1317 debug "Sourcing /etc/defaults/rc.conf" 1318 . /etc/defaults/rc.conf 1319 source_rc_confs 1320 elif [ -r /etc/rc.conf ]; then 1321 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)." 1322 . /etc/rc.conf 1323 fi 1324 _rc_conf_loaded=true 1325 fi 1326 if [ -f /etc/rc.conf.d/"$_name" ]; then 1327 debug "Sourcing /etc/rc.conf.d/${_name}" 1328 . /etc/rc.conf.d/"$_name" 1329 fi 1330 1331 # Set defaults if defined. 1332 for _var in $rcvar $rcvars; do 1333 eval _defval=\$${_var}_defval 1334 if [ -n "$_defval" ]; then 1335 eval : \${$_var:=\$${_var}_defval} 1336 fi 1337 done 1338 1339 # check obsolete rc.conf variables 1340 for _var in $rcvars_obsolete; do 1341 eval _v=\$$_var 1342 eval _msg=\$${_var}_obsolete_msg 1343 eval _new=\$${_var}_newvar 1344 case $_v in 1345 "") 1346 ;; 1347 *) 1348 if [ -z "$_new" ]; then 1349 _msg="Ignored." 1350 else 1351 eval $_new=\"\$$_var\" 1352 if [ -z "$_msg" ]; then 1353 _msg="Use \$$_new instead." 1354 fi 1355 fi 1356 warn "\$$_var is obsolete. $_msg" 1357 ;; 1358 esac 1359 done 1360} 1361 1362# 1363# load_rc_config_var name var 1364# Read the rc.conf(5) var for name and set in the 1365# current shell, using load_rc_config in a subshell to prevent 1366# unwanted side effects from other variable assignments. 1367# 1368load_rc_config_var() 1369{ 1370 if [ $# -ne 2 ]; then 1371 err 3 'USAGE: load_rc_config_var name var' 1372 fi 1373 eval $(eval '( 1374 load_rc_config '$1' >/dev/null; 1375 if [ -n "${'$2'}" -o "${'$2'-UNSET}" != "UNSET" ]; then 1376 echo '$2'=\'\''${'$2'}\'\''; 1377 fi 1378 )' ) 1379} 1380 1381# 1382# rc_usage commands 1383# Print a usage string for $0, with `commands' being a list of 1384# valid commands. 1385# 1386rc_usage() 1387{ 1388 echo -n 1>&2 "Usage: $0 [fast|force|one|quiet](" 1389 1390 _sep= 1391 for _elem; do 1392 echo -n 1>&2 "$_sep$_elem" 1393 _sep="|" 1394 done 1395 echo 1>&2 ")" 1396 exit 1 1397} 1398 1399# 1400# err exitval message 1401# Display message to stderr and log to the syslog, and exit with exitval. 1402# 1403err() 1404{ 1405 exitval=$1 1406 shift 1407 1408 if [ -x /usr/bin/logger ]; then 1409 logger "$0: ERROR: $*" 1410 fi 1411 echo 1>&2 "$0: ERROR: $*" 1412 exit $exitval 1413} 1414 1415# 1416# warn message 1417# Display message to stderr and log to the syslog. 1418# 1419warn() 1420{ 1421 if [ -x /usr/bin/logger ]; then 1422 logger "$0: WARNING: $*" 1423 fi 1424 echo 1>&2 "$0: WARNING: $*" 1425} 1426 1427# 1428# info message 1429# Display informational message to stdout and log to syslog. 1430# 1431info() 1432{ 1433 case ${rc_info} in 1434 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1435 if [ -x /usr/bin/logger ]; then 1436 logger "$0: INFO: $*" 1437 fi 1438 echo "$0: INFO: $*" 1439 ;; 1440 esac 1441} 1442 1443# 1444# debug message 1445# If debugging is enabled in rc.conf output message to stderr. 1446# BEWARE that you don't call any subroutine that itself calls this 1447# function. 1448# 1449debug() 1450{ 1451 case ${rc_debug} in 1452 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 1453 if [ -x /usr/bin/logger ]; then 1454 logger "$0: DEBUG: $*" 1455 fi 1456 echo 1>&2 "$0: DEBUG: $*" 1457 ;; 1458 esac 1459} 1460 1461# 1462# backup_file action file cur backup 1463# Make a backup copy of `file' into `cur', and save the previous 1464# version of `cur' as `backup' or use rcs for archiving. 1465# 1466# This routine checks the value of the backup_uses_rcs variable, 1467# which can be either YES or NO. 1468# 1469# The `action' keyword can be one of the following: 1470# 1471# add `file' is now being backed up (and is possibly 1472# being reentered into the backups system). `cur' 1473# is created and RCS files, if necessary, are 1474# created as well. 1475# 1476# update `file' has changed and needs to be backed up. 1477# If `cur' exists, it is copied to to `back' or 1478# checked into RCS (if the repository file is old), 1479# and then `file' is copied to `cur'. Another RCS 1480# check in done here if RCS is being used. 1481# 1482# remove `file' is no longer being tracked by the backups 1483# system. If RCS is not being used, `cur' is moved 1484# to `back', otherwise an empty file is checked in, 1485# and then `cur' is removed. 1486# 1487# 1488backup_file() 1489{ 1490 _action=$1 1491 _file=$2 1492 _cur=$3 1493 _back=$4 1494 1495 if checkyesno backup_uses_rcs; then 1496 _msg0="backup archive" 1497 _msg1="update" 1498 1499 # ensure that history file is not locked 1500 if [ -f $_cur,v ]; then 1501 rcs -q -u -U -M $_cur 1502 fi 1503 1504 # ensure after switching to rcs that the 1505 # current backup is not lost 1506 if [ -f $_cur ]; then 1507 # no archive, or current newer than archive 1508 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then 1509 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1510 rcs -q -kb -U $_cur 1511 co -q -f -u $_cur 1512 fi 1513 fi 1514 1515 case $_action in 1516 add|update) 1517 cp -p $_file $_cur 1518 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1519 rcs -q -kb -U $_cur 1520 co -q -f -u $_cur 1521 chown root:wheel $_cur $_cur,v 1522 ;; 1523 remove) 1524 cp /dev/null $_cur 1525 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 1526 rcs -q -kb -U $_cur 1527 chown root:wheel $_cur $_cur,v 1528 rm $_cur 1529 ;; 1530 esac 1531 else 1532 case $_action in 1533 add|update) 1534 if [ -f $_cur ]; then 1535 cp -p $_cur $_back 1536 fi 1537 cp -p $_file $_cur 1538 chown root:wheel $_cur 1539 ;; 1540 remove) 1541 mv -f $_cur $_back 1542 ;; 1543 esac 1544 fi 1545} 1546 1547# make_symlink src link 1548# Make a symbolic link 'link' to src from basedir. If the 1549# directory in which link is to be created does not exist 1550# a warning will be displayed and an error will be returned. 1551# Returns 0 on sucess, 1 otherwise. 1552# 1553make_symlink() 1554{ 1555 local src link linkdir _me 1556 src="$1" 1557 link="$2" 1558 linkdir="`dirname $link`" 1559 _me="make_symlink()" 1560 1561 if [ -z "$src" -o -z "$link" ]; then 1562 warn "$_me: requires two arguments." 1563 return 1 1564 fi 1565 if [ ! -d "$linkdir" ]; then 1566 warn "$_me: the directory $linkdir does not exist." 1567 return 1 1568 fi 1569 if ! ln -sf $src $link; then 1570 warn "$_me: unable to make a symbolic link from $link to $src" 1571 return 1 1572 fi 1573 return 0 1574} 1575 1576# devfs_rulesets_from_file file 1577# Reads a set of devfs commands from file, and creates 1578# the specified rulesets with their rules. Returns non-zero 1579# if there was an error. 1580# 1581devfs_rulesets_from_file() 1582{ 1583 local file _err _me _opts 1584 file="$1" 1585 _me="devfs_rulesets_from_file" 1586 _err=0 1587 1588 if [ -z "$file" ]; then 1589 warn "$_me: you must specify a file" 1590 return 1 1591 fi 1592 if [ ! -e "$file" ]; then 1593 debug "$_me: no such file ($file)" 1594 return 0 1595 fi 1596 1597 # Disable globbing so that the rule patterns are not expanded 1598 # by accident with matching filesystem entries. 1599 _opts=$-; set -f 1600 1601 debug "reading rulesets from file ($file)" 1602 { while read line 1603 do 1604 case $line in 1605 \#*) 1606 continue 1607 ;; 1608 \[*\]*) 1609 rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"` 1610 if [ -z "$rulenum" ]; then 1611 warn "$_me: cannot extract rule number ($line)" 1612 _err=1 1613 break 1614 fi 1615 rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"` 1616 if [ -z "$rulename" ]; then 1617 warn "$_me: cannot extract rule name ($line)" 1618 _err=1 1619 break; 1620 fi 1621 eval $rulename=\$rulenum 1622 debug "found ruleset: $rulename=$rulenum" 1623 if ! /sbin/devfs rule -s $rulenum delset; then 1624 _err=1 1625 break 1626 fi 1627 ;; 1628 *) 1629 rulecmd="${line%%"\#*"}" 1630 # evaluate the command incase it includes 1631 # other rules 1632 if [ -n "$rulecmd" ]; then 1633 debug "adding rule ($rulecmd)" 1634 if ! eval /sbin/devfs rule -s $rulenum $rulecmd 1635 then 1636 _err=1 1637 break 1638 fi 1639 fi 1640 ;; 1641 esac 1642 if [ $_err -ne 0 ]; then 1643 debug "error in $_me" 1644 break 1645 fi 1646 done } < $file 1647 case $_opts in *f*) ;; *) set +f ;; esac 1648 return $_err 1649} 1650 1651# devfs_init_rulesets 1652# Initializes rulesets from configuration files. Returns 1653# non-zero if there was an error. 1654# 1655devfs_init_rulesets() 1656{ 1657 local file _me 1658 _me="devfs_init_rulesets" 1659 1660 # Go through this only once 1661 if [ -n "$devfs_rulesets_init" ]; then 1662 debug "$_me: devfs rulesets already initialized" 1663 return 1664 fi 1665 for file in $devfs_rulesets; do 1666 if ! devfs_rulesets_from_file $file; then 1667 warn "$_me: could not read rules from $file" 1668 return 1 1669 fi 1670 done 1671 devfs_rulesets_init=1 1672 debug "$_me: devfs rulesets initialized" 1673 return 0 1674} 1675 1676# devfs_set_ruleset ruleset [dir] 1677# Sets the default ruleset of dir to ruleset. The ruleset argument 1678# must be a ruleset name as specified in devfs.rules(5) file. 1679# Returns non-zero if it could not set it successfully. 1680# 1681devfs_set_ruleset() 1682{ 1683 local devdir rs _me 1684 [ -n "$1" ] && eval rs=\$$1 || rs= 1685 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1686 _me="devfs_set_ruleset" 1687 1688 if [ -z "$rs" ]; then 1689 warn "$_me: you must specify a ruleset number" 1690 return 1 1691 fi 1692 debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })" 1693 if ! /sbin/devfs $devdir ruleset $rs; then 1694 warn "$_me: unable to set ruleset $rs to ${devdir#-m }" 1695 return 1 1696 fi 1697 return 0 1698} 1699 1700# devfs_apply_ruleset ruleset [dir] 1701# Apply ruleset number $ruleset to the devfs mountpoint $dir. 1702# The ruleset argument must be a ruleset name as specified 1703# in a devfs.rules(5) file. Returns 0 on success or non-zero 1704# if it could not apply the ruleset. 1705# 1706devfs_apply_ruleset() 1707{ 1708 local devdir rs _me 1709 [ -n "$1" ] && eval rs=\$$1 || rs= 1710 [ -n "$2" ] && devdir="-m "$2"" || devdir= 1711 _me="devfs_apply_ruleset" 1712 1713 if [ -z "$rs" ]; then 1714 warn "$_me: you must specify a ruleset" 1715 return 1 1716 fi 1717 debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })" 1718 if ! /sbin/devfs $devdir rule -s $rs applyset; then 1719 warn "$_me: unable to apply ruleset $rs to ${devdir#-m }" 1720 return 1 1721 fi 1722 return 0 1723} 1724 1725# devfs_domount dir [ruleset] 1726# Mount devfs on dir. If ruleset is specified it is set 1727# on the mount-point. It must also be a ruleset name as specified 1728# in a devfs.rules(5) file. Returns 0 on success. 1729# 1730devfs_domount() 1731{ 1732 local devdir rs _me 1733 devdir="$1" 1734 [ -n "$2" ] && rs=$2 || rs= 1735 _me="devfs_domount()" 1736 1737 if [ -z "$devdir" ]; then 1738 warn "$_me: you must specify a mount-point" 1739 return 1 1740 fi 1741 debug "$_me: mount-point is ($devdir), ruleset is ($rs)" 1742 if ! mount -t devfs dev "$devdir"; then 1743 warn "$_me: Unable to mount devfs on $devdir" 1744 return 1 1745 fi 1746 if [ -n "$rs" ]; then 1747 devfs_init_rulesets 1748 devfs_set_ruleset $rs $devdir 1749 devfs -m $devdir rule applyset 1750 fi 1751 return 0 1752} 1753 1754# devfs_mount_jail dir [ruleset] 1755# Mounts a devfs file system appropriate for jails 1756# on the directory dir. If ruleset is specified, the ruleset 1757# it names will be used instead. If present, ruleset must 1758# be the name of a ruleset as defined in a devfs.rules(5) file. 1759# This function returns non-zero if an error occurs. 1760# 1761devfs_mount_jail() 1762{ 1763 local jdev rs _me 1764 jdev="$1" 1765 [ -n "$2" ] && rs=$2 || rs="devfsrules_jail" 1766 _me="devfs_mount_jail" 1767 1768 devfs_init_rulesets 1769 if ! devfs_domount "$jdev" $rs; then 1770 warn "$_me: devfs was not mounted on $jdev" 1771 return 1 1772 fi 1773 return 0 1774} 1775 1776# Provide a function for normalizing the mounting of memory 1777# filesystems. This should allow the rest of the code here to remain 1778# as close as possible between 5-current and 4-stable. 1779# $1 = size 1780# $2 = mount point 1781# $3 = (optional) extra mdmfs flags 1782mount_md() 1783{ 1784 if [ -n "$3" ]; then 1785 flags="$3" 1786 fi 1787 /sbin/mdmfs $flags -s $1 md $2 1788} 1789 1790# Code common to scripts that need to load a kernel module 1791# if it isn't in the kernel yet. Syntax: 1792# load_kld [-e regex] [-m module] file 1793# where -e or -m chooses the way to check if the module 1794# is already loaded: 1795# regex is egrep'd in the output from `kldstat -v', 1796# module is passed to `kldstat -m'. 1797# The default way is as though `-m file' were specified. 1798load_kld() 1799{ 1800 local _loaded _mod _opt _re 1801 1802 while getopts "e:m:" _opt; do 1803 case "$_opt" in 1804 e) _re="$OPTARG" ;; 1805 m) _mod="$OPTARG" ;; 1806 *) err 3 'USAGE: load_kld [-e regex] [-m module] file' ;; 1807 esac 1808 done 1809 shift $(($OPTIND - 1)) 1810 if [ $# -ne 1 ]; then 1811 err 3 'USAGE: load_kld [-e regex] [-m module] file' 1812 fi 1813 _mod=${_mod:-$1} 1814 _loaded=false 1815 if [ -n "$_re" ]; then 1816 if kldstat -v | egrep -q -e "$_re"; then 1817 _loaded=true 1818 fi 1819 else 1820 if kldstat -q -m "$_mod"; then 1821 _loaded=true 1822 fi 1823 fi 1824 if ! $_loaded; then 1825 if ! kldload "$1"; then 1826 warn "Unable to load kernel module $1" 1827 return 1 1828 else 1829 info "$1 kernel module loaded." 1830 fi 1831 else 1832 debug "load_kld: $1 kernel module already loaded." 1833 fi 1834 return 0 1835} 1836 1837# ltr str src dst [var] 1838# Change every $src in $str to $dst. 1839# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor 1840# awk(1). If var is non-NULL, set it to the result. 1841ltr() 1842{ 1843 local _str _src _dst _out _com _var 1844 _str="$1" 1845 _src="$2" 1846 _dst="$3" 1847 _var="$4" 1848 _out="" 1849 1850 local IFS="${_src}" 1851 for _com in ${_str}; do 1852 if [ -z "${_out}" ]; then 1853 _out="${_com}" 1854 else 1855 _out="${_out}${_dst}${_com}" 1856 fi 1857 done 1858 if [ -n "${_var}" ]; then 1859 setvar "${_var}" "${_out}" 1860 else 1861 echo "${_out}" 1862 fi 1863} 1864 1865# Creates a list of providers for GELI encryption. 1866geli_make_list() 1867{ 1868 local devices devices2 1869 local provider mountpoint type options rest 1870 1871 # Create list of GELI providers from fstab. 1872 while read provider mountpoint type options rest ; do 1873 case ":${options}" in 1874 :*noauto*) 1875 noauto=yes 1876 ;; 1877 *) 1878 noauto=no 1879 ;; 1880 esac 1881 1882 case ":${provider}" in 1883 :#*) 1884 continue 1885 ;; 1886 *.eli) 1887 # Skip swap devices. 1888 if [ "${type}" = "swap" -o "${options}" = "sw" -o "${noauto}" = "yes" ]; then 1889 continue 1890 fi 1891 devices="${devices} ${provider}" 1892 ;; 1893 esac 1894 done < /etc/fstab 1895 1896 # Append providers from geli_devices. 1897 devices="${devices} ${geli_devices}" 1898 1899 for provider in ${devices}; do 1900 provider=${provider%.eli} 1901 provider=${provider#/dev/} 1902 devices2="${devices2} ${provider}" 1903 done 1904 1905 echo ${devices2} 1906} 1907 1908# Find scripts in local_startup directories that use the old syntax 1909# 1910find_local_scripts_old () { 1911 zlist='' 1912 slist='' 1913 for dir in ${local_startup}; do 1914 if [ -d "${dir}" ]; then 1915 for file in ${dir}/[0-9]*.sh; do 1916 grep '^# PROVIDE:' $file >/dev/null 2>&1 && 1917 continue 1918 zlist="$zlist $file" 1919 done 1920 for file in ${dir}/[^0-9]*.sh; do 1921 grep '^# PROVIDE:' $file >/dev/null 2>&1 && 1922 continue 1923 slist="$slist $file" 1924 done 1925 fi 1926 done 1927} 1928 1929find_local_scripts_new () { 1930 local_rc='' 1931 for dir in ${local_startup}; do 1932 if [ -d "${dir}" ]; then 1933 for file in `grep -l '^# PROVIDE:' ${dir}/* 2>/dev/null`; do 1934 case "$file" in 1935 *.sample) ;; 1936 *) if [ -x "$file" ]; then 1937 local_rc="${local_rc} ${file}" 1938 fi 1939 ;; 1940 esac 1941 done 1942 fi 1943 done 1944} 1945 1946# check_required_{before|after} command 1947# Check for things required by the command before and after its precmd, 1948# respectively. The two separate functions are needed because some 1949# conditions should prevent precmd from being run while other things 1950# depend on precmd having already been run. 1951# 1952check_required_before() 1953{ 1954 local _f 1955 1956 case "$1" in 1957 start) 1958 for _f in $required_vars; do 1959 if ! checkyesno $_f; then 1960 warn "\$${_f} is not enabled." 1961 if [ -z "$rc_force" ]; then 1962 return 1 1963 fi 1964 fi 1965 done 1966 1967 for _f in $required_dirs; do 1968 if [ ! -d "${_f}/." ]; then 1969 warn "${_f} is not a directory." 1970 if [ -z "$rc_force" ]; then 1971 return 1 1972 fi 1973 fi 1974 done 1975 1976 for _f in $required_files; do 1977 if [ ! -r "${_f}" ]; then 1978 warn "${_f} is not readable." 1979 if [ -z "$rc_force" ]; then 1980 return 1 1981 fi 1982 fi 1983 done 1984 ;; 1985 esac 1986 1987 return 0 1988} 1989 1990check_required_after() 1991{ 1992 local _f _args 1993 1994 case "$1" in 1995 start) 1996 for _f in $required_modules; do 1997 case "${_f}" in 1998 *~*) _args="-e ${_f#*~} ${_f%%~*}" ;; 1999 *:*) _args="-m ${_f#*:} ${_f%%:*}" ;; 2000 *) _args="${_f}" ;; 2001 esac 2002 if ! load_kld ${_args}; then 2003 if [ -z "$rc_force" ]; then 2004 return 1 2005 fi 2006 fi 2007 done 2008 ;; 2009 esac 2010 2011 return 0 2012} 2013 2014# check_kern_features mib 2015# Return existence of kern.features.* sysctl MIB as true or 2016# false. The result will be cached in $_rc_cache_kern_features_ 2017# namespace. "0" means the kern.features.X exists. 2018 2019check_kern_features() 2020{ 2021 local _v 2022 2023 [ -n "$1" ] || return 1; 2024 eval _v=\$_rc_cache_kern_features_$1 2025 [ -n "$_v" ] && return "$_v"; 2026 2027 if ${SYSCTL_N} kern.features.$1 > /dev/null 2>&1; then 2028 eval _rc_cache_kern_features_$1=0 2029 return 0 2030 else 2031 eval _rc_cache_kern_features_$1=1 2032 return 1 2033 fi 2034} 2035 2036# check_namevarlist var 2037# Return "0" if ${name}_var is reserved in rc.subr. 2038 2039_rc_namevarlist="program chroot chdir flags fib nice user group groups" 2040check_namevarlist() 2041{ 2042 local _v 2043 2044 for _v in $_rc_namevarlist; do 2045 case $1 in 2046 $_v) return 0 ;; 2047 esac 2048 done 2049 2050 return 1 2051} 2052 2053# _echoonce var msg mode 2054# mode=0: Echo $msg if ${$var} is empty. 2055# After doing echo, a string is set to ${$var}. 2056# 2057# mode=1: Echo $msg if ${$var} is a string with non-zero length. 2058# 2059_echoonce() 2060{ 2061 local _var _msg _mode 2062 eval _var=\$$1 2063 _msg=$2 2064 _mode=$3 2065 2066 case $_mode in 2067 1) [ -n "$_var" ] && echo "$_msg" ;; 2068 *) [ -z "$_var" ] && echo -n "$_msg" && eval "$1=finished" ;; 2069 esac 2070} 2071 2072fi # [ -z "${_rc_subr_loaded}" ] 2073 2074_rc_subr_loaded=: 2075