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