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