xref: /netbsd-src/etc/rc.subr (revision f42f89fd6fc4d08451450f9b7ffa731678160f1c)
1*f42f89fdSandvar# $NetBSD: rc.subr,v 1.111 2022/05/22 11:27:33 andvar Exp $
26096ea59Slukem#
375350585Sapb# Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
46096ea59Slukem# All rights reserved.
56096ea59Slukem#
66096ea59Slukem# This code is derived from software contributed to The NetBSD Foundation
76096ea59Slukem# by Luke Mewburn.
86096ea59Slukem#
96096ea59Slukem# Redistribution and use in source and binary forms, with or without
106096ea59Slukem# modification, are permitted provided that the following conditions
116096ea59Slukem# are met:
126096ea59Slukem# 1. Redistributions of source code must retain the above copyright
136096ea59Slukem#    notice, this list of conditions and the following disclaimer.
146096ea59Slukem# 2. Redistributions in binary form must reproduce the above copyright
156096ea59Slukem#    notice, this list of conditions and the following disclaimer in the
166096ea59Slukem#    documentation and/or other materials provided with the distribution.
176096ea59Slukem#
186096ea59Slukem# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
196096ea59Slukem# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
206096ea59Slukem# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
216096ea59Slukem# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
226096ea59Slukem# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
236096ea59Slukem# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
246096ea59Slukem# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
256096ea59Slukem# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
266096ea59Slukem# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
276096ea59Slukem# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
286096ea59Slukem# POSSIBILITY OF SUCH DAMAGE.
296096ea59Slukem#
306096ea59Slukem# rc.subr
31c3b0e18dScjs#	functions used by various rc scripts
326096ea59Slukem#
33c3b0e18dScjs
343c8a1444Sjmmv: ${rcvar_manpage:='rc.conf(5)'}
3531edfc6fSapb: ${RC_PID:=$$} ; export RC_PID
3689fd5357Sapbnl='
3789fd5357Sapb' # a literal newline
383c8a1444Sjmmv
39bda2cfe4Schristos# RC variables to clear on start.
40bda2cfe4Schristos_env_clear_rc_vars="
41bda2cfe4SchristosRC_PID=
42bda2cfe4Schristos_rc_pid=
43bda2cfe4Schristos_rc_original_stdout_fd=
44bda2cfe4Schristos_rc_original_stderr_fd=
45bda2cfe4Schristos_rc_postprocessor_fd=
463dd07195Schristos_rc_kill_ntries=
47bda2cfe4Schristos"
48bda2cfe4Schristos
490a50b87eSchristosexport PATH=/sbin:/bin:/usr/sbin:/usr/bin
5077eeaedfSlukem#
516096ea59Slukem#	functions
526096ea59Slukem#	---------
536096ea59Slukem
5477eeaedfSlukem#
556096ea59Slukem# checkyesno var
5656e4b525Sroy#	Test $1 variable.
5756e4b525Sroy#	Return 0 if it's "yes" (et al), 1 if it's "no" (et al), 2 otherwise.
586096ea59Slukem#
5956e4b525Sroycheckyesnox()
606096ea59Slukem{
616096ea59Slukem	eval _value=\$${1}
626096ea59Slukem	case $_value in
6379201de0Slukem
6479201de0Slukem		#	"yes", "true", "on", or "1"
6579201de0Slukem	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
6679201de0Slukem		return 0
676b18196fSlukem		;;
6879201de0Slukem
6979201de0Slukem		#	"no", "false", "off", or "0"
7079201de0Slukem	[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
7179201de0Slukem		return 1
726b18196fSlukem		;;
736b18196fSlukem	*)
7456e4b525Sroy		return 2
756b18196fSlukem		;;
766b18196fSlukem	esac
77c3b0e18dScjs}
7885726955Smellon
793c81b28aSlukem#
8056e4b525Sroy# checkyesno var
8156e4b525Sroy#	Test $1 variable, and warn if not set to YES or NO.
8256e4b525Sroy#	Return 0 if it's "yes" (et al), nonzero otherwise.
8356e4b525Sroy#
8456e4b525Sroycheckyesno()
8556e4b525Sroy{
8656e4b525Sroy	local var
8756e4b525Sroy
8856e4b525Sroy	checkyesnox $1
8956e4b525Sroy	var=$?
90e063fa5fSkre	case "${var}" in
91e063fa5fSkre	( 0 | 1 )	return $var;;
92e063fa5fSkre	esac
9356e4b525Sroy	warn "\$${1} is not set properly - see ${rcvar_manpage}."
9456e4b525Sroy	return 1
9556e4b525Sroy}
9656e4b525Sroy
9756e4b525Sroy#
9889fd5357Sapb# yesno_to_truefalse var
9989fd5357Sapb#	Convert the value of a variable from any of the values
10089fd5357Sapb#	understood by checkyesno() to "true" or "false".
10189fd5357Sapb#
10289fd5357Sapbyesno_to_truefalse()
10389fd5357Sapb{
10489fd5357Sapb	local var=$1
10589fd5357Sapb	if checkyesno $var; then
10689fd5357Sapb		eval $var=true
10789fd5357Sapb		return 0
10889fd5357Sapb	else
10989fd5357Sapb		eval $var=false
11089fd5357Sapb		return 1
11189fd5357Sapb	fi
11289fd5357Sapb}
11389fd5357Sapb
11489fd5357Sapb#
11550b7dbcbSlukem# reverse_list list
11650b7dbcbSlukem#	print the list in reverse order
11750b7dbcbSlukem#
11850b7dbcbSlukemreverse_list()
11950b7dbcbSlukem{
12050b7dbcbSlukem	_revlist=
121b224530cSchristos	for _revfile; do
12250b7dbcbSlukem		_revlist="$_revfile $_revlist"
12350b7dbcbSlukem	done
12450b7dbcbSlukem	echo $_revlist
12550b7dbcbSlukem}
12650b7dbcbSlukem
12785726955Smellon#
12831edfc6fSapb# If booting directly to multiuser, send SIGTERM to
12931edfc6fSapb# the parent (/etc/rc) to abort the boot.
13031edfc6fSapb# Otherwise just exit.
13131edfc6fSapb#
13231edfc6fSapbstop_boot()
13331edfc6fSapb{
13431edfc6fSapb	if [ "$autoboot" = yes ]; then
13531edfc6fSapb		echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!"
13631edfc6fSapb		kill -TERM ${RC_PID}
13731edfc6fSapb	fi
13831edfc6fSapb	exit 1
13931edfc6fSapb}
14031edfc6fSapb
14131edfc6fSapb#
1425ee7ac88Slukem# mount_critical_filesystems type
1435ee7ac88Slukem#	Go through the list of critical file systems as provided in
1445ee7ac88Slukem#	the rc.conf(5) variable $critical_filesystems_${type}, checking
1455ee7ac88Slukem#	each one to see if it is mounted, and if it is not, mounting it.
14670472a48Sapb#	It's not an error if file systems prefixed with "OPTIONAL:"
14770472a48Sapb#	are not mentioned in /etc/fstab.
14885726955Smellon#
1496096ea59Slukemmount_critical_filesystems()
1506096ea59Slukem{
1515ee7ac88Slukem	eval _fslist=\$critical_filesystems_${1}
15270472a48Sapb	_mountcrit_es=0
153c8ddd612Slukem	for _fs in $_fslist; do
15470472a48Sapb		_optional=false
15570472a48Sapb		case "$_fs" in
15670472a48Sapb		OPTIONAL:*)
15770472a48Sapb			_optional=true
15870472a48Sapb			_fs="${_fs#*:}"
15970472a48Sapb			;;
16070472a48Sapb		esac
16115388316Slukem		_ismounted=false
16270472a48Sapb		# look for a line like "${fs} on * type *"
16370472a48Sapb		# or "* on ${fs} type *" in the output from mount.
16470472a48Sapb		case "${nl}$( mount )${nl}" in
16570472a48Sapb		*" on ${_fs} type "*)
16615388316Slukem			_ismounted=true
16770472a48Sapb			;;
16870472a48Sapb		*"${nl}${_fs} on "*)
16970472a48Sapb			_ismounted=true
17070472a48Sapb			;;
17170472a48Sapb		esac
17215388316Slukem		if $_ismounted; then
17370472a48Sapb			print_rc_metadata \
17470472a48Sapb			"note:File system ${_fs} was already mounted"
175ef98b9ddSlukem		else
17670472a48Sapb			_mount_output=$( mount $_fs 2>&1 )
17770472a48Sapb			_mount_es=$?
17870472a48Sapb			case "$_mount_output" in
17970472a48Sapb			*"${nl}"*)
18070472a48Sapb				# multiple lines can't be good,
18170472a48Sapb				# not even if $_optional is true
18270472a48Sapb				;;
183f932526aSapb			*[uU]'nknown special file or file system'*)
18470472a48Sapb				if $_optional; then
18570472a48Sapb					# ignore this error
18670472a48Sapb					print_rc_metadata \
18770472a48Sapb			"note:Optional file system ${_fs} is not present"
18870472a48Sapb					_mount_es=0
18970472a48Sapb					_mount_output=""
19085726955Smellon				fi
19170472a48Sapb				;;
19270472a48Sapb			esac
19370472a48Sapb			if [ -n "$_mount_output" ]; then
19470472a48Sapb				printf >&2 "%s\n" "$_mount_output"
19570472a48Sapb			fi
19670472a48Sapb			if [ "$_mount_es" != 0 ]; then
19770472a48Sapb				_mountcrit_es="$_mount_es"
19870472a48Sapb			fi
19970472a48Sapb		fi
20085726955Smellon	done
20170472a48Sapb	return $_mountcrit_es
20285726955Smellon}
203668efbbcScjs
2046096ea59Slukem#
205ae342f47Salnsn# mount_critical_filesystems_zfs
206ae342f47Salnsn#	Go through the list of critical ZFS mountpoints as provided in
207ae342f47Salnsn#	the rc.conf(5) variable $critical_filesystems_zfs, checking
208ae342f47Salnsn#	each one to see if it is mounted, and if it is not, mounting it.
209ae342f47Salnsn#	It's not an error if file systems prefixed with "OPTIONAL:"
210082b9a1eSalnsn#	aren't ZFS mountpoints.
211ae342f47Salnsnmount_critical_filesystems_zfs()
212ae342f47Salnsn{
213082b9a1eSalnsn	_fslist=$critical_filesystems_zfs
214ae342f47Salnsn	_tab="	"
215ae342f47Salnsn	_mountcrit_es=0
216ae342f47Salnsn	for _fs in $_fslist; do
217ae342f47Salnsn		_optional=false
218ae342f47Salnsn		case "$_fs" in
219ae342f47Salnsn		OPTIONAL:*)
220ae342f47Salnsn			_optional=true
221ae342f47Salnsn			_fs="${_fs#*:}"
222ae342f47Salnsn			;;
223ae342f47Salnsn		esac
224ae342f47Salnsn
225082b9a1eSalnsn		_dataset=$(
226ae342f47Salnsn			zfs list -H -o mountpoint,name |
227ae342f47Salnsn			while read _line ; do
228ae342f47Salnsn				_dataset=''
229ae342f47Salnsn				case "$_line" in
230ae342f47Salnsn				"${_fs}${_tab}"*)
231ae342f47Salnsn					_dataset="${_line#*${_tab}}"
232ae342f47Salnsn					;;
233ae342f47Salnsn				esac
234ae342f47Salnsn				if [ -n "$_dataset" ]; then
235ae342f47Salnsn					case "$( zfs get -H -o value canmount $_dataset )" in
236ae342f47Salnsn					on)
237ae342f47Salnsn						echo -n "$_dataset"
238ae342f47Salnsn						break ;;
239ae342f47Salnsn					*) # noauto|off - dataset isn't supposed to be mounted
240ae342f47Salnsn						;;
241ae342f47Salnsn					esac
242ae342f47Salnsn				fi
243082b9a1eSalnsn			done)
244ae342f47Salnsn
245ae342f47Salnsn		if [ -z "$_dataset" ]; then
246ae342f47Salnsn			if $_optional; then
247ae342f47Salnsn				# ignore this error
248ae342f47Salnsn				print_rc_metadata \
249ae342f47Salnsn				"note:Optional file system $_fs is not present"
250ae342f47Salnsn			else
251ae342f47Salnsn				printf >&2 "%s\n" "No suitable ZFS dataset found for mountpoint $_fs"
252ae342f47Salnsn				_mountcrit_es=1
253ae342f47Salnsn			fi
254ae342f47Salnsn		else
255ae342f47Salnsn			_mount_es=
256ae342f47Salnsn			case "$( zfs get -H -o value mounted $_dataset )" in
257ae342f47Salnsn			yes)
258ae342f47Salnsn				_mount_es=1
259ae342f47Salnsn				print_rc_metadata \
260ae342f47Salnsn				"note:File system $_fs was already mounted"
261ae342f47Salnsn				;;
262082b9a1eSalnsn			*) # no
263ae342f47Salnsn				zfs mount "$_dataset" >/dev/null
264ae342f47Salnsn				_mount_es=$?
265082b9a1eSalnsn				;;
266082b9a1eSalnsn			esac
267ae342f47Salnsn
268082b9a1eSalnsn			if [ $_mount_es -ne 0 ]; then
269ae342f47Salnsn				_mountcrit_es="$_mount_es"
270ae342f47Salnsn			fi
271ae342f47Salnsn		fi
272ae342f47Salnsn	done
273ae342f47Salnsn	return $_mountcrit_es
274ae342f47Salnsn}
275ae342f47Salnsn
276ae342f47Salnsn#
277d40d6757Slukem# check_pidfile pidfile procname [interpreter]
278d40d6757Slukem#	Parses the first line of pidfile for a PID, and ensures
2796096ea59Slukem#	that the process is running and matches procname.
280d40d6757Slukem#	Prints the matching PID upon success, nothing otherwise.
281d40d6757Slukem#	interpreter is optional; see _find_processes() for details.
2826096ea59Slukem#
2836096ea59Slukemcheck_pidfile()
2846096ea59Slukem{
2856096ea59Slukem	_pidfile=$1
2866096ea59Slukem	_procname=$2
287d40d6757Slukem	_interpreter=$3
288e063fa5fSkre	if [ -z "$_pidfile" ] || [ -z "$_procname" ]; then
289d40d6757Slukem		err 3 'USAGE: check_pidfile pidfile procname [interpreter]'
290668efbbcScjs	fi
2916096ea59Slukem	if [ ! -f $_pidfile ]; then
2926096ea59Slukem		return
2936096ea59Slukem	fi
2946096ea59Slukem	read _pid _junk < $_pidfile
2956096ea59Slukem	if [ -z "$_pid" ]; then
2966096ea59Slukem		return
2976096ea59Slukem	fi
298d40d6757Slukem	_find_processes $_procname ${_interpreter:-.} '-p '"$_pid"
2996096ea59Slukem}
3006096ea59Slukem
3016096ea59Slukem#
302d40d6757Slukem# check_process procname [interpreter]
3036096ea59Slukem#	Ensures that a process (or processes) named procname is running.
304d40d6757Slukem#	Prints a list of matching PIDs.
305d40d6757Slukem#	interpreter is optional; see _find_processes() for details.
3066096ea59Slukem#
3076096ea59Slukemcheck_process()
3086096ea59Slukem{
3096096ea59Slukem	_procname=$1
310d40d6757Slukem	_interpreter=$2
3116096ea59Slukem	if [ -z "$_procname" ]; then
312d40d6757Slukem		err 3 'USAGE: check_process procname [interpreter]'
3136096ea59Slukem	fi
3147d5ae540Skre	_find_processes $_procname ${_interpreter:-.} '-A'
315d40d6757Slukem}
316d40d6757Slukem
317d40d6757Slukem#
318d40d6757Slukem# _find_processes procname interpreter psargs
319d40d6757Slukem#	Search for procname in the output of ps generated by psargs.
320d40d6757Slukem#	Prints the PIDs of any matching processes, space separated.
321d40d6757Slukem#
322d40d6757Slukem#	If interpreter == ".", check the following variations of procname
323d40d6757Slukem#	against the first word of each command:
324d40d6757Slukem#		procname
325d40d6757Slukem#		`basename procname`
326d40d6757Slukem#		`basename procname` + ":"
327d40d6757Slukem#		"(" + `basename procname` + ")"
328d40d6757Slukem#
329d40d6757Slukem#	If interpreter != ".", read the first line of procname, remove the
330d40d6757Slukem#	leading #!, normalise whitespace, append procname, and attempt to
331d40d6757Slukem#	match that against each command, either as is, or with extra words
332dbdaee06Sdholland#	at the end.  As an alternative, to deal with interpreted daemons
3335e1904ecShe#	using perl, the basename of the interpreter plus a colon is also
3345e1904ecShe#	tried as the prefix to procname.
335d40d6757Slukem#
336d40d6757Slukem_find_processes()
337d40d6757Slukem{
338d40d6757Slukem	if [ $# -ne 3 ]; then
339d40d6757Slukem		err 3 'USAGE: _find_processes procname interpreter psargs'
340d40d6757Slukem	fi
341d40d6757Slukem	_procname=$1
342d40d6757Slukem	_interpreter=$2
343d40d6757Slukem	_psargs=$3
344d40d6757Slukem
3456096ea59Slukem	_pref=
34678b99d68Shubertf	_procnamebn=${_procname##*/}
347d40d6757Slukem	if [ $_interpreter != "." ]; then	# an interpreted script
348fa3f94a4Selad		read _interp < ${_chroot:-}/$_procname	# read interpreter name
349d40d6757Slukem		_interp=${_interp#\#!}		# strip #!
350d40d6757Slukem		set -- $_interp
3513a128b33Schristos		if [ $1 = "/usr/bin/env" ]; then
3523a128b33Schristos			shift
3533a128b33Schristos			set -- $(type $1)
3543a128b33Schristos			shift $(($# - 1))
3553a128b33Schristos			_interp="${1##*/} $_procname"
3563a128b33Schristos		else
3573a128b33Schristos			_interp="$* $_procname"
3583a128b33Schristos		fi
359d40d6757Slukem		if [ $_interpreter != $1 ]; then
360d40d6757Slukem			warn "\$command_interpreter $_interpreter != $1"
361d40d6757Slukem		fi
3625e1904ecShe		_interpbn=${1##*/}
363d40d6757Slukem		_fp_args='_argv'
364d40d6757Slukem		_fp_match='case "$_argv" in
36578b99d68Shubertf		    ${_interp}|"${_interp} "*|"${_interpbn}: "*${_procnamebn}*)'
366d40d6757Slukem	else					# a normal daemon
367d40d6757Slukem		_fp_args='_arg0 _argv'
368d40d6757Slukem		_fp_match='case "$_arg0" in
369d40d6757Slukem		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
370d40d6757Slukem	fi
371d40d6757Slukem
372d40d6757Slukem	_proccheck='
3737e6759edSchristos		ps -o "pid,args" '"$_psargs"' 2>&1 |
374d40d6757Slukem		while read _npid '"$_fp_args"'; do
375c47a8060Slukem			case "$_npid" in
3767e6759edSchristos			ps:|PID)
377c47a8060Slukem				continue ;;
378d40d6757Slukem			esac ; '"$_fp_match"'
379d40d6757Slukem				echo -n "$_pref$_npid" ;
3806096ea59Slukem				_pref=" "
381c47a8060Slukem				;;
382c47a8060Slukem			esac
383d40d6757Slukem		done'
384d40d6757Slukem
385d40d6757Slukem#echo 1>&2 "proccheck is :$_proccheck:"
386d40d6757Slukem	eval $_proccheck
3876096ea59Slukem}
3886096ea59Slukem
3896096ea59Slukem#
3903dd07195Schristos# kill_pids signal pid [pid ...]
3913dd07195Schristos#	kills the given pids with signal.
3923dd07195Schristos#	returns the list of pids killed successfully.
3933dd07195Schristos#
3943dd07195Schristoskill_pids()
3953dd07195Schristos{
3963dd07195Schristos	local signal=$1
3973dd07195Schristos	shift
3985af20f98Sotis	local list="$*"
3993dd07195Schristos	local j=
4003dd07195Schristos	local nlist=
4013dd07195Schristos	for j in $list; do
4023dd07195Schristos		if kill -$signal $j 2>/dev/null; then
4033dd07195Schristos			nlist="${nlist}${nlist:+ }$j"
4043dd07195Schristos		fi
4053dd07195Schristos	done
4063dd07195Schristos	echo $nlist
4073dd07195Schristos}
4083dd07195Schristos
4093dd07195Schristos#
4108490f0b0Slukem# wait_for_pids pid [pid ...]
4114c9bb3bcSlukem#	spins until none of the pids exist
4123dd07195Schristos#	if _rc_kill_ntries is set and exceeded, it SIGKILLS the remaining
4133dd07195Schristos#	pids
4148490f0b0Slukem#
4158490f0b0Slukemwait_for_pids()
4168490f0b0Slukem{
4173dd07195Schristos	local ntries=0
4183dd07195Schristos	local prefix=
4195af20f98Sotis	local nlist=
4205af20f98Sotis	local list="$*"
4213dd07195Schristos
4223dd07195Schristos	if [ -z "$list" ]; then
4238490f0b0Slukem		return
4248490f0b0Slukem	fi
4253dd07195Schristos
4264c9bb3bcSlukem	while true; do
4275af20f98Sotis		nlist=$(kill_pids 0 $list)
4283dd07195Schristos		if [ -z "$nlist" ]; then
4298490f0b0Slukem			break
4308490f0b0Slukem		fi
4313dd07195Schristos		if [ "$list" != "$nlist" ]; then
4323dd07195Schristos			list=$nlist
4333dd07195Schristos			echo -n ${prefix:-"Waiting for PIDS: "}$list
4343dd07195Schristos			prefix=", "
435ccc4fd50Sroy		fi
436ccc4fd50Sroy		# We want this to be a tight loop for a fast exit
437ccc4fd50Sroy		sleep 0.05
4383dd07195Schristos		ntries=$((ntries + 1))
4393dd07195Schristos		if [ -n "${_rc_kill_ntries}" ]; then
4403dd07195Schristos			if [ ${ntries} -gt ${_rc_kill_ntries} ]; then
4413dd07195Schristos				kill_pids 9 $list > /dev/null
4423dd07195Schristos			fi
4433dd07195Schristos		fi
4448490f0b0Slukem	done
4453dd07195Schristos	if [ -n "$prefix" ]; then
4468490f0b0Slukem		echo "."
4474c9bb3bcSlukem	fi
4488490f0b0Slukem}
4498490f0b0Slukem
4508490f0b0Slukem#
451bff64ddcSjmmv# run_rc_command argument [parameters]
4521a286b14Slukem#	Search for argument in the list of supported commands, which is:
4538490f0b0Slukem#		"start stop restart rcvar status poll ${extra_commands}"
4541a286b14Slukem#	If there's a match, run ${argument}_cmd or the default method
455bff64ddcSjmmv#	(see below), and pass the optional list of parameters to it.
4566096ea59Slukem#
4571a286b14Slukem#	If argument has a given prefix, then change the operation as follows:
4581a286b14Slukem#		Prefix	Operation
4596096ea59Slukem#		------	---------
460892c0453Slukem#		fast	Skip the pid check, and set rc_fast=yes
461892c0453Slukem#		force	Set ${rcvar} to YES, and set rc_force=yes
462f3bab2a8Slukem#		one	Set ${rcvar} to YES
4636096ea59Slukem#
4646096ea59Slukem#	The following globals are used:
465bd11504cSlukem#
4661a286b14Slukem#	Name		Needed	Purpose
4671a286b14Slukem#	----		------	-------
4686096ea59Slukem#	name		y	Name of script.
469bd11504cSlukem#
4706096ea59Slukem#	command		n	Full path to command.
4711a286b14Slukem#				Not needed if ${rc_arg}_cmd is set for
4726096ea59Slukem#				each keyword.
473bd11504cSlukem#
4746096ea59Slukem#	command_args	n	Optional args/shell directives for command.
475bd11504cSlukem#
476d40d6757Slukem#	command_interpreter n	If not empty, command is interpreted, so
477d40d6757Slukem#				call check_{pidfile,process}() appropriately.
478d40d6757Slukem#
4790c2e1a2bSlukem#	extra_commands	n	List of extra commands supported.
480bd11504cSlukem#
48180ce7c6cSlukem#	pidfile		n	If set, use check_pidfile $pidfile $command,
48280ce7c6cSlukem#				otherwise use check_process $command.
48380ce7c6cSlukem#				In either case, only check if $command is set.
48480ce7c6cSlukem#
48580ce7c6cSlukem#	procname	n	Process name to check for instead of $command.
486bd11504cSlukem#
487bd11504cSlukem#	rcvar		n	This is checked with checkyesno to determine
488bd11504cSlukem#				if the action should be run.
489bd11504cSlukem#
4900847f3e3Slukem#	${name}_chroot	n	Directory to chroot to before running ${command}
49180ce7c6cSlukem#				Requires /usr to be mounted.
492bd11504cSlukem#
4930847f3e3Slukem#	${name}_chdir	n	Directory to cd to before running ${command}
4940847f3e3Slukem#				(if not using ${name}_chroot).
495bd11504cSlukem#
4966096ea59Slukem#	${name}_flags	n	Arguments to call ${command} with.
497bd11504cSlukem#				NOTE:	$flags from the parent environment
498bd11504cSlukem#					can be used to override this.
499bd11504cSlukem#
5004ff90c62She#	${name}_env	n	Additional environment variable settings
5014ff90c62She#				for running ${command}
5024ff90c62She#
503a96d29c7Slukem#	${name}_nice	n	Nice level to run ${command} at.
504bd11504cSlukem#
5050847f3e3Slukem#	${name}_user	n	User to run ${command} as, using su(1) if not
5060847f3e3Slukem#				using ${name}_chroot.
50780ce7c6cSlukem#				Requires /usr to be mounted.
508bd11504cSlukem#
5090847f3e3Slukem#	${name}_group	n	Group to run chrooted ${command} as.
51080ce7c6cSlukem#				Requires /usr to be mounted.
511bd11504cSlukem#
512f6a33791Slukem#	${name}_groups	n	Comma separated list of supplementary groups
513f6a33791Slukem#				to run the chrooted ${command} with.
51480ce7c6cSlukem#				Requires /usr to be mounted.
515bd11504cSlukem#
5161a286b14Slukem#	${rc_arg}_cmd	n	If set, use this as the method when invoked;
5176096ea59Slukem#				Otherwise, use default command (see below)
518bd11504cSlukem#
5191a286b14Slukem#	${rc_arg}_precmd n	If set, run just before performing the
5201a286b14Slukem#				${rc_arg}_cmd method in the default
5211a286b14Slukem#				operation (i.e, after checking for required
5221a286b14Slukem#				bits and process (non)existence).
5236096ea59Slukem#				If this completes with a non-zero exit code,
5241a286b14Slukem#				don't run ${rc_arg}_cmd.
525bd11504cSlukem#
5261a286b14Slukem#	${rc_arg}_postcmd n	If set, run just after performing the
5271a286b14Slukem#				${rc_arg}_cmd method, if that method
5289cfa003dSlukem#				returned a zero exit code.
5299cfa003dSlukem#
5306096ea59Slukem#	required_dirs	n	If set, check for the existence of the given
5316096ea59Slukem#				directories before running the default
5326096ea59Slukem#				(re)start command.
533bd11504cSlukem#
5346096ea59Slukem#	required_files	n	If set, check for the readability of the given
5356096ea59Slukem#				files before running the default (re)start
5366096ea59Slukem#				command.
537bd11504cSlukem#
5386096ea59Slukem#	required_vars	n	If set, perform checkyesno on each of the
5396096ea59Slukem#				listed variables before running the default
5406096ea59Slukem#				(re)start command.
5416096ea59Slukem#
5421a286b14Slukem#	Default behaviour for a given argument, if no override method is
5431a286b14Slukem#	provided:
544bd11504cSlukem#
5451a286b14Slukem#	Argument	Default behaviour
5461a286b14Slukem#	--------	-----------------
5476096ea59Slukem#	start		if !running && checkyesno ${rcvar}
5486096ea59Slukem#				${command}
549bd11504cSlukem#
5506096ea59Slukem#	stop		if ${pidfile}
5511a286b14Slukem#				rc_pid=$(check_pidfile $pidfile $command)
5526096ea59Slukem#			else
5531a286b14Slukem#				rc_pid=$(check_process $command)
5541a286b14Slukem#			kill $sig_stop $rc_pid
5551a286b14Slukem#			wait_for_pids $rc_pid
5564c9bb3bcSlukem#			($sig_stop defaults to TERM.)
557bd11504cSlukem#
5584c9bb3bcSlukem#	reload		Similar to stop, except use $sig_reload instead,
5594c9bb3bcSlukem#			and doesn't wait_for_pids.
5606096ea59Slukem#			$sig_reload defaults to HUP.
561bd11504cSlukem#
5626096ea59Slukem#	restart		Run `stop' then `start'.
5636096ea59Slukem#
5648490f0b0Slukem#	status		Show if ${command} is running, etc.
5658490f0b0Slukem#
5668490f0b0Slukem#	poll		Wait for ${command} to exit.
5678490f0b0Slukem#
5688490f0b0Slukem#	rcvar		Display what rc.conf variable is used (if any).
5698490f0b0Slukem#
5701a286b14Slukem#	Variables available to methods, and after run_rc_command() has
5711a286b14Slukem#	completed:
5721a286b14Slukem#
5731a286b14Slukem#	Variable	Purpose
5741a286b14Slukem#	--------	-------
575f3bab2a8Slukem#	rc_arg		Argument to command, after fast/force/one processing
5761a286b14Slukem#			performed
5771a286b14Slukem#
5781a286b14Slukem#	rc_flags	Flags to start the default command with.
5791a286b14Slukem#			Defaults to ${name}_flags, unless overridden
5801a286b14Slukem#			by $flags from the environment.
5811a286b14Slukem#			This variable may be changed by the precmd method.
5821a286b14Slukem#
5831a286b14Slukem#	rc_pid		PID of command (if appropriate)
5841a286b14Slukem#
5851a286b14Slukem#	rc_fast		Not empty if "fast" was provided (q.v.)
5861a286b14Slukem#
5871a286b14Slukem#	rc_force	Not empty if "force" was provided (q.v.)
5888490f0b0Slukem#
589bd11504cSlukem#
5906096ea59Slukemrun_rc_command()
5916096ea59Slukem{
5921a286b14Slukem	rc_arg=$1
593bd11504cSlukem	if [ -z "$name" ]; then
594c47a8060Slukem		err 3 'run_rc_command: $name is not set.'
5956096ea59Slukem	fi
5966096ea59Slukem
597f3bab2a8Slukem	_rc_prefix=
5981a286b14Slukem	case "$rc_arg" in
599bd11504cSlukem	fast*)				# "fast" prefix; don't check pid
6001a286b14Slukem		rc_arg=${rc_arg#fast}
601892c0453Slukem		rc_fast=yes
6026096ea59Slukem		;;
603f3bab2a8Slukem	force*)				# "force" prefix; always run
604892c0453Slukem		rc_force=yes
605f3bab2a8Slukem		_rc_prefix=force
606f3bab2a8Slukem		rc_arg=${rc_arg#${_rc_prefix}}
607f3bab2a8Slukem		if [ -n "${rcvar}" ]; then
608f3bab2a8Slukem			eval ${rcvar}=YES
609f3bab2a8Slukem		fi
610f3bab2a8Slukem		;;
611f3bab2a8Slukem	one*)				# "one" prefix; set ${rcvar}=yes
612f3bab2a8Slukem		_rc_prefix=one
613f3bab2a8Slukem		rc_arg=${rc_arg#${_rc_prefix}}
614be9b3eeaSlukem		if [ -n "${rcvar}" ]; then
615bd11504cSlukem			eval ${rcvar}=YES
616be9b3eeaSlukem		fi
6176096ea59Slukem		;;
618668efbbcScjs	esac
6196096ea59Slukem
6209a803287Sreed	_keywords="start stop restart rcvar"
6219a803287Sreed	if [ -n "$extra_commands" ]; then
6229a803287Sreed		_keywords="${_keywords} ${extra_commands}"
6239a803287Sreed	fi
6241a286b14Slukem	rc_pid=
6256096ea59Slukem	_pidcmd=
62680ce7c6cSlukem	_procname=${procname:-${command}}
62780ce7c6cSlukem
628bd11504cSlukem					# setup pid check command if not fast
629e063fa5fSkre	if [ -z "$rc_fast" ] && [ -n "$_procname" ]; then
6306096ea59Slukem		if [ -n "$pidfile" ]; then
6311a286b14Slukem			_pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
63280ce7c6cSlukem		else
6331a286b14Slukem			_pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
634668efbbcScjs		fi
6356096ea59Slukem		if [ -n "$_pidcmd" ]; then
6368490f0b0Slukem			_keywords="${_keywords} status poll"
6376096ea59Slukem		fi
6386096ea59Slukem	fi
6396096ea59Slukem
6401a286b14Slukem	if [ -z "$rc_arg" ]; then
6416096ea59Slukem		rc_usage "$_keywords"
6426096ea59Slukem	fi
643bff64ddcSjmmv	shift	# remove $rc_arg from the positional parameters
6446096ea59Slukem
645c8ddd612Slukem	if [ -n "$flags" ]; then	# allow override from environment
6461a286b14Slukem		rc_flags=$flags
6476096ea59Slukem	else
6481a286b14Slukem		eval rc_flags=\$${name}_flags
6496096ea59Slukem	fi
650c47a8060Slukem	eval _chdir=\$${name}_chdir	_chroot=\$${name}_chroot \
651c47a8060Slukem	    _nice=\$${name}_nice	_user=\$${name}_user \
6524ff90c62She	    _group=\$${name}_group	_groups=\$${name}_groups \
6534ff90c62She	    _env=\"\$${name}_env\"
6546096ea59Slukem
65580ce7c6cSlukem	if [ -n "$_user" ]; then	# unset $_user if running as that user
65680ce7c6cSlukem		if [ "$_user" = "$(id -un)" ]; then
65780ce7c6cSlukem			unset _user
65880ce7c6cSlukem		fi
65980ce7c6cSlukem	fi
66080ce7c6cSlukem
661be9b3eeaSlukem					# if ${rcvar} is set, and $1 is not
66204784cf3Slukem					# "rcvar", then run
663be9b3eeaSlukem					#	checkyesno ${rcvar}
66474bbb8efSsalo					# and return if that failed or warn
66574bbb8efSsalo					# user and exit when interactive
666bd11504cSlukem					#
667e063fa5fSkre	if [ -n "${rcvar}" ] && [ "$rc_arg" != "rcvar" ]; then
668bd11504cSlukem		if ! checkyesno ${rcvar}; then
66974bbb8efSsalo					# check whether interactive or not
67074bbb8efSsalo			if [ -n "$_run_rc_script" ]; then
671bd11504cSlukem				return 0
672bd11504cSlukem			fi
67374bbb8efSsalo			for _elem in $_keywords; do
67474bbb8efSsalo				if [ "$_elem" = "$rc_arg" ]; then
67575350585Sapb					cat 1>&2 <<EOF
67675350585Sapb\$${rcvar} is not enabled - see ${rcvar_manpage}.
67775350585SapbUse the following if you wish to perform the operation:
67875350585Sapb  $0 one${rc_arg}
67975350585SapbEOF
68074bbb8efSsalo					exit 1
68174bbb8efSsalo				fi
68274bbb8efSsalo			done
68374bbb8efSsalo			echo 1>&2 "$0: unknown directive '$rc_arg'."
68474bbb8efSsalo			rc_usage "$_keywords"
68574bbb8efSsalo		fi
686bd11504cSlukem	fi
687bd11504cSlukem
688bd11504cSlukem	eval $_pidcmd			# determine the pid if necessary
6896096ea59Slukem
6906096ea59Slukem	for _elem in $_keywords; do
6911a286b14Slukem		if [ "$_elem" != "$rc_arg" ]; then
6926096ea59Slukem			continue
6936096ea59Slukem		fi
6946096ea59Slukem
695bd11504cSlukem					# if there's a custom ${XXX_cmd},
696bd11504cSlukem					# run that instead of the default
697bd11504cSlukem					#
6981a286b14Slukem		eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
6991a286b14Slukem		    _postcmd=\$${rc_arg}_postcmd
7006096ea59Slukem		if [ -n "$_cmd" ]; then
701bd11504cSlukem					# if the precmd failed and force
702bd11504cSlukem					# isn't set, exit
703bd11504cSlukem					#
7041a286b14Slukem			if ! eval $_precmd && [ -z "$rc_force" ]; then
705bd11504cSlukem				return 1
706bd11504cSlukem			fi
707bd11504cSlukem
708bff64ddcSjmmv			if ! eval $_cmd \"\${@}\" && [ -z "$rc_force" ]; then
7099bcc0986Slukem				return 1
7109bcc0986Slukem			fi
7119bcc0986Slukem			eval $_postcmd
7126096ea59Slukem			return 0
7136096ea59Slukem		fi
7146096ea59Slukem
715bff64ddcSjmmv		if [ ${#} -gt 0 ]; then
716bff64ddcSjmmv			err 1 "the $rc_arg command does not take any parameters"
717bff64ddcSjmmv		fi
718bff64ddcSjmmv
7191a286b14Slukem		case "$rc_arg" in	# default operations...
7206096ea59Slukem
7216096ea59Slukem		status)
7221a286b14Slukem			if [ -n "$rc_pid" ]; then
7231a286b14Slukem				echo "${name} is running as pid $rc_pid."
7246096ea59Slukem			else
7256096ea59Slukem				echo "${name} is not running."
726fa16fd6fSlukem				return 1
7276096ea59Slukem			fi
7286096ea59Slukem			;;
7296096ea59Slukem
7306096ea59Slukem		start)
7311a286b14Slukem			if [ -n "$rc_pid" ]; then
7329bd9220cSlukem				echo 1>&2 "${name} already running? (pid=$rc_pid)."
7336096ea59Slukem				exit 1
7346096ea59Slukem			fi
7356096ea59Slukem
736e85d25dbSlukem			if [ ! -x ${_chroot}${command} ]; then
7376096ea59Slukem				return 0
7386096ea59Slukem			fi
7396096ea59Slukem
740bd11504cSlukem					# check for required variables,
741bd11504cSlukem					# directories, and files
742bd11504cSlukem					#
7436096ea59Slukem			for _f in $required_vars; do
7446096ea59Slukem				if ! checkyesno $_f; then
7453c81b28aSlukem					warn "\$${_f} is not enabled."
7461a286b14Slukem					if [ -z "$rc_force" ]; then
7476096ea59Slukem						return 1
7486096ea59Slukem					fi
749bd11504cSlukem				fi
7506096ea59Slukem			done
7516096ea59Slukem			for _f in $required_dirs; do
7526096ea59Slukem				if [ ! -d "${_f}/." ]; then
75360d3ee1bSlukem					warn "${_f} is not a directory."
7541a286b14Slukem					if [ -z "$rc_force" ]; then
7556096ea59Slukem						return 1
7566096ea59Slukem					fi
757bd11504cSlukem				fi
7586096ea59Slukem			done
7596096ea59Slukem			for _f in $required_files; do
7606096ea59Slukem				if [ ! -r "${_f}" ]; then
76160d3ee1bSlukem					warn "${_f} is not readable."
7621a286b14Slukem					if [ -z "$rc_force" ]; then
7636096ea59Slukem						return 1
7646096ea59Slukem					fi
765bd11504cSlukem				fi
7666096ea59Slukem			done
7676096ea59Slukem
768bd11504cSlukem					# if the precmd failed and force
769bd11504cSlukem					# isn't set, exit
770bd11504cSlukem					#
7711a286b14Slukem			if ! eval $_precmd && [ -z "$rc_force" ]; then
772bd11504cSlukem				return 1
773bd11504cSlukem			fi
774bd11504cSlukem
775bd11504cSlukem					# setup the command to run, and run it
776be9b3eeaSlukem					#
7776096ea59Slukem			echo "Starting ${name}."
7780847f3e3Slukem			if [ -n "$_chroot" ]; then
7790847f3e3Slukem				_doit="\
780bb9e7fd3Schristos$_env_clear_rc_vars $_env \
781a96d29c7Slukem${_nice:+nice -n $_nice }\
7820847f3e3Slukemchroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
7831a286b14Slukem$_chroot $command $rc_flags $command_args"
7840847f3e3Slukem			else
785eabbaa2fSlukem				_doit="\
786eabbaa2fSlukem${_chdir:+cd $_chdir; }\
787bb9e7fd3Schristos$_env_clear_rc_vars $_env \
788eabbaa2fSlukem${_nice:+nice -n $_nice }\
7891a286b14Slukem$command $rc_flags $command_args"
790ab72f65dSlukem				if [ -n "$_user" ]; then
791ab72f65dSlukem				    _doit="su -m $_user -c 'sh -c \"$_doit\"'"
792ab72f65dSlukem				fi
7930847f3e3Slukem			fi
7949cfa003dSlukem
7959cfa003dSlukem					# if the cmd failed and force
7969cfa003dSlukem					# isn't set, exit
7979cfa003dSlukem					#
7981a286b14Slukem			if ! eval $_doit && [ -z "$rc_force" ]; then
7999cfa003dSlukem				return 1
8009cfa003dSlukem			fi
8019cfa003dSlukem
8029cfa003dSlukem					# finally, run postcmd
8039cfa003dSlukem					#
8049cfa003dSlukem			eval $_postcmd
8056096ea59Slukem			;;
8066096ea59Slukem
8076096ea59Slukem		stop)
8081a286b14Slukem			if [ -z "$rc_pid" ]; then
8096096ea59Slukem				if [ -n "$pidfile" ]; then
8109bd9220cSlukem					echo 1>&2 \
8116096ea59Slukem				    "${name} not running? (check $pidfile)."
8126096ea59Slukem				else
8139bd9220cSlukem					echo 1>&2 "${name} not running?"
8146096ea59Slukem				fi
8156096ea59Slukem				exit 1
8166096ea59Slukem			fi
8176096ea59Slukem
8189cfa003dSlukem					# if the precmd failed and force
8199cfa003dSlukem					# isn't set, exit
8209cfa003dSlukem					#
8211a286b14Slukem			if ! eval $_precmd && [ -z "$rc_force" ]; then
822bd11504cSlukem				return 1
823bd11504cSlukem			fi
8249cfa003dSlukem
8259cfa003dSlukem					# send the signal to stop
8269cfa003dSlukem					#
8276096ea59Slukem			echo "Stopping ${name}."
8281a286b14Slukem			_doit="kill -${sig_stop:-TERM} $rc_pid"
829ab72f65dSlukem			if [ -n "$_user" ]; then
830ab72f65dSlukem				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
831ab72f65dSlukem			fi
8329cfa003dSlukem
8339cfa003dSlukem					# if the stop cmd failed and force
8349cfa003dSlukem					# isn't set, exit
8359cfa003dSlukem					#
8361a286b14Slukem			if ! eval $_doit && [ -z "$rc_force" ]; then
8379cfa003dSlukem				return 1
8389cfa003dSlukem			fi
8399cfa003dSlukem
8409cfa003dSlukem					# wait for the command to exit,
8419cfa003dSlukem					# and run postcmd.
8421a286b14Slukem			wait_for_pids $rc_pid
8439cfa003dSlukem			eval $_postcmd
8446096ea59Slukem			;;
8456096ea59Slukem
8466096ea59Slukem		reload)
8471a286b14Slukem			if [ -z "$rc_pid" ]; then
8486096ea59Slukem				if [ -n "$pidfile" ]; then
8499bd9220cSlukem					echo 1>&2 \
8506096ea59Slukem				    "${name} not running? (check $pidfile)."
8516096ea59Slukem				else
8529bd9220cSlukem					echo 1>&2 "${name} not running?"
8536096ea59Slukem				fi
8546096ea59Slukem				exit 1
8556096ea59Slukem			fi
8566096ea59Slukem			echo "Reloading ${name} config files."
8571a286b14Slukem			if ! eval $_precmd && [ -z "$rc_force" ]; then
858bd11504cSlukem				return 1
859bd11504cSlukem			fi
8601a286b14Slukem			_doit="kill -${sig_reload:-HUP} $rc_pid"
861ab72f65dSlukem			if [ -n "$_user" ]; then
862ab72f65dSlukem				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
863ab72f65dSlukem			fi
8641a286b14Slukem			if ! eval $_doit && [ -z "$rc_force" ]; then
8659cfa003dSlukem				return 1
8669cfa003dSlukem			fi
8679cfa003dSlukem			eval $_postcmd
8686096ea59Slukem			;;
8696096ea59Slukem
8706096ea59Slukem		restart)
8711a286b14Slukem			if ! eval $_precmd && [ -z "$rc_force" ]; then
872bd11504cSlukem				return 1
8736096ea59Slukem			fi
874be9b3eeaSlukem					# prevent restart being called more
875be9b3eeaSlukem					# than once by any given script
876be9b3eeaSlukem					#
87715388316Slukem			if ${_rc_restart_done:-false}; then
878be9b3eeaSlukem				return 0
879be9b3eeaSlukem			fi
88015388316Slukem			_rc_restart_done=true
8818490f0b0Slukem
882f3bab2a8Slukem			( $0 ${_rc_prefix}stop )
883f3bab2a8Slukem			$0 ${_rc_prefix}start
8846096ea59Slukem
8859cfa003dSlukem			eval $_postcmd
8866096ea59Slukem			;;
8876096ea59Slukem
8888490f0b0Slukem		poll)
8891a286b14Slukem			if [ -n "$rc_pid" ]; then
8901a286b14Slukem				wait_for_pids $rc_pid
8918490f0b0Slukem			fi
8928490f0b0Slukem			;;
8938490f0b0Slukem
8946096ea59Slukem		rcvar)
8956096ea59Slukem			echo "# $name"
896bd11504cSlukem			if [ -n "$rcvar" ]; then
897bd11504cSlukem				if checkyesno ${rcvar}; then
898c34ee371Suwe					echo "${rcvar}=YES"
8996096ea59Slukem				else
900c34ee371Suwe					echo "${rcvar}=NO"
901bd11504cSlukem				fi
9026096ea59Slukem			fi
9036096ea59Slukem			;;
9046096ea59Slukem
9056096ea59Slukem		*)
9066096ea59Slukem			rc_usage "$_keywords"
9076096ea59Slukem			;;
9086096ea59Slukem
9096096ea59Slukem		esac
9106096ea59Slukem		return 0
9116096ea59Slukem	done
9126096ea59Slukem
9131a286b14Slukem	echo 1>&2 "$0: unknown directive '$rc_arg'."
9146096ea59Slukem	rc_usage "$_keywords"
9156096ea59Slukem	exit 1
9166096ea59Slukem}
9176096ea59Slukem
9186096ea59Slukem#
9197bc38475Sapb# _have_rc_postprocessor
9207bc38475Sapb#	Test whether the current script is running in a context that
9217bc38475Sapb#	was invoked from /etc/rc with a postprocessor.
9227bc38475Sapb#
9237bc38475Sapb#	If the test fails, some variables may be unset to make
9247bc38475Sapb#	such tests more efficient in future.
9257bc38475Sapb#
9267bc38475Sapb_have_rc_postprocessor()
9277bc38475Sapb{
9287bc38475Sapb	# Cheap tests that fd and pid are set, fd is writable.
9298e58c959Sphx	[ -n "${_rc_pid}" ] || { unset _rc_pid; return 1; }
9308e58c959Sphx	[ -n "${_rc_postprocessor_fd}" ] || { unset _rc_pid; return 1; }
9318e58c959Sphx	eval ": >&${_rc_postprocessor_fd}" 2>/dev/null \
9327bc38475Sapb	|| { unset _rc_pid; return 1; }
9337bc38475Sapb
9347bc38475Sapb	return 0
9357bc38475Sapb}
9367bc38475Sapb
9377bc38475Sapb#
9386096ea59Slukem# run_rc_script file arg
9396096ea59Slukem#	Start the script `file' with `arg', and correctly handle the
9406096ea59Slukem#	return value from the script.  If `file' ends with `.sh', it's
94150aa4839Slukem#	sourced into the current environment.  If `file' appears to be
94250aa4839Slukem#	a backup or scratch file, ignore it.  Otherwise if it's
94350aa4839Slukem#	executable run as a child process.
944c8ddd612Slukem#
94589fd5357Sapb#	If `file' contains "KEYWORD: interactive" and if we are
9467bc38475Sapb#	running inside /etc/rc with postprocessing, then the script's
9477bc38475Sapb#	stdout and stderr are redirected to $_rc_original_stdout_fd and
94889fd5357Sapb#	$_rc_original_stderr_fd, so the output will be displayed on the
94989fd5357Sapb#	console but not intercepted by /etc/rc's postprocessor.
95089fd5357Sapb#
9516096ea59Slukemrun_rc_script()
9526096ea59Slukem{
9536096ea59Slukem	_file=$1
9546096ea59Slukem	_arg=$2
955e063fa5fSkre	if [ -z "$_file" ] || [ -z "$_arg" ]; then
9566096ea59Slukem		err 3 'USAGE: run_rc_script file arg'
9576096ea59Slukem	fi
9586096ea59Slukem
95974bbb8efSsalo	_run_rc_script=true
96074bbb8efSsalo
961d40d6757Slukem	unset	name command command_args command_interpreter \
962d40d6757Slukem		extra_commands pidfile procname \
96380ce7c6cSlukem		rcvar required_dirs required_files required_vars
9649cfa003dSlukem	eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
9650ccd65dfSlukem
96689fd5357Sapb	_must_redirect=false
9677bc38475Sapb	if _have_rc_postprocessor \
96889fd5357Sapb	    && _has_rcorder_keyword interactive $_file
96989fd5357Sapb	then
97089fd5357Sapb		_must_redirect=true
97189fd5357Sapb	fi
97289fd5357Sapb
9736096ea59Slukem	case "$_file" in
9746096ea59Slukem	*.sh)				# run in current shell
97589fd5357Sapb		if $_must_redirect; then
97689fd5357Sapb			print_rc_metadata \
97789fd5357Sapb			    "note:Output from ${_file} is not logged"
9781e2ed7f3Sapb			no_rc_postprocess eval \
9791e2ed7f3Sapb			    'set $_arg ; . $_file'
98089fd5357Sapb		else
9816096ea59Slukem			set $_arg ; . $_file
98289fd5357Sapb		fi
9836096ea59Slukem		;;
9846d7e3e1bSlukem	*[~#]|*.OLD|*.orig|*,v)		# scratch file; skip
98550aa4839Slukem		warn "Ignoring scratch file $_file"
98650aa4839Slukem		;;
9876096ea59Slukem	*)				# run in subshell
98889fd5357Sapb		if [ -x $_file ] && $_must_redirect; then
98989fd5357Sapb			print_rc_metadata \
99089fd5357Sapb			    "note:Output from ${_file} is not logged"
99189fd5357Sapb			if [ -n "$rc_fast_and_loose" ]; then
9921e2ed7f3Sapb				no_rc_postprocess eval \
9931e2ed7f3Sapb				    'set $_arg ; . $_file'
99489fd5357Sapb			else
9951e2ed7f3Sapb				no_rc_postprocess eval \
9961e2ed7f3Sapb				    '( set $_arg ; . $_file )'
99789fd5357Sapb			fi
99889fd5357Sapb		elif [ -x $_file ]; then
9990ccd65dfSlukem			if [ -n "$rc_fast_and_loose" ]; then
10000ccd65dfSlukem				set $_arg ; . $_file
10010ccd65dfSlukem			else
10026096ea59Slukem				( set $_arg ; . $_file )
100350aa4839Slukem			fi
100489fd5357Sapb		else
100589fd5357Sapb			warn "Ignoring non-executable file $_file"
10060ccd65dfSlukem		fi
10076096ea59Slukem		;;
10086096ea59Slukem	esac
10096096ea59Slukem}
10106096ea59Slukem
10116096ea59Slukem#
10123c81b28aSlukem# load_rc_config command
10132c25ae21Slukem#	Source in the configuration file for a given command.
10142c25ae21Slukem#
10152c25ae21Slukemload_rc_config()
10162c25ae21Slukem{
10172c25ae21Slukem	_command=$1
10182c25ae21Slukem	if [ -z "$_command" ]; then
10192c25ae21Slukem		err 3 'USAGE: load_rc_config command'
10202c25ae21Slukem	fi
10212c25ae21Slukem
1022dd2a7e0dSlukem	if ${_rc_conf_loaded:-false}; then
1023dd2a7e0dSlukem		:
1024dd2a7e0dSlukem	else
10252c25ae21Slukem		. /etc/rc.conf
102615388316Slukem		_rc_conf_loaded=true
1027c47a8060Slukem	fi
10285b8623beSfvdl	if [ -f /etc/rc.conf.d/"$_command" ]; then
10295b8623beSfvdl		. /etc/rc.conf.d/"$_command"
10305b8623beSfvdl	fi
10312c25ae21Slukem}
10322c25ae21Slukem
10333c81b28aSlukem#
10343c81b28aSlukem# load_rc_config_var cmd var
10353c81b28aSlukem#	Read the rc.conf(5) var for cmd and set in the
10363c81b28aSlukem#	current shell, using load_rc_config in a subshell to prevent
10373c81b28aSlukem#	unwanted side effects from other variable assignments.
10383c81b28aSlukem#
10393c81b28aSlukemload_rc_config_var()
10403c81b28aSlukem{
10413c81b28aSlukem	if [ $# -ne 2 ]; then
10423c81b28aSlukem		err 3 'USAGE: load_rc_config_var cmd var'
10433c81b28aSlukem	fi
10443c81b28aSlukem	eval $(eval '(
10453c81b28aSlukem		load_rc_config '$1' >/dev/null;
1046e063fa5fSkre		if [ -n "${'$2'}" ] || [ "${'$2'-UNSET}" != "UNSET" ]; then
10473c81b28aSlukem			echo '$2'=\'\''${'$2'}\'\'';
10483c81b28aSlukem		fi
10493c81b28aSlukem	)' )
10503c81b28aSlukem}
10512c25ae21Slukem
10522c25ae21Slukem#
10536096ea59Slukem# rc_usage commands
10546096ea59Slukem#	Print a usage string for $0, with `commands' being a list of
10556096ea59Slukem#	valid commands.
10566096ea59Slukem#
10576096ea59Slukemrc_usage()
10586096ea59Slukem{
1059f3bab2a8Slukem	echo -n 1>&2 "Usage: $0 [fast|force|one]("
10606096ea59Slukem
10616096ea59Slukem	_sep=
1062b224530cSchristos	for _elem; do
10636096ea59Slukem		echo -n 1>&2 "$_sep$_elem"
10646096ea59Slukem		_sep="|"
10656096ea59Slukem	done
10666096ea59Slukem	echo 1>&2 ")"
10676096ea59Slukem	exit 1
10686096ea59Slukem}
10696096ea59Slukem
10706096ea59Slukem#
10716096ea59Slukem# err exitval message
10726096ea59Slukem#	Display message to stderr and log to the syslog, and exit with exitval.
10736096ea59Slukem#
10746096ea59Slukemerr()
10756096ea59Slukem{
10766096ea59Slukem	exitval=$1
10776096ea59Slukem	shift
10786096ea59Slukem
107936ae72d9Sgrant	if [ -x /usr/bin/logger ]; then
1080acae4fe5Slukem		logger "$0: ERROR: $*"
108136ae72d9Sgrant	fi
1082acae4fe5Slukem	echo 1>&2 "$0: ERROR: $*"
10836096ea59Slukem	exit $exitval
10846096ea59Slukem}
10856096ea59Slukem
10866096ea59Slukem#
10876096ea59Slukem# warn message
10886096ea59Slukem#	Display message to stderr and log to the syslog.
10896096ea59Slukem#
10906096ea59Slukemwarn()
10916096ea59Slukem{
109236ae72d9Sgrant	if [ -x /usr/bin/logger ]; then
1093acae4fe5Slukem		logger "$0: WARNING: $*"
109436ae72d9Sgrant	fi
1095acae4fe5Slukem	echo 1>&2 "$0: WARNING: $*"
1096668efbbcScjs}
10972811b170Satatat
10982811b170Satatat#
10992811b170Satatat# backup_file action file cur backup
11002811b170Satatat#	Make a backup copy of `file' into `cur', and save the previous
11012811b170Satatat#	version of `cur' as `backup' or use rcs for archiving.
11022811b170Satatat#
11032811b170Satatat#	This routine checks the value of the backup_uses_rcs variable,
11042811b170Satatat#	which can be either YES or NO.
11052811b170Satatat#
11062811b170Satatat#	The `action' keyword can be one of the following:
11072811b170Satatat#
11082811b170Satatat#	add		`file' is now being backed up (and is possibly
11092811b170Satatat#			being reentered into the backups system).  `cur'
11102811b170Satatat#			is created and RCS files, if necessary, are
11112811b170Satatat#			created as well.
11122811b170Satatat#
11132811b170Satatat#	update		`file' has changed and needs to be backed up.
11142811b170Satatat#			If `cur' exists, it is copied to to `back' or
11152811b170Satatat#			checked into RCS (if the repository file is old),
11162811b170Satatat#			and then `file' is copied to `cur'.  Another RCS
11172811b170Satatat#			check in done here if RCS is being used.
11182811b170Satatat#
11192811b170Satatat#	remove		`file' is no longer being tracked by the backups
11202811b170Satatat#			system.  If RCS is not being used, `cur' is moved
11212811b170Satatat#			to `back', otherwise an empty file is checked in,
11222811b170Satatat#			and then `cur' is removed.
11232811b170Satatat#
11242811b170Satatat#
11252811b170Satatatbackup_file()
11262811b170Satatat{
11272811b170Satatat	_action=$1
11282811b170Satatat	_file=$2
11292811b170Satatat	_cur=$3
11302811b170Satatat	_back=$4
11312811b170Satatat
11322811b170Satatat	if checkyesno backup_uses_rcs; then
11332811b170Satatat		_msg0="backup archive"
11342811b170Satatat		_msg1="update"
11352811b170Satatat
113687c89197Satatat		# ensure that history file is not locked
113787c89197Satatat		if [ -f $_cur,v ]; then
113887c89197Satatat			rcs -q -u -U -M $_cur
113987c89197Satatat		fi
114087c89197Satatat
11412811b170Satatat		# ensure after switching to rcs that the
11422811b170Satatat		# current backup is not lost
11432811b170Satatat		if [ -f $_cur ]; then
11442811b170Satatat			# no archive, or current newer than archive
1145e063fa5fSkre			if [ ! -f $_cur,v ] || [ $_cur -nt $_cur,v ]; then
114687c89197Satatat				ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
114787c89197Satatat				rcs -q -kb -U $_cur
1148a40243dfSlukem				co -q -f -u $_cur
11492811b170Satatat			fi
11502811b170Satatat		fi
11512811b170Satatat
11522811b170Satatat		case $_action in
11532811b170Satatat		add|update)
11542811b170Satatat			cp -p $_file $_cur
115587c89197Satatat			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
115687c89197Satatat			rcs -q -kb -U $_cur
1157a40243dfSlukem			co -q -f -u $_cur
11582811b170Satatat			chown root:wheel $_cur $_cur,v
11592811b170Satatat			;;
11602811b170Satatat		remove)
11612811b170Satatat			cp /dev/null $_cur
116287c89197Satatat			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
116387c89197Satatat			rcs -q -kb -U $_cur
11642811b170Satatat			chown root:wheel $_cur $_cur,v
11652811b170Satatat			rm $_cur
11662811b170Satatat			;;
11672811b170Satatat		esac
11682811b170Satatat	else
11692811b170Satatat		case $_action in
11702811b170Satatat		add|update)
11712811b170Satatat			if [ -f $_cur ]; then
11722811b170Satatat				cp -p $_cur $_back
11732811b170Satatat			fi
11742811b170Satatat			cp -p $_file $_cur
11752811b170Satatat			chown root:wheel $_cur
11762811b170Satatat			;;
11772811b170Satatat		remove)
11782811b170Satatat			mv -f $_cur $_back
11792811b170Satatat			;;
11802811b170Satatat		esac
11812811b170Satatat	fi
11822811b170Satatat}
11837d2e1537Smycroft
118487fc4e29Schristos#
118587fc4e29Schristos# handle_fsck_error fsck_exit_code
118687fc4e29Schristos#	Take action depending on the return code from fsck.
118787fc4e29Schristos#
118887fc4e29Schristoshandle_fsck_error()
118987fc4e29Schristos{
119087fc4e29Schristos	case $1 in
119187fc4e29Schristos	0)	# OK
119287fc4e29Schristos		return
119387fc4e29Schristos		;;
119487fc4e29Schristos	2)	# Needs re-run, still fs errors
119587fc4e29Schristos		echo "File system still has errors; re-run fsck manually!"
119687fc4e29Schristos		;;
119787fc4e29Schristos	4)	# Root modified
119887fc4e29Schristos		echo "Root file system was modified, rebooting ..."
119987fc4e29Schristos		reboot -n
120087fc4e29Schristos		echo "Reboot failed; help!"
120187fc4e29Schristos		;;
120287fc4e29Schristos	8)	# Check failed
120387fc4e29Schristos		echo "Automatic file system check failed; help!"
120487fc4e29Schristos		;;
120587fc4e29Schristos	12)	# Got signal
120687fc4e29Schristos		echo "Boot interrupted."
120787fc4e29Schristos		;;
120887fc4e29Schristos	*)
120987fc4e29Schristos		echo "Unknown error $1; help!"
121087fc4e29Schristos		;;
121187fc4e29Schristos	esac
121287fc4e29Schristos	stop_boot
121387fc4e29Schristos}
121487fc4e29Schristos
121589fd5357Sapb#
121689fd5357Sapb# _has_rcorder_keyword word file
121789fd5357Sapb#	Check whether a file contains a "# KEYWORD:" comment with a
121889fd5357Sapb#	specified keyword in the style used by rcorder(8).
121989fd5357Sapb#
122089fd5357Sapb_has_rcorder_keyword()
122189fd5357Sapb{
122289fd5357Sapb	local word="$1"
122389fd5357Sapb	local file="$2"
122489fd5357Sapb	local line
122589fd5357Sapb
122689fd5357Sapb	[ -r "$file" ] || return 1
122789fd5357Sapb	while read line; do
122889fd5357Sapb		case "${line} " in
122989fd5357Sapb		"# KEYWORD:"*[\ \	]"${word}"[\ \	]*)
123089fd5357Sapb			return 0
123189fd5357Sapb			;;
123289fd5357Sapb		"#"*)
123389fd5357Sapb			continue
123489fd5357Sapb			;;
123589fd5357Sapb		*[A-Za-z0-9]*)
123689fd5357Sapb			# give up at the first non-empty non-comment line
123789fd5357Sapb			return 1
123889fd5357Sapb			;;
123989fd5357Sapb		esac
124089fd5357Sapb	done <"$file"
124189fd5357Sapb	return 1
124289fd5357Sapb}
124389fd5357Sapb
124489fd5357Sapb#
124589fd5357Sapb# print_rc_metadata string
124689fd5357Sapb#	Print the specified string in such a way that the post-processor
124789fd5357Sapb#	inside /etc/rc will treat it as meta-data.
124889fd5357Sapb#
124989fd5357Sapb#	If we are not running inside /etc/rc, do nothing.
125089fd5357Sapb#
125189fd5357Sapb#	For public use by any rc.d script, the string must begin with
125289fd5357Sapb#	"note:", followed by arbitrary text.  The intent is that the text
125389fd5357Sapb#	will appear in a log file but not on the console.
125489fd5357Sapb#
125589fd5357Sapb#	For private use within /etc/rc, the string must contain a
125689fd5357Sapb#	keyword recognised by the rc_postprocess_metadata() function
125789fd5357Sapb#	defined in /etc/rc, followed by a colon, followed by one or more
125889fd5357Sapb#	colon-separated arguments associated with the keyword.
125989fd5357Sapb#
126089fd5357Sapbprint_rc_metadata()
126189fd5357Sapb{
126289fd5357Sapb	# _rc_postprocessor fd, if defined, is the fd to which we must
126389fd5357Sapb	# print, prefixing the output with $_rc_metadata_prefix.
126489fd5357Sapb	#
12657bc38475Sapb	if _have_rc_postprocessor; then
126675350585Sapb		command printf "%s%s\n" "$rc_metadata_prefix" "$1" \
126789fd5357Sapb			>&${_rc_postprocessor_fd}
126889fd5357Sapb	fi
126989fd5357Sapb}
127089fd5357Sapb
127189fd5357Sapb#
127275350585Sapb# _flush_rc_output
127375350585Sapb#	Arrange for output to be flushed, if we are running
127475350585Sapb#	inside /etc/rc with postprocessing.
127575350585Sapb#
127675350585Sapb_flush_rc_output()
127775350585Sapb{
127875350585Sapb	print_rc_metadata "nop"
127975350585Sapb}
128075350585Sapb
128175350585Sapb#
128275350585Sapb# print_rc_normal [-n] string
128389fd5357Sapb#	Print the specified string in such way that it is treated as
128489fd5357Sapb#	normal output, regardless of whether or not we are running
128589fd5357Sapb#	inside /etc/rc with post-processing.
128689fd5357Sapb#
128775350585Sapb#	If "-n" is specified in $1, then the string in $2 is printed
128875350585Sapb#	without a newline; otherwise, the string in $1 is printed
128975350585Sapb#	with a newline.
129075350585Sapb#
129175350585Sapb#	Intended use cases include:
129275350585Sapb#
129375350585Sapb#	o   An rc.d script can use ``print_rc_normal -n'' to print a
129475350585Sapb#	    partial line in such a way that it appears immediately
129575350585Sapb#	    instead of being buffered by rc(8)'s post-processor.
129675350585Sapb#
129775350585Sapb#	o   An rc.d script that is run via the no_rc_postprocess
129875350585Sapb#	    function (so most of its output is invisible to rc(8)'s
129975350585Sapb#	    post-processor) can use print_rc_normal to force some of its
130075350585Sapb#	    output to be seen by the post-processor.
130175350585Sapb#
130289fd5357Sapb#
130389fd5357Sapbprint_rc_normal()
130489fd5357Sapb{
13057bc38475Sapb	# print to stdout or _rc_postprocessor_fd, depending on
13067bc38475Sapb	# whether not we have an rc postprocessor.
130789fd5357Sapb	#
13087bc38475Sapb	local fd=1
13097bc38475Sapb	_have_rc_postprocessor && fd="${_rc_postprocessor_fd}"
131075350585Sapb	case "$1" in
131175350585Sapb	"-n")
131275350585Sapb		command printf "%s" "$2" >&${fd}
131375350585Sapb		_flush_rc_output
131475350585Sapb		;;
131575350585Sapb	*)
131675350585Sapb		command printf "%s\n" "$1" >&${fd}
131775350585Sapb		;;
131875350585Sapb	esac
131989fd5357Sapb}
132089fd5357Sapb
132189fd5357Sapb#
132289fd5357Sapb# no_rc_postprocess cmd...
132389fd5357Sapb#	Execute the specified command in such a way that its output
132489fd5357Sapb#	bypasses the post-processor that handles the output from
132589fd5357Sapb#	most commands that are run inside /etc/rc.  If we are not
132689fd5357Sapb#	inside /etc/rc, then just execute the command without special
132789fd5357Sapb#	treatment.
132889fd5357Sapb#
132989fd5357Sapb#	The intent is that interactive commands can be run via
1330*f42f89fdSandvar#	no_rc_postprocess(), and their output will appear immediately
133189fd5357Sapb#	on the console instead of being hidden or delayed by the
133289fd5357Sapb#	post-processor.	 An unfortunate consequence of the output
133389fd5357Sapb#	bypassing the post-processor is that the output will not be
133489fd5357Sapb#	logged.
133589fd5357Sapb#
133689fd5357Sapbno_rc_postprocess()
133789fd5357Sapb{
13387bc38475Sapb	if _have_rc_postprocessor; then
133989fd5357Sapb		"$@" >&${_rc_original_stdout_fd} 2>&${_rc_original_stderr_fd}
134089fd5357Sapb	else
134189fd5357Sapb		"$@"
134289fd5357Sapb	fi
134389fd5357Sapb}
134489fd5357Sapb
134589fd5357Sapb#
134689fd5357Sapb# twiddle
134789fd5357Sapb#	On each call, print a different one of "/", "-", "\\", "|",
134889fd5357Sapb#	followed by a backspace.  The most recently printed value is
134989fd5357Sapb#	saved in $_twiddle_state.
135089fd5357Sapb#
135189fd5357Sapb#	Output is to /dev/tty, so this function may be useful even inside
135289fd5357Sapb#	a script whose output is redirected.
135389fd5357Sapb#
135489fd5357Sapbtwiddle()
135589fd5357Sapb{
135689fd5357Sapb	case "$_twiddle_state" in
135789fd5357Sapb	'/')	_next='-' ;;
135889fd5357Sapb	'-')	_next='\' ;;
135989fd5357Sapb	'\')	_next='|' ;;
136089fd5357Sapb	*)	_next='/' ;;
136189fd5357Sapb	esac
136275350585Sapb	command printf "%s\b" "$_next" >/dev/tty
136389fd5357Sapb	_twiddle_state="$_next"
136489fd5357Sapb}
136589fd5357Sapb
1366520fd1e5Schristos#
1367520fd1e5Schristos# human_exit_code
1368520fd1e5Schristos#	Print the a human version of the exit code.
1369520fd1e5Schristos#
1370520fd1e5Schristoshuman_exit_code()
1371520fd1e5Schristos{
1372d6169708Schristos	if [ "$1" -lt 127 ]
1373520fd1e5Schristos	then
1374520fd1e5Schristos		echo "exited with code $1"
13752ae8ee3aSchristos	elif [ "$(expr $1 % 256)" -eq 127 ]
1376520fd1e5Schristos	then
1377a3299c90Schristos		# This cannot really happen because the shell will not
1378a3299c90Schristos		# pass stopped job status out and the exit code is limited
1379a3299c90Schristos		# to 8 bits. This code is here just for completeness.
1380520fd1e5Schristos		echo "stopped with signal $(expr $1 / 256)"
1381520fd1e5Schristos	else
1382520fd1e5Schristos		echo "terminated with signal $(expr $1 - 128)"
1383520fd1e5Schristos	fi
1384520fd1e5Schristos}
1385520fd1e5Schristos
1386f265a7c0Sapb#
1387f265a7c0Sapb# collapse_backslash_newline
1388f265a7c0Sapb#	Copy input to output, collapsing <backslash><newline>
1389f265a7c0Sapb#	to nothing, but leaving other backslashes alone.
1390f265a7c0Sapb#
1391f265a7c0Sapbcollapse_backslash_newline()
1392f265a7c0Sapb{
1393f265a7c0Sapb	local line
1394f265a7c0Sapb	while read -r line ; do
1395f265a7c0Sapb		case "$line" in
1396f265a7c0Sapb		*\\)
1397f265a7c0Sapb			# print it, without the backslash or newline
139875350585Sapb			command printf "%s" "${line%?}"
1399f265a7c0Sapb			;;
1400f265a7c0Sapb		*)
1401f265a7c0Sapb			# print it, with a newline
140275350585Sapb			command printf "%s\n" "${line}"
1403f265a7c0Sapb			;;
1404f265a7c0Sapb		esac
1405f265a7c0Sapb	done
1406f265a7c0Sapb}
1407520fd1e5Schristos
1408532fa0d9Sapb# Shell implementations of basename and dirname, usable before
1409532fa0d9Sapb# the /usr file system is mounted.
1410532fa0d9Sapb#
1411532fa0d9Sapbbasename()
1412532fa0d9Sapb{
1413532fa0d9Sapb	local file="$1"
1414532fa0d9Sapb	local suffix="$2"
1415532fa0d9Sapb	local base
1416532fa0d9Sapb
1417532fa0d9Sapb	base="${file##*/}"		# remove up to and including last '/'
1418532fa0d9Sapb	base="${base%${suffix}}"	# remove suffix, if any
1419532fa0d9Sapb	command printf "%s\n" "${base}"
1420532fa0d9Sapb}
1421532fa0d9Sapb
1422532fa0d9Sapbdirname()
1423532fa0d9Sapb{
1424532fa0d9Sapb	local file="$1"
1425532fa0d9Sapb	local dir
1426532fa0d9Sapb
1427532fa0d9Sapb	case "$file" in
1428532fa0d9Sapb	/*/*)	dir="${file%/*}" ;;	# common case: absolute path
1429532fa0d9Sapb	/*)	dir="/" ;;		# special case: name in root dir
1430532fa0d9Sapb	*/*)	dir="${file%/*}" ;;	# common case: relative path with '/'
1431532fa0d9Sapb	*)	dir="." ;;		# special case: name without '/'
1432532fa0d9Sapb	esac
1433532fa0d9Sapb	command printf "%s\n" "${dir}"
1434532fa0d9Sapb}
1435532fa0d9Sapb
143675350585Sapb# Override the normal "echo" and "printf" commands, so that
143775350585Sapb# partial lines printed by rc.d scripts appear immediately,
143875350585Sapb# instead of being buffered by rc(8)'s post-processor.
143975350585Sapb#
144075350585Sapb# Naive use of the echo or printf commands from rc.d scripts,
144175350585Sapb# elsewhere in rc.subr, or anything else that sources rc.subr,
144275350585Sapb# will call these functions.  To call the real echo and printf
144375350585Sapb# commands, use "command echo" or "command printf".
144475350585Sapb#
1445e063fa5fSkre# Avoid use of echo altogether as much as possible, printf works better
1446e063fa5fSkre#
144775350585Sapbecho()
144875350585Sapb{
1449e063fa5fSkre	local IFS=' ' NL='\n'	# not a literal newline...
1450e063fa5fSkre
145175350585Sapb	case "$1" in
1452e063fa5fSkre	-n)	NL=; shift;;
145375350585Sapb	esac
1454e063fa5fSkre
1455e063fa5fSkre	command printf "%s${NL}" "$*"
1456e063fa5fSkre
1457e063fa5fSkre	if test -z "${NL}"
1458e063fa5fSkre	then
1459e063fa5fSkre		_flush_rc_output
1460e063fa5fSkre	fi
1461e063fa5fSkre	return 0
146275350585Sapb}
1463e063fa5fSkre
146475350585Sapbprintf()
146575350585Sapb{
146675350585Sapb	command printf "$@"
146775350585Sapb	case "$1" in
146875350585Sapb	*'\n')	: ;;
146975350585Sapb	*)	_flush_rc_output ;;
147075350585Sapb	esac
1471e063fa5fSkre	return 0
147275350585Sapb}
147375350585Sapb
1474709030f1Schristoskat() {
1475709030f1Schristos	local i
1476709030f1Schristos	local v
1477709030f1Schristos	for i; do
1478709030f1Schristos		while read -r v; do
1479709030f1Schristos			v="${v%%#*}"
1480709030f1Schristos			if [ -z "$v" ]; then
1481709030f1Schristos				continue
1482709030f1Schristos			fi
1483709030f1Schristos			echo "$v"
1484709030f1Schristos		done < "$i"
1485709030f1Schristos	done
1486709030f1Schristos}
1487709030f1Schristos
14887d2e1537Smycroft_rc_subr_loaded=:
1489