xref: /dragonfly/etc/rc.subr (revision 63e03116)
1# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $
2# $FreeBSD: head/etc/rc.subr 275359 2014-12-01 12:17:42Z des $
3#
4# Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
5# All rights reserved.
6#
7# This code is derived from software contributed to The NetBSD Foundation
8# by Luke Mewburn.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions
12# are met:
13# 1. Redistributions of source code must retain the above copyright
14#    notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notice, this list of conditions and the following disclaimer in the
17#    documentation and/or other materials provided with the distribution.
18# 3. All advertising materials mentioning features or use of this software
19#    must display the following acknowledgement:
20#        This product includes software developed by the NetBSD
21#        Foundation, Inc. and its contributors.
22# 4. Neither the name of The NetBSD Foundation nor the names of its
23#    contributors may be used to endorse or promote products derived
24#    from this software without specific prior written permission.
25#
26# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36# POSSIBILITY OF SUCH DAMAGE.
37#
38# rc.subr
39#	functions used by various rc scripts
40#
41
42: ${RC_PID:=$$}; export RC_PID
43
44#
45#	Operating System dependent/independent variables
46#
47
48if [ -z "$_file" ]; then
49	_file="$0"
50fi
51provide_list=`rcorder -p $_file`
52
53if [ -n "${_rc_subr_loaded}" ]; then
54	return
55fi
56
57_rc_subr_loaded="YES"
58
59SYSCTL="/sbin/sysctl"
60SYSCTL_N="${SYSCTL} -n"
61SYSCTL_W="${SYSCTL}"
62CMD_OSTYPE="${SYSCTL_N} kern.ostype"
63OSTYPE=`${CMD_OSTYPE}`
64
65RC_RUNNING=0
66RC_FAILED=1
67RC_DISABLED=2
68RC_IRRELEVANT=3
69RC_CONFIGURED=4
70RC_STOPPED=5
71
72#
73#	functions
74#	---------
75
76# list_vars pattern
77#	List vars matching pattern.
78#
79list_vars()
80{
81	set | { while read LINE; do
82		var="${LINE%%=*}"
83		case "$var" in
84		"$LINE"|*[!a-zA-Z0-9_]*) continue ;;
85		$1) echo $var
86		esac
87	done; }
88}
89
90# set_rcvar base_var
91#	Set the variable name enabling a specific service.
92#	FreeBSD uses ${service}_enable, while NetBSD uses
93#	just the name of the service. For example:
94#	FreeBSD: sendmail_enable="YES"
95#	NetBSD : sendmail="YES"
96#	$1 - if $name is not the base to work of off, specify
97#	     a different one
98#
99set_rcvar()
100{
101	if [ -z "$1" ]; then
102		base_var=${name}
103	else
104		base_var="$1"
105	fi
106
107	echo ${base_var}
108}
109
110# set_provide_list
111#
112#	$1	should be $rc_arg (start, stop, restart, reload, etc)
113#	$2	return value $RC_*
114#
115#	Set the rcng_* variables associated with elements in provide_list
116#	based on $1 and $2.
117#
118#	Returns non-zero when early termination should occur, in which
119#	case the caller should return with a value of $? - 1
120#
121set_provide_list()
122{
123    # Remember, plret is set to the early termination return code + 1,
124    # or 0 if we want to continue the operation.
125    #
126    for i in $provide_list; do
127	case $1$2 in
128	start$RC_RUNNING|restart$RC_RUNNING)
129	    varsym -s rcng_$i=running
130	    ;;
131	start$RC_FAILED|restart$RC_FAILED)
132	    varsym -s rcng_$i=failed
133	    ;;
134	start$RC_DISABLED|restart$RC_DISABLED|reload$RC_DISABLED)
135	    varsym -s rcng_$i=disabled
136	    ;;
137	start$RC_IRRELEVANT|restart$RC_IRRELEVANT|reload$RC_IRRELEVANT)
138	    varsym -s rcng_$i=irrelevant
139	    ;;
140	start$RC_CONFIGURED|restart$RC_CONFIGURED)
141	    varsym -s rcng_$i=configured
142	    ;;
143	stop$RC_DISABLED)
144	    varsym -s rcng_$i=disabled
145	    ;;
146	stop$RC_IRRELEVANT)
147	    varsym -s rcng_$i=irrelevant
148	    ;;
149	stop*)
150	    varsym -s rcng_$i=stopped
151	    ;;
152	*)
153	    ;;
154	esac
155    done
156}
157
158# check_early_term
159#	$1	should be $rc_arg (start, stop, restart, reload, etc)
160#	$2	return value $RC_*
161#	$3	$rc_force	"" not to force, "anything" to force.
162#
163# The return code is 0 if early termination is not to occur, non-zero if
164# it is to occur.  When early termination is to occur the caller should
165# return check_early_term()'s return code - 1.    That is, early termination
166# can occur with or without an error.
167#
168# The provide list will be adjusted when early termination occurs.
169#
170check_early_term()
171{
172    case $2 in
173    $RC_RUNNING)
174	return 0
175	;;
176    $RC_FAILED)
177	set_provide_list $1 $2
178	[ -z "$3" ] || return 0
179	return 2
180	;;
181    $RC_DISABLED)
182	set_provide_list $1 $2
183	[ -z "$3" ] || return 0
184	return 1
185	;;
186    $RC_IRRELEVANT)
187	set_provide_list $1 $2
188	[ -z "$3" ] || return 0
189	return 1
190	;;
191    $RC_CONFIGURED)
192	return 0
193	;;
194    $RC_STOPPED)
195	return 0
196	;;
197    esac
198    set_provide_list $1 $2
199    [ -z "$3" ] || return 0
200    return 2
201}
202
203# adjust_return_code $1
204#
205#	Convert the return code to an exit code of 0 (success) or 1 (failure)
206#
207adjust_return_code()
208{
209    if [ $1 = $RC_FAILED ]; then
210	return 1
211    fi
212    return 0
213}
214
215#
216# force_depend script
217#	Force a service to start. Intended for use by services
218#	to resolve dependency issues. It is assumed the caller
219#	has check to make sure this call is necessary
220#	$1 - filename of script, in /etc/rc.d, to run
221#
222force_depend()
223{
224	_depend="$1"
225
226	info "${name} depends on ${_depend}, which will be forced to start."
227	if ! /etc/rc.d/${_depend} forcestart ; then
228		warn "Unable to force ${_depend}. It may already be running."
229		return 1
230	fi
231	return 0
232}
233
234#
235# checkyesno var
236#	Test $1 variable, and warn if not set to YES or NO.
237#	Return 0 if it's "yes" (et al), nonzero otherwise.
238#
239checkyesno()
240{
241	# try foo
242	eval _value=\$${1%_enable}
243	# try foo_enable
244	if [ -z $_value ]
245	then
246		eval _value=\$${1%_enable}_enable;
247	fi
248	debug "checkyesno: $1 is set to $_value."
249	case $_value in
250
251		#	"yes", "true", "on", or "1"
252	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
253		return 0
254		;;
255
256		#	"no", "false", "off", or "0"
257	[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
258		return 1
259		;;
260	*)
261		warn "\$${1} is not set properly - see rc.conf(5)."
262		return 1
263		;;
264	esac
265}
266
267#
268# reverse_list list
269#	print the list in reverse order
270#
271reverse_list()
272{
273	_revlist=
274	for _revfile in $*; do
275		_revlist="$_revfile $_revlist"
276	done
277	echo $_revlist
278}
279
280#
281# stop_boot always
282#	If booting directly to multiuser or $always is true,
283#	send SIGTERM to the parent (/etc/rc) to abort the boot.
284#	Otherwise just exit.
285#
286stop_boot()
287{
288	local always
289
290	case $1 in
291		#	"yes", "true", "on", or "1"
292        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
293		always=true
294		;;
295	*)
296		always=false
297		;;
298	esac
299	if [ "$autoboot" = yes -o "$always" = true ]; then
300		echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!"
301		kill -TERM ${RC_PID}
302	fi
303	exit 1
304}
305
306#
307# mount_critical_filesystems type
308#	Go through the list of critical filesystems as provided in
309#	the rc.conf(5) variable $critical_filesystems_${type}, checking
310#	each one to see if it is mounted, and if it is not, mounting it.
311#
312mount_critical_filesystems()
313{
314	eval _fslist=\$critical_filesystems_${1}
315	for _fs in $_fslist; do
316		mount | (
317			_ismounted=no
318			while read what _on on _type type; do
319				if [ $on = $_fs ]; then
320					_ismounted=yes
321				fi
322			done
323			if [ $_ismounted = no ]; then
324				mount $_fs >/dev/null 2>&1
325			fi
326		)
327	done
328}
329
330#
331# check_pidfile pidfile procname [interpreter]
332#	Parses the first line of pidfile for a PID, and ensures
333#	that the process is running and matches procname.
334#	Prints the matching PID upon success, nothing otherwise.
335#	interpreter is optional; see _find_processes() for details.
336#
337check_pidfile()
338{
339	_pidfile=$1
340	_procname=$2
341	_interpreter=$3
342	if [ -z "$_pidfile" -o -z "$_procname" ]; then
343		err 3 'USAGE: check_pidfile pidfile procname [interpreter]'
344	fi
345	if [ ! -f $_pidfile ]; then
346		debug "pid file {$_pidfile): not readable."
347		return
348	fi
349	read _pid _junk < $_pidfile
350	if [ -z "$_pid" ]; then
351		debug "pid file {$_pidfile): no pid in file."
352		return
353	fi
354	_find_processes $_procname ${_interpreter:-.} '-p '"$_pid"
355}
356
357#
358# check_process procname [interpreter]
359#	Ensures that a process (or processes) named procname is running.
360#	Prints a list of matching PIDs.
361#	interpreter is optional; see _find_processes() for details.
362#
363check_process()
364{
365	_procname=$1
366	_interpreter=$2
367	if [ -z "$_procname" ]; then
368		err 3 'USAGE: check_process procname [interpreter]'
369	fi
370	_find_processes $_procname ${_interpreter:-.} '-ax'
371}
372
373#
374# _find_processes procname interpreter psargs
375#	Search for procname in the output of ps generated by psargs.
376#	Prints the PIDs of any matching processes, space separated.
377#
378#	If interpreter == ".", check the following variations of procname
379#	against the first word of each command:
380#		procname
381#		`basename procname`
382#		`basename procname` + ":"
383#		"(" + `basename procname` + ")"
384#
385#	If interpreter != ".", read the first line of procname, remove the
386#	leading #!, normalise whitespace, append procname, and attempt to
387#	match that against each command, either as is, or with extra words
388#	at the end.
389#
390_find_processes()
391{
392	if [ $# -ne 3 ]; then
393		err 3 'USAGE: _find_processes procname interpreter psargs'
394	fi
395	_procname=$1
396	_interpreter=$2
397	_psargs=$3
398
399	_pref=
400	if [ $_interpreter != "." ]; then	# an interpreted script
401		read _interp < $_procname	# read interpreter name
402		_interp=${_interp#\#!}		# strip #!
403		set -- $_interp
404		if [ $_interpreter != $1 ]; then
405			warn "\$command_interpreter $_interpreter != $1"
406		fi
407		_interp="$* $_procname"		# cleanup spaces, add _procname
408		_interpbn="$1"			# the interpreter binary
409		_fp_args='_argv'
410		_fp_match='case "$_argv" in
411		    "${_interpbn##*/}: "$_procname*|${_interp}|"${_interp} "*)'
412	else					# a normal daemon
413		_procnamebn=${_procname##*/}
414		_fp_args='_arg0 _argv'
415		_fp_match='case "$_arg0" in
416		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
417	fi
418
419	_proccheck='
420		ps -o "pid,command" '"$_psargs"' |
421		while read _npid '"$_fp_args"'; do
422			case "$_npid" in
423			    PID)
424				continue ;;
425			esac ; '"$_fp_match"'
426				echo -n "$_pref$_npid" ;
427				_pref=" "
428				;;
429			esac
430		done'
431
432#	debug "in _find_processes: proccheck is ($_proccheck)."
433	eval $_proccheck
434}
435
436#
437# wait_for_pids pid [pid ...]
438#	spins until none of the pids exist
439#
440wait_for_pids()
441{
442	_list=$*
443	if [ -z "$_list" ]; then
444		return
445	fi
446	_prefix=
447	while true; do
448		_nlist="";
449		for _j in $_list; do
450			if kill -0 $_j 2>/dev/null; then
451				_nlist="${_nlist}${_nlist:+ }$_j"
452			fi
453		done
454		if [ -z "$_nlist" ]; then
455			break
456		fi
457		_list=$_nlist
458		echo -n ${_prefix:-"Waiting for PIDS: "}$_list
459		_prefix=", "
460		sleep 2
461	done
462	if [ -n "$_prefix" ]; then
463		echo "."
464	fi
465}
466
467#
468# get_pidfile_from_conf string file
469#
470#	Takes a string to search for in the specified file.
471#	Ignores lines with traditional comment characters.
472#
473# Example:
474#
475# if get_pidfile_from_conf string file; then
476#	pidfile="$_pidfile_from_conf"
477# else
478#	pidfile='appropriate default'
479# fi
480#
481get_pidfile_from_conf()
482{
483	if [ -z "$1" -o -z "$2" ]; then
484		err 3 "USAGE: get_pidfile_from_conf string file ($name)"
485	fi
486
487	local string file line
488
489	string="$1" ; file="$2"
490
491	if [ ! -s "$file" ]; then
492		err 3 "get_pidfile_from_conf: $file does not exist ($name)"
493	fi
494
495	while read line; do
496		case "$line" in
497		*[#\;]*${string}*)	continue ;;
498		*${string}*)		break ;;
499		esac
500	done < $file
501
502	if [ -n "$line" ]; then
503		line=${line#*/}
504		_pidfile_from_conf="/${line%%[\"\;]*}"
505	else
506		return 1
507	fi
508}
509
510#
511# check_startmsgs
512#	If rc_quiet is set (usually as a result of using faststart at
513#	boot time) check if rc_startmsgs is enabled.
514#
515check_startmsgs()
516{
517	if [ -n "$rc_quiet" ]; then
518		checkyesno rc_startmsgs
519	else
520		return 0
521	fi
522}
523
524#
525# run_rc_command argument
526#	Search for argument in the list of supported commands, which is:
527#		"start stop restart rcvar status poll ${extra_commands}"
528#	If there's a match, run ${argument}_cmd or the default method
529#	(see below).
530#
531#	If argument has a given prefix, then change the operation as follows:
532#		Prefix	Operation
533#		------	---------
534#		fast	Skip the pid check, and set rc_fast=yes, rc_quiet=yes
535#		force	Set ${rcvar} to YES, and set rc_force=yes
536#		one	Set ${rcvar} to YES
537#		quiet	Don't output some diagnostics, and set rc_quiet=yes
538#
539#	The following globals are used:
540#
541#	Name		Needed	Purpose
542#	----		------	-------
543#	provide_list	(gen)	list of keywords provided by current rcng file
544#
545#	name		y	Name of script.
546#
547#	command		n	Full path to command.
548#				Not needed if ${rc_arg}_cmd is set for
549#				each keyword.
550#
551#	command_args	n	Optional args/shell directives for command.
552#
553#	command_interpreter n	If not empty, command is interpreted, so
554#				call check_{pidfile,process}() appropriately.
555#
556#	extra_commands	n	List of extra commands supported.
557#
558#	pidfile		n	If set, use check_pidfile $pidfile $command,
559#				otherwise use check_process $command.
560#				In either case, only check if $command is set.
561#
562#	procname	n	Process name to check for instead of $command.
563#
564#	rcvar		n	This is checked with checkyesno to determine
565#				if the action should be run.
566#
567#	${name}_chroot	n	Directory to chroot to before running ${command}
568#				Requires /usr to be mounted.
569#
570#	${name}_chdir	n	Directory to cd to before running ${command}
571#				(if not using ${name}_chroot).
572#
573#	${name}_flags	n	Arguments to call ${command} with.
574#				NOTE:	$flags from the parent environment
575#					can be used to override this.
576#
577#	${name}_env	n	Environment variables to run ${command} with.
578#
579#	${name}_nice	n	Nice level to run ${command} at.
580#
581#	${name}_user	n	User to run ${command} as, using su(1) if not
582#				using ${name}_chroot.
583#				Requires /usr to be mounted.
584#
585#	${name}_group	n	Group to run chrooted ${command} as.
586#				Requires /usr to be mounted.
587#
588#	${name}_groups	n	Comma separated list of supplementary groups
589#				to run the chrooted ${command} with.
590#				Requires /usr to be mounted.
591#
592#	${name}_prepend	n	Command added before ${command}.
593#
594#	${rc_arg}_cmd	n	If set, use this as the method when invoked;
595#				Otherwise, use default command (see below)
596#
597#	${rc_arg}_precmd n	If set, run just before performing the
598#				${rc_arg}_cmd method in the default
599#				operation (i.e, after checking for required
600#				bits and process (non)existence).
601#				If this completes with a non-zero exit code,
602#				don't run ${rc_arg}_cmd.
603#
604#	${rc_arg}_postcmd n	If set, run just after performing the
605#				${rc_arg}_cmd method, if that method
606#				returned a zero exit code.
607#
608#	required_dirs	n	If set, check for the existence of the given
609#				directories before running the default
610#				(re)start command.
611#
612#	required_files	n	If set, check for the readability of the given
613#				files before running the default (re)start
614#				command.
615#
616#	required_modules n	If set, ensure the given kernel modules are
617#				loaded before running a (re)start command.
618#				The check and possible loads are actually
619#				done after start_precmd so that the modules
620#				aren't loaded in vain, should the precmd
621#				return a non-zero status to indicate an error.
622#				If a word in the list looks like "foo:bar",
623#				"foo" is the KLD file name and "bar" is the
624#				module name.  If a word looks like "foo~bar",
625#				"foo" is the KLD file name and "bar" is a
626#				egrep(1) pattern matching the module name.
627#				Otherwise the module name is assumed to be
628#				the same as the KLD file name, which is most
629#				common.  See load_kld().
630#
631#	required_vars	n	If set, perform checkyesno on each of the
632#				listed variables before running the default
633#				(re)start command.
634#
635#	Default behaviour for a given argument, if no override method is
636#	provided:
637#
638#	Argument	Default behaviour
639#	--------	-----------------
640#	start		if !running && checkyesno ${rcvar}
641#				${command}
642#
643#	stop		if ${pidfile}
644#				rc_pid=$(check_pidfile $pidfile $command)
645#			else
646#				rc_pid=$(check_process $command)
647#			kill $sig_stop $rc_pid
648#			wait_for_pids $rc_pid
649#			($sig_stop defaults to TERM.)
650#
651#	reload		Similar to stop, except use $sig_reload instead,
652#			and doesn't wait_for_pids.
653#			$sig_reload defaults to HUP.
654#
655#	restart		Run `stop' then `start'.
656#
657#	status		Show if ${command} is running, etc.
658#
659#	poll		Wait for ${command} to exit.
660#
661#	rcvar		Display what rc.conf variable is used (if any).
662#
663#	Variables available to methods, and after run_rc_command() has
664#	completed:
665#
666#	Variable	Purpose
667#	--------	-------
668#	rc_arg		Argument to command, after fast/force/one processing
669#			performed
670#
671#	rc_flags	Flags to start the default command with.
672#			Defaults to ${name}_flags, unless overridden
673#			by $flags from the environment.
674#			This variable may be changed by the precmd method.
675#
676#	rc_pid		PID of command (if appropriate)
677#
678#	rc_fast		Not empty if "fast" was provided (q.v.)
679#
680#	rc_force	Not empty if "force" was provided (q.v.)
681#
682#	rc_quiet	Not empty if "quiet" was provided
683#
684#
685dummy_rc_command()
686{
687	rc_arg=$1
688
689	case "$rc_arg" in
690	fast*)				# "fast" prefix; don't check pid
691		rc_arg=${rc_arg#fast}
692		;;
693	force*)				# "force" prefix; always start
694		rc_arg=${rc_arg#force}
695		;;
696	one*)				# "one" prefix; set ${rcvar}=yes
697		rc_arg=${rc_arg#one}
698		;;
699	esac
700	set_provide_list $rc_arg $RC_CONFIGURED
701	return 0
702}
703
704run_rc_command()
705{
706	_return=0
707	rc_arg=$1
708	if [ -z "$name" ]; then
709		err 3 'run_rc_command: $name is not set.'
710	fi
711
712	# Don't repeat the first argument when passing additional command-
713	# line arguments to the command subroutines.
714	#
715	shift 1
716	rc_extra_args="$*"
717
718	case "$rc_arg" in
719	fast*)				# "fast" prefix; don't check pid
720		rc_arg=${rc_arg#fast}
721		rc_fast=yes
722		rc_quiet=yes
723		;;
724	force*)				# "force" prefix; always start
725		rc_arg=${rc_arg#force}
726		rc_force=yes
727		if [ -n "${rcvar}" ]; then
728			eval ${rcvar}=YES
729		fi
730		;;
731	one*)				# "one" prefix; set ${rcvar}=yes
732		rc_arg=${rc_arg#one}
733		if [ -n "${rcvar}" ]; then
734			eval ${rcvar}=YES
735		fi
736		;;
737	quiet*)				# "quiet" prefix; omit some messages
738		_rc_prefix=quiet
739		rc_arg=${rc_arg#${_rc_prefix}}
740		rc_quiet=yes
741		;;
742	esac
743
744	eval _override_command=\$${name}_program
745	if [ -n "$_override_command" ]; then
746		command=$_override_command
747	fi
748
749	_keywords="start stop restart rcvar $extra_commands"
750	rc_pid=
751	_pidcmd=
752	_procname=${procname:-${command}}
753
754					# setup pid check command if not fast
755	if [ -z "$rc_fast" -a -n "$_procname" ]; then
756		if [ -n "$pidfile" ]; then
757			_pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
758		else
759			_pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
760		fi
761		if [ -n "$_pidcmd" ]; then
762			_keywords="${_keywords} status poll"
763		fi
764	fi
765
766	if [ -z "$rc_arg" ]; then
767		rc_usage "$_keywords"
768	fi
769
770	if [ -n "$flags" ]; then	# allow override from environment
771		rc_flags=$flags
772	else
773		eval rc_flags=\$${name}_flags
774	fi
775	eval _chdir=\$${name}_chdir	_chroot=\$${name}_chroot \
776	    _nice=\$${name}_nice	_user=\$${name}_user \
777	    _group=\$${name}_group	_groups=\$${name}_groups \
778	    _env=\$${name}_env 		_prepend=\$${name}_prepend
779
780	if [ -n "$_user" ]; then	# unset $_user if running as that user
781		if [ "$_user" = "$(id -un)" ]; then
782			unset _user
783		fi
784	fi
785
786					# if ${rcvar} is set, and $1 is not
787					# "rcvar", then run
788					#	checkyesno ${rcvar}
789					# and return if that failed
790					#
791	if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
792		if ! checkyesno ${rcvar}; then
793			set_provide_list $rc_arg $RC_DISABLED
794			return 0
795		fi
796	fi
797
798	eval $_pidcmd			# determine the pid if necessary
799
800	for _elem in $_keywords; do
801		if [ "$_elem" != "$rc_arg" ]; then
802			continue
803		fi
804
805					# if there's a custom ${XXX_cmd},
806					# run that instead of the default
807					#
808		eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
809		    _postcmd=\$${rc_arg}_postcmd
810		if [ -n "$_cmd" ]; then
811					# if the precmd failed and force
812					# isn't set, exit
813					#
814			if [ -n "$_precmd" ]; then
815				debug "run_rc_command: evaluating ${_precmd}()."
816				eval $_precmd $rc_extra_args
817
818				_return=$?
819				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
820			fi
821
822			if [ -n "$_cmd" ]; then
823				debug "run_rc_command: evaluating ${_cmd}()."
824				eval $_cmd $rc_extra_args
825				_return=$?
826				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
827			fi
828
829			if [ -n "$_postcmd" ]; then
830				debug "run_rc_command: evaluating ${_postcmd}()."
831				eval $_postcmd $rc_extra_args
832				_return=$?
833				check_early_term $rc_arg $_return "" || return $(($?-1))
834			fi
835			set_provide_list $rc_arg $_return
836			adjust_return_code $_return
837			return $?
838		fi
839
840		case "$rc_arg" in	# default operations...
841
842		status)
843			if [ -n "$rc_pid" ]; then
844				echo "${name} is running as pid $rc_pid."
845			else
846				echo "${name} is not running."
847				return 1
848			fi
849			;;
850
851		start)
852			if [ -n "$rc_pid" ]; then
853				if [ -z "$rc_quiet" ]; then
854					echo "${name} already running? (pid=$rc_pid)."
855				fi
856				exit 1
857			fi
858
859			if [ ! -x $command ]; then
860				info "run_rc_command: cannot run ($command)."
861				set_provide_list $rc_arg $RC_FAILED
862				adjust_return_code $RC_FAILED
863				return $?
864			fi
865
866					# check for required variables,
867					# directories, and files
868					#
869			for _f in $required_vars; do
870				if ! checkyesno $_f; then
871					warn "\$${_f} is not set."
872					if [ -z "$rc_force" ]; then
873						set_provide_list $rc_arg $RC_FAILED
874						adjust_return_code $RC_FAILED
875						return $?
876					fi
877				fi
878			done
879			for _f in $required_dirs; do
880				if [ ! -d "${_f}/." ]; then
881					warn "${_f} is not a directory."
882					if [ -z "$rc_force" ]; then
883						set_provide_list $rc_arg $RC_FAILED
884						adjust_return_code $RC_FAILED
885						return $?
886					fi
887				fi
888			done
889			for _f in $required_files; do
890				if [ ! -r "${_f}" ]; then
891					warn "${_f} is not readable."
892					if [ -z "$rc_force" ]; then
893						set_provide_list $rc_arg $RC_FAILED
894						adjust_return_code $RC_FAILED
895						return $?
896					fi
897				fi
898			done
899			for _f in $required_modules; do
900				case "${_f}" in
901				*~*)	_args="-e ${_f#*~} ${_f%%~*}" ;;
902				*:*)	_args="-m ${_f#*:} ${_f%%:*}" ;;
903				*)	_args="${_f}" ;;
904				esac
905				if ! load_kld ${_args}; then
906					if [ -z "$rc_force" ]; then
907						set_provide_list $rc_arg $RC_FAILED
908						adjust_return_code $RC_FAILED
909						return $?
910					fi
911				fi
912			done
913
914					# if the precmd failed and force
915					# isn't set, exit
916					#
917			if [ -n "${_precmd}" ]; then
918				debug "run_rc_command: evaluating ${_precmd}()."
919				eval $_precmd
920				_return=$?
921				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
922			fi
923
924					# setup the command to run, and run it
925					#
926			echo "Starting ${name}."
927			if [ -n "$_chroot" ]; then
928				_doit="\
929${_nice:+nice -n $_nice }\
930${_env:+env $_env }\
931chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
932$_chroot $command $rc_flags $command_args"
933			else
934				_doit="\
935${_chdir:+cd $_chdir; }\
936${_nice:+nice -n $_nice }\
937${_env:+env $_env }\
938$command $rc_flags $command_args"
939				if [ -n "$_user" ]; then
940				    _doit="su -m $_user -c 'sh -c \"$_doit\"'"
941				fi
942				if [ -n "$_prepend" ]; then
943					_doit="$_prepend $_doit"
944				fi
945			fi
946
947					# if the cmd failed and force
948					# isn't set, exit
949					#
950			debug "run_rc_command: _doit: $_doit"
951			eval $_doit
952			_return=$?
953			check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
954					# finally, run postcmd
955					#
956			if [ -n "${_postcmd}" ]; then
957				debug "run_rc_command: evaluating ${_postcmd}()."
958				eval $_postcmd
959			fi
960			;;
961
962		stop)
963			if [ -z "$rc_pid" ]; then
964				if [ -n "$pidfile" ]; then
965					echo \
966				    "${name} not running? (check $pidfile)."
967				else
968					echo "${name} not running?"
969				fi
970				set_provide_list $rc_arg $RC_STOPPED
971				exit 1
972			fi
973
974					# if the precmd failed and force
975					# isn't set, exit
976					#
977			if [ -n "$_precmd" ]; then
978				eval $_precmd
979				_return=$?
980				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
981			fi
982
983					# send the signal to stop
984					#
985			echo "Stopping ${name}."
986			_doit="kill -${sig_stop:-TERM} $rc_pid"
987			if [ -n "$_user" ]; then
988				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
989			fi
990
991					# if the stop cmd failed and force
992					# isn't set, exit
993					#
994			eval $_doit
995			_return=$?
996			check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
997					# wait for the command to exit,
998					# and run postcmd.
999			sleep 0.1
1000			wait_for_pids $rc_pid
1001			if [ -n "$_postcmd" ]; then
1002				eval $_postcmd
1003				_return=$?
1004			fi
1005			;;
1006
1007		reload)
1008			if [ -z "$rc_pid" ]; then
1009				if [ -n "$pidfile" ]; then
1010					echo \
1011				    "${name} not running? (check $pidfile)."
1012				else
1013					echo "${name} not running?"
1014				fi
1015				set_provide_list $rc_arg $RC_FAILED
1016				exit 1
1017			fi
1018			echo "Reloading ${name} config files."
1019			if [ -n "$_precmd" ]; then
1020				eval $_precmd
1021				_return=$?
1022				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
1023			fi
1024			_doit="kill -${sig_reload:-HUP} $rc_pid"
1025			if [ -n "$_user" ]; then
1026				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
1027			fi
1028			eval $_doit
1029			_return=$?
1030			check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
1031			if [ -n "$_postcmd" ]; then
1032				eval $_postcmd
1033				_return=$?
1034			fi
1035			;;
1036
1037		restart)
1038			if [ -n "$_precmd" ]; then
1039				eval $_precmd $rc_extra_args
1040				_return=$?
1041				check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
1042			fi
1043					# prevent restart being called more
1044					# than once by any given script
1045					#
1046			if [ -n "$_rc_restart_done" ]; then
1047				return 0
1048			fi
1049			_rc_restart_done=YES
1050
1051			( $0 ${rc_force:+force}stop $rc_extra_args )
1052			$0 ${rc_force:+force}start $rc_extra_args
1053			_return=$?
1054
1055			if [ -n "$_postcmd" ]; then
1056				eval $_postcmd $rc_extra_args
1057				adjust_return_code $?
1058				_return=$?
1059			fi
1060			# Do not set_provide_list(), the start command above
1061			# will have done it for us and we do not know the
1062			# actual RC code to base a setting on here.
1063			#
1064			return $_return
1065			;;
1066
1067		poll)
1068			if [ -n "$rc_pid" ]; then
1069				wait_for_pids $rc_pid
1070			fi
1071			;;
1072
1073		rcvar)
1074			echo "# $name"
1075			if [ -n "$rcvar" ]; then
1076				if checkyesno ${rcvar}; then
1077					echo "\$${rcvar}=YES"
1078				else
1079					echo "\$${rcvar}=NO"
1080				fi
1081			fi
1082			;;
1083
1084		*)
1085			rc_usage "$_keywords"
1086			;;
1087
1088		esac
1089		set_provide_list $rc_arg $_return
1090		adjust_return_code $_return
1091		return $?
1092	done
1093
1094	echo 1>&2 "$0: unknown directive '$rc_arg'."
1095	rc_usage "$_keywords"
1096	exit 1
1097}
1098
1099#
1100# Helper functions for run_rc_command: common code.
1101# They use such global variables besides the exported rc_* ones:
1102#
1103#	name	       R/W
1104#	------------------
1105#	_precmd		R
1106#	_postcmd	R
1107#	_return		W
1108#
1109_run_rc_precmd()
1110{
1111	check_required_before "$rc_arg" || return 1
1112
1113	if [ -n "$_precmd" ]; then
1114		debug "run_rc_command: ${rc_arg}_precmd: $_precmd $rc_extra_args"
1115		eval "$_precmd $rc_extra_args"
1116		_return=$?
1117
1118		# If precmd failed and force isn't set, request exit.
1119		if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then
1120			return 1
1121		fi
1122	fi
1123
1124	check_required_after "$rc_arg" || return 1
1125
1126	return 0
1127}
1128
1129_run_rc_postcmd()
1130{
1131	if [ -n "$_postcmd" ]; then
1132		debug "run_rc_command: ${rc_arg}_postcmd: $_postcmd $rc_extra_args"
1133		eval "$_postcmd $rc_extra_args"
1134		_return=$?
1135	fi
1136	return 0
1137}
1138
1139_run_rc_doit()
1140{
1141	debug "run_rc_command: doit: $*"
1142	eval "$@"
1143	_return=$?
1144
1145	# If command failed and force isn't set, request exit.
1146	if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then
1147		return 1
1148	fi
1149
1150	return 0
1151}
1152
1153_run_rc_notrunning()
1154{
1155	local _pidmsg
1156
1157	if [ -n "$pidfile" ]; then
1158		_pidmsg=" (check $pidfile)."
1159	else
1160		_pidmsg=
1161	fi
1162	echo 1>&2 "${name} not running?${_pidmsg}"
1163}
1164
1165_run_rc_killcmd()
1166{
1167	local _cmd
1168
1169	_cmd="kill -$1 $rc_pid"
1170	if [ -n "$_user" ]; then
1171		_cmd="su -m ${_user} -c 'sh -c \"${_cmd}\"'"
1172	fi
1173	echo "$_cmd"
1174}
1175
1176#
1177# run_rc_script file arg
1178#	Start the script `file' with `arg', and correctly handle the
1179#	return value from the script.  If `file' ends with `.sh', it's
1180#	sourced into the current environment.  If `file' appears to be
1181#	a backup or scratch file, ignore it.  Otherwise if it's
1182#	executable run as a child process.
1183#
1184run_rc_script()
1185{
1186	_file=$1
1187	_arg=$2
1188	if [ -z "$_file" -o -z "$_arg" ]; then
1189		err 3 'USAGE: run_rc_script file arg'
1190	fi
1191
1192	trap "echo 'Reboot interrupted'; exit 1" 3
1193
1194	unset	name command command_args command_interpreter \
1195		extra_commands pidfile procname \
1196		rcvar required_dirs required_files required_vars
1197	eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
1198
1199	case "$_file" in
1200	*.sh)				# run in current shell
1201		set $_arg ; . $_file
1202		;;
1203	*[~#]|*.OLD|*.orig)		# scratch file; skip
1204		warn "Ignoring scratch file $_file"
1205		;;
1206	*)				# run in subshell
1207		if [ -x $_file ]; then
1208			if [ -n "$rc_fast_and_loose" ]; then
1209				set $_arg ; . $_file
1210			else
1211				( trap "echo 'Reboot interrupted'; exit 1" 3
1212				  set $_arg ; . $_file )
1213			fi
1214		fi
1215		;;
1216	esac
1217}
1218
1219# Code common to scripts that need to load a kernel module
1220# if it isn't in the kernel yet. Syntax:
1221#   load_kld [-e regex] [-m module] file
1222# where -e or -m chooses the way to check if the module
1223# is already loaded:
1224#   regex is egrep'd in the output from `kldstat -v',
1225#   module is passed to `kldstat -m'.
1226# The default way is as though `-m file' were specified.
1227load_kld()
1228{
1229	local _loaded _mod _opt _re
1230
1231	while getopts "e:m:" _opt; do
1232		case "$_opt" in
1233		e) _re="$OPTARG" ;;
1234		m) _mod="$OPTARG" ;;
1235		*) err 3 'USAGE: load_kld [-e regex] [-m module] file' ;;
1236		esac
1237	done
1238	shift $(($OPTIND - 1))
1239	if [ $# -ne 1 ]; then
1240		err 3 'USAGE: load_kld [-e regex] [-m module] file'
1241	fi
1242	_mod=${_mod:-$1}
1243	_loaded=false
1244	if [ -n "$_re" ]; then
1245		if kldstat -v | egrep -q -e "$_re"; then
1246			_loaded=true
1247		fi
1248	else
1249		if kldstat -q -m "$_mod"; then
1250			_loaded=true
1251		fi
1252	fi
1253	if ! $_loaded; then
1254		if ! kldload "$1"; then
1255			warn "Unable to load kernel module $1"
1256			return 1
1257		else
1258			info "$1 kernel module loaded."
1259		fi
1260	else
1261		debug "load_kld: $1 kernel module already loaded."
1262	fi
1263	return 0
1264}
1265
1266
1267# ltr str src dst
1268#	Change every $src in $str to $dst.
1269#	Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor
1270#	awk(1).
1271ltr()
1272{
1273	local _str _src _dst _out _com
1274	_str=$1
1275	_src=$2
1276	_dst=$3
1277	_out=""
1278
1279	IFS=${_src}
1280	for _com in ${_str}; do
1281		if [ -z "${_out}" ]; then
1282			_out="${_com}"
1283		else
1284			_out="${_out}${_dst}${_com}"
1285		fi
1286	done
1287	echo "${_out}"
1288}
1289
1290#
1291# load_rc_config
1292#	Source in the configuration file for a given command.
1293#
1294load_rc_config()
1295{
1296	_command=$1
1297	if [ -z "$_command" ]; then
1298		err 3 'USAGE: load_rc_config command'
1299	fi
1300
1301	if [ -z "$_rc_conf_loaded" ]; then
1302		if [ -r /etc/defaults/rc.conf ]; then
1303			debug "Sourcing /etc/defaults/rc.conf"
1304			. /etc/defaults/rc.conf
1305			source_rc_confs
1306		elif [ -r /etc/rc.conf ]; then
1307			debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)."
1308			. /etc/rc.conf
1309		fi
1310		_rc_conf_loaded=YES
1311	fi
1312	if [ -f /etc/rc.conf.d/"$_command" ]; then
1313		debug "Sourcing /etc/rc.conf.d/${_command}"
1314		. /etc/rc.conf.d/"$_command"
1315	fi
1316
1317	# XXX - Deprecated variable name support
1318	#
1319	[ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable"
1320	[ -n "$portmap_program" ] && rpcbind_program="$portmap_program"
1321	[ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags"
1322	[ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable"
1323
1324}
1325
1326#
1327# rc_usage commands
1328#	Print a usage string for $0, with `commands' being a list of
1329#	valid commands.
1330#
1331rc_usage()
1332{
1333	echo -n 1>&2 "Usage: $0 [fast|force|one|quiet]("
1334
1335	_sep=
1336	for _elem in $*; do
1337		echo -n 1>&2 "$_sep$_elem"
1338		_sep="|"
1339	done
1340	echo 1>&2 ")"
1341	exit 1
1342}
1343
1344#
1345# err exitval message
1346#	Display message to stderr and log to the syslog, and exit with exitval.
1347#
1348err()
1349{
1350	exitval=$1
1351	shift
1352
1353	if [ -x /usr/bin/logger ]; then
1354		logger "$0: ERROR: $*"
1355	fi
1356	echo 1>&2 "$0: ERROR: $*"
1357	exit $exitval
1358}
1359
1360#
1361# warn message
1362#	Display message to stderr and log to the syslog.
1363#
1364warn()
1365{
1366	if [ -x /usr/bin/logger ]; then
1367		logger "$0: WARNING: $*"
1368	fi
1369	echo 1>&2 "$0: WARNING: $*"
1370}
1371
1372#
1373# info message
1374#	Display informational message to stdout and log to syslog.
1375#
1376info()
1377{
1378	case ${rc_info} in
1379	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1380		if [ -x /usr/bin/logger ]; then
1381			logger "$0: INFO: $*"
1382		fi
1383		echo "$0: INFO: $*"
1384		;;
1385	esac
1386}
1387
1388#
1389# debug message
1390#	If debugging is enabled in rc.conf output message to stderr.
1391#	BEWARE that you don't call any subroutine that itself calls this
1392#	function.
1393#
1394debug()
1395{
1396	case ${rc_debug} in
1397	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1398		if [ -x /usr/bin/logger ]; then
1399			logger "$0: INFO: $*"
1400		fi
1401        	echo 1>&2 "$0: DEBUG: $*"
1402		;;
1403	esac
1404}
1405
1406#
1407# backup_file action file cur backup
1408#	Make a backup copy of `file' into `cur', and save the previous
1409#	version of `cur' as `backup' or use rcs for archiving.
1410#
1411#	This routine checks the value of the backup_uses_rcs variable,
1412#	which can be either YES or NO.
1413#
1414#	The `action' keyword can be one of the following:
1415#
1416#	add		`file' is now being backed up (and is possibly
1417#			being reentered into the backups system).  `cur'
1418#			is created and RCS files, if necessary, are
1419#			created as well.
1420#
1421#	update		`file' has changed and needs to be backed up.
1422#			If `cur' exists, it is copied to to `back' or
1423#			checked into RCS (if the repository file is old),
1424#			and then `file' is copied to `cur'.  Another RCS
1425#			check in done here if RCS is being used.
1426#
1427#	remove		`file' is no longer being tracked by the backups
1428#			system.  If RCS is not being used, `cur' is moved
1429#			to `back', otherwise an empty file is checked in,
1430#			and then `cur' is removed.
1431#
1432#
1433backup_file()
1434{
1435	_action=$1
1436	_cpfile=$2
1437	_cur=$3
1438	_back=$4
1439
1440	if checkyesno backup_uses_rcs; then
1441		_msg0="backup archive"
1442		_msg1="update"
1443
1444		# ensure that history file is not locked
1445		if [ -f $_cur,v ]; then
1446			rcs -q -u -U -M $_cur
1447		fi
1448
1449		# ensure after switching to rcs that the
1450		# current backup is not lost
1451		if [ -f $_cur ]; then
1452			# no archive, or current newer than archive
1453			if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
1454				ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1455				rcs -q -kb -U $_cur
1456				co -q -f -u $_cur
1457			fi
1458		fi
1459
1460		case $_action in
1461		add|update)
1462			cp -p $_cpfile $_cur
1463			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1464			rcs -q -kb -U $_cur
1465			co -q -f -u $_cur
1466			chown root:wheel $_cur $_cur,v
1467			;;
1468		remove)
1469			cp /dev/null $_cur
1470			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1471			rcs -q -kb -U $_cur
1472			chown root:wheel $_cur $_cur,v
1473			rm $_cur
1474			;;
1475		esac
1476	else
1477		case $_action in
1478		add|update)
1479			if [ -f $_cur ]; then
1480				cp -p $_cur $_back
1481			fi
1482			cp -p $_cpfile $_cur
1483			chown root:wheel $_cur
1484			;;
1485		remove)
1486			mv -f $_cur $_back
1487			;;
1488		esac
1489	fi
1490}
1491
1492# devfs_mount_jail dir
1493# Mounts a devfs file system appropriate for jails
1494# on the directory dir.
1495# This function returns non-zero if an error occurs.
1496#
1497devfs_mount_jail()
1498{
1499	local jdev _me
1500	jdev="$1"
1501	_me="devfs_mount_jail"
1502
1503	if ! devfs_domount "$jdev" $rs; then
1504		warn "$_me: devfs was not mounted on $jdev"
1505		return 1
1506	fi
1507	return 0
1508}
1509
1510# devfs_domount dir
1511# Mount devfs on dir.
1512# Returns 0 on success.
1513#
1514devfs_domount()
1515{
1516	local devdir _me
1517	devdir="$1"
1518	_me="devfs_domount()"
1519
1520	if [ -z "$devdir" ]; then
1521		warn "$_me: you must specify a mount-point"
1522		return 1
1523	fi
1524
1525	debug "$_me: mount-point is ($devdir)"
1526	if ! mount -t devfs devfs "$devdir"; then
1527		warn "$_me: Unable to mount devfs on $devdir"
1528		return 1
1529	fi
1530
1531return 0
1532}
1533
1534# Find scripts in local_startup directories.
1535find_local_scripts() {
1536	local_rc=''
1537	for dir in ${local_startup}; do
1538		if [ -d "${dir}" ]; then
1539			for file in `grep -l '^# PROVIDE:' ${dir}/* 2>/dev/null`; do
1540				case "$file" in
1541				*.sample) ;;
1542				*)	if [ -x "$file" ]; then
1543						local_rc="${local_rc} ${file}"
1544					fi
1545					;;
1546				esac
1547			done
1548		fi
1549	done
1550}
1551