xref: /minix3/etc/rc.subr (revision 77e79d33746fa2b709086b9caa51b1415d66c801)
10a6a1f1dSLionel Sambuc# $NetBSD: rc.subr,v 1.96 2014/10/07 19:09:45 roy Exp $
2e68cf3bfSBen Gras#
3e68cf3bfSBen Gras# Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
4e68cf3bfSBen Gras# All rights reserved.
5e68cf3bfSBen Gras#
6e68cf3bfSBen Gras# This code is derived from software contributed to The NetBSD Foundation
7e68cf3bfSBen Gras# by Luke Mewburn.
8e68cf3bfSBen Gras#
9e68cf3bfSBen Gras# Redistribution and use in source and binary forms, with or without
10e68cf3bfSBen Gras# modification, are permitted provided that the following conditions
11e68cf3bfSBen Gras# are met:
12e68cf3bfSBen Gras# 1. Redistributions of source code must retain the above copyright
13e68cf3bfSBen Gras#    notice, this list of conditions and the following disclaimer.
14e68cf3bfSBen Gras# 2. Redistributions in binary form must reproduce the above copyright
15e68cf3bfSBen Gras#    notice, this list of conditions and the following disclaimer in the
16e68cf3bfSBen Gras#    documentation and/or other materials provided with the distribution.
17e68cf3bfSBen Gras#
18e68cf3bfSBen Gras# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19e68cf3bfSBen Gras# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20e68cf3bfSBen Gras# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21e68cf3bfSBen Gras# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22e68cf3bfSBen Gras# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23e68cf3bfSBen Gras# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24e68cf3bfSBen Gras# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25e68cf3bfSBen Gras# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26e68cf3bfSBen Gras# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27e68cf3bfSBen Gras# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28e68cf3bfSBen Gras# POSSIBILITY OF SUCH DAMAGE.
29e68cf3bfSBen Gras#
30e68cf3bfSBen Gras# rc.subr
31e68cf3bfSBen Gras#	functions used by various rc scripts
32e68cf3bfSBen Gras#
33e68cf3bfSBen Gras
34e68cf3bfSBen Gras: ${rcvar_manpage:='rc.conf(5)'}
35e68cf3bfSBen Gras: ${RC_PID:=$$} ; export RC_PID
36e68cf3bfSBen Grasnl='
37e68cf3bfSBen Gras' # a literal newline
38e68cf3bfSBen Gras
39e68cf3bfSBen Gras#
40e68cf3bfSBen Gras#	functions
41e68cf3bfSBen Gras#	---------
42e68cf3bfSBen Gras
43e68cf3bfSBen Gras#
44e68cf3bfSBen Gras# checkyesno var
450a6a1f1dSLionel Sambuc#	Test $1 variable.
460a6a1f1dSLionel Sambuc#	Return 0 if it's "yes" (et al), 1 if it's "no" (et al), 2 otherwise.
47e68cf3bfSBen Gras#
480a6a1f1dSLionel Sambuccheckyesnox()
49e68cf3bfSBen Gras{
50e68cf3bfSBen Gras	eval _value=\$${1}
51e68cf3bfSBen Gras	case $_value in
52e68cf3bfSBen Gras
53e68cf3bfSBen Gras		#	"yes", "true", "on", or "1"
54e68cf3bfSBen Gras	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
55e68cf3bfSBen Gras		return 0
56e68cf3bfSBen Gras		;;
57e68cf3bfSBen Gras
58e68cf3bfSBen Gras		#	"no", "false", "off", or "0"
59e68cf3bfSBen Gras	[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
60e68cf3bfSBen Gras		return 1
61e68cf3bfSBen Gras		;;
62e68cf3bfSBen Gras	*)
630a6a1f1dSLionel Sambuc		return 2
64e68cf3bfSBen Gras		;;
65e68cf3bfSBen Gras	esac
66e68cf3bfSBen Gras}
67e68cf3bfSBen Gras
68e68cf3bfSBen Gras#
690a6a1f1dSLionel Sambuc# checkyesno var
700a6a1f1dSLionel Sambuc#	Test $1 variable, and warn if not set to YES or NO.
710a6a1f1dSLionel Sambuc#	Return 0 if it's "yes" (et al), nonzero otherwise.
720a6a1f1dSLionel Sambuc#
730a6a1f1dSLionel Sambuccheckyesno()
740a6a1f1dSLionel Sambuc{
750a6a1f1dSLionel Sambuc	local var
760a6a1f1dSLionel Sambuc
770a6a1f1dSLionel Sambuc	checkyesnox $1
780a6a1f1dSLionel Sambuc	var=$?
790a6a1f1dSLionel Sambuc	[ $var = 0 -o $var = 1 ] && return $var
800a6a1f1dSLionel Sambuc	warn "\$${1} is not set properly - see ${rcvar_manpage}."
810a6a1f1dSLionel Sambuc	return 1
820a6a1f1dSLionel Sambuc}
830a6a1f1dSLionel Sambuc
840a6a1f1dSLionel Sambuc#
85e68cf3bfSBen Gras# yesno_to_truefalse var
86e68cf3bfSBen Gras#	Convert the value of a variable from any of the values
87e68cf3bfSBen Gras#	understood by checkyesno() to "true" or "false".
88e68cf3bfSBen Gras#
89e68cf3bfSBen Grasyesno_to_truefalse()
90e68cf3bfSBen Gras{
91e68cf3bfSBen Gras	local var=$1
92e68cf3bfSBen Gras	if checkyesno $var; then
93e68cf3bfSBen Gras		eval $var=true
94e68cf3bfSBen Gras		return 0
95e68cf3bfSBen Gras	else
96e68cf3bfSBen Gras		eval $var=false
97e68cf3bfSBen Gras		return 1
98e68cf3bfSBen Gras	fi
99e68cf3bfSBen Gras}
100e68cf3bfSBen Gras
101e68cf3bfSBen Gras#
102e68cf3bfSBen Gras# reverse_list list
103e68cf3bfSBen Gras#	print the list in reverse order
104e68cf3bfSBen Gras#
105e68cf3bfSBen Grasreverse_list()
106e68cf3bfSBen Gras{
107e68cf3bfSBen Gras	_revlist=
108e68cf3bfSBen Gras	for _revfile; do
109e68cf3bfSBen Gras		_revlist="$_revfile $_revlist"
110e68cf3bfSBen Gras	done
111e68cf3bfSBen Gras	echo $_revlist
112e68cf3bfSBen Gras}
113e68cf3bfSBen Gras
114e68cf3bfSBen Gras#
115e68cf3bfSBen Gras# If booting directly to multiuser, send SIGTERM to
116e68cf3bfSBen Gras# the parent (/etc/rc) to abort the boot.
117e68cf3bfSBen Gras# Otherwise just exit.
118e68cf3bfSBen Gras#
119e68cf3bfSBen Grasstop_boot()
120e68cf3bfSBen Gras{
121e68cf3bfSBen Gras	if [ "$autoboot" = yes ]; then
122e68cf3bfSBen Gras		echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!"
123e68cf3bfSBen Gras		kill -TERM ${RC_PID}
124e68cf3bfSBen Gras	fi
125e68cf3bfSBen Gras	exit 1
126e68cf3bfSBen Gras}
127e68cf3bfSBen Gras
128e68cf3bfSBen Gras#
129e68cf3bfSBen Gras# mount_critical_filesystems type
130e68cf3bfSBen Gras#	Go through the list of critical file systems as provided in
131e68cf3bfSBen Gras#	the rc.conf(5) variable $critical_filesystems_${type}, checking
132e68cf3bfSBen Gras#	each one to see if it is mounted, and if it is not, mounting it.
133e68cf3bfSBen Gras#	It's not an error if file systems prefixed with "OPTIONAL:"
134e68cf3bfSBen Gras#	are not mentioned in /etc/fstab.
135e68cf3bfSBen Gras#
136e68cf3bfSBen Grasmount_critical_filesystems()
137e68cf3bfSBen Gras{
138e68cf3bfSBen Gras	eval _fslist=\$critical_filesystems_${1}
139e68cf3bfSBen Gras	_mountcrit_es=0
140e68cf3bfSBen Gras	for _fs in $_fslist; do
141e68cf3bfSBen Gras		_optional=false
142e68cf3bfSBen Gras		case "$_fs" in
143e68cf3bfSBen Gras		OPTIONAL:*)
144e68cf3bfSBen Gras			_optional=true
145e68cf3bfSBen Gras			_fs="${_fs#*:}"
146e68cf3bfSBen Gras			;;
147e68cf3bfSBen Gras		esac
148e68cf3bfSBen Gras		_ismounted=false
149e68cf3bfSBen Gras		# look for a line like "${fs} on * type *"
150e68cf3bfSBen Gras		# or "* on ${fs} type *" in the output from mount.
151e68cf3bfSBen Gras		case "${nl}$( mount )${nl}" in
152e68cf3bfSBen Gras		*" on ${_fs} type "*)
153e68cf3bfSBen Gras			_ismounted=true
154e68cf3bfSBen Gras			;;
155e68cf3bfSBen Gras		*"${nl}${_fs} on "*)
156e68cf3bfSBen Gras			_ismounted=true
157e68cf3bfSBen Gras			;;
158e68cf3bfSBen Gras		esac
159e68cf3bfSBen Gras		if $_ismounted; then
160e68cf3bfSBen Gras			print_rc_metadata \
161e68cf3bfSBen Gras			"note:File system ${_fs} was already mounted"
162e68cf3bfSBen Gras		else
163e68cf3bfSBen Gras			_mount_output=$( mount $_fs 2>&1 )
164e68cf3bfSBen Gras			_mount_es=$?
165e68cf3bfSBen Gras			case "$_mount_output" in
166e68cf3bfSBen Gras			*"${nl}"*)
167e68cf3bfSBen Gras				# multiple lines can't be good,
168e68cf3bfSBen Gras				# not even if $_optional is true
169e68cf3bfSBen Gras				;;
17084d9c625SLionel Sambuc			*[uU]'nknown special file or file system'*)
171e68cf3bfSBen Gras				if $_optional; then
172e68cf3bfSBen Gras					# ignore this error
173e68cf3bfSBen Gras					print_rc_metadata \
174e68cf3bfSBen Gras			"note:Optional file system ${_fs} is not present"
175e68cf3bfSBen Gras					_mount_es=0
176e68cf3bfSBen Gras					_mount_output=""
177e68cf3bfSBen Gras				fi
178e68cf3bfSBen Gras				;;
179e68cf3bfSBen Gras			esac
180e68cf3bfSBen Gras			if [ -n "$_mount_output" ]; then
181e68cf3bfSBen Gras				printf >&2 "%s\n" "$_mount_output"
182e68cf3bfSBen Gras			fi
183e68cf3bfSBen Gras			if [ "$_mount_es" != 0 ]; then
184e68cf3bfSBen Gras				_mountcrit_es="$_mount_es"
185e68cf3bfSBen Gras			fi
186e68cf3bfSBen Gras		fi
187e68cf3bfSBen Gras	done
188e68cf3bfSBen Gras	return $_mountcrit_es
189e68cf3bfSBen Gras}
190e68cf3bfSBen Gras
191e68cf3bfSBen Gras#
192e68cf3bfSBen Gras# check_pidfile pidfile procname [interpreter]
193e68cf3bfSBen Gras#	Parses the first line of pidfile for a PID, and ensures
194e68cf3bfSBen Gras#	that the process is running and matches procname.
195e68cf3bfSBen Gras#	Prints the matching PID upon success, nothing otherwise.
196e68cf3bfSBen Gras#	interpreter is optional; see _find_processes() for details.
197e68cf3bfSBen Gras#
198e68cf3bfSBen Grascheck_pidfile()
199e68cf3bfSBen Gras{
200e68cf3bfSBen Gras	_pidfile=$1
201e68cf3bfSBen Gras	_procname=$2
202e68cf3bfSBen Gras	_interpreter=$3
203e68cf3bfSBen Gras	if [ -z "$_pidfile" -o -z "$_procname" ]; then
204e68cf3bfSBen Gras		err 3 'USAGE: check_pidfile pidfile procname [interpreter]'
205e68cf3bfSBen Gras	fi
206e68cf3bfSBen Gras	if [ ! -f $_pidfile ]; then
207e68cf3bfSBen Gras		return
208e68cf3bfSBen Gras	fi
209e68cf3bfSBen Gras	read _pid _junk < $_pidfile
210e68cf3bfSBen Gras	if [ -z "$_pid" ]; then
211e68cf3bfSBen Gras		return
212e68cf3bfSBen Gras	fi
213e68cf3bfSBen Gras	_find_processes $_procname ${_interpreter:-.} '-p '"$_pid"
214e68cf3bfSBen Gras}
215e68cf3bfSBen Gras
216e68cf3bfSBen Gras#
217e68cf3bfSBen Gras# check_process procname [interpreter]
218e68cf3bfSBen Gras#	Ensures that a process (or processes) named procname is running.
219e68cf3bfSBen Gras#	Prints a list of matching PIDs.
220e68cf3bfSBen Gras#	interpreter is optional; see _find_processes() for details.
221e68cf3bfSBen Gras#
222e68cf3bfSBen Grascheck_process()
223e68cf3bfSBen Gras{
224e68cf3bfSBen Gras	_procname=$1
225e68cf3bfSBen Gras	_interpreter=$2
226e68cf3bfSBen Gras	if [ -z "$_procname" ]; then
227e68cf3bfSBen Gras		err 3 'USAGE: check_process procname [interpreter]'
228e68cf3bfSBen Gras	fi
229e68cf3bfSBen Gras	_find_processes $_procname ${_interpreter:-.} '-ax'
230e68cf3bfSBen Gras}
231e68cf3bfSBen Gras
232e68cf3bfSBen Gras#
233e68cf3bfSBen Gras# _find_processes procname interpreter psargs
234e68cf3bfSBen Gras#	Search for procname in the output of ps generated by psargs.
235e68cf3bfSBen Gras#	Prints the PIDs of any matching processes, space separated.
236e68cf3bfSBen Gras#
237e68cf3bfSBen Gras#	If interpreter == ".", check the following variations of procname
238e68cf3bfSBen Gras#	against the first word of each command:
239e68cf3bfSBen Gras#		procname
240e68cf3bfSBen Gras#		`basename procname`
241e68cf3bfSBen Gras#		`basename procname` + ":"
242e68cf3bfSBen Gras#		"(" + `basename procname` + ")"
243e68cf3bfSBen Gras#
244e68cf3bfSBen Gras#	If interpreter != ".", read the first line of procname, remove the
245e68cf3bfSBen Gras#	leading #!, normalise whitespace, append procname, and attempt to
246e68cf3bfSBen Gras#	match that against each command, either as is, or with extra words
247e68cf3bfSBen Gras#	at the end.  As an alternative, to deal with interpreted daemons
248e68cf3bfSBen Gras#	using perl, the basename of the interpreter plus a colon is also
249e68cf3bfSBen Gras#	tried as the prefix to procname.
250e68cf3bfSBen Gras#
251e68cf3bfSBen Gras_find_processes()
252e68cf3bfSBen Gras{
253e68cf3bfSBen Gras	if [ $# -ne 3 ]; then
254e68cf3bfSBen Gras		err 3 'USAGE: _find_processes procname interpreter psargs'
255e68cf3bfSBen Gras	fi
256e68cf3bfSBen Gras	_procname=$1
257e68cf3bfSBen Gras	_interpreter=$2
258e68cf3bfSBen Gras	_psargs=$3
259e68cf3bfSBen Gras
260e68cf3bfSBen Gras	_pref=
261e68cf3bfSBen Gras	_procnamebn=${_procname##*/}
262e68cf3bfSBen Gras	if [ $_interpreter != "." ]; then	# an interpreted script
263e68cf3bfSBen Gras		read _interp < ${_chroot:-}/$_procname	# read interpreter name
264e68cf3bfSBen Gras		_interp=${_interp#\#!}		# strip #!
265e68cf3bfSBen Gras		set -- $_interp
266e68cf3bfSBen Gras		if [ $1 = "/usr/bin/env" ]; then
267e68cf3bfSBen Gras			shift
268e68cf3bfSBen Gras			set -- $(type $1)
269e68cf3bfSBen Gras			shift $(($# - 1))
270e68cf3bfSBen Gras			_interp="${1##*/} $_procname"
271e68cf3bfSBen Gras		else
272e68cf3bfSBen Gras			_interp="$* $_procname"
273e68cf3bfSBen Gras		fi
274e68cf3bfSBen Gras		if [ $_interpreter != $1 ]; then
275e68cf3bfSBen Gras			warn "\$command_interpreter $_interpreter != $1"
276e68cf3bfSBen Gras		fi
277e68cf3bfSBen Gras		_interpbn=${1##*/}
278e68cf3bfSBen Gras		_fp_args='_argv'
279e68cf3bfSBen Gras		_fp_match='case "$_argv" in
280e68cf3bfSBen Gras		    ${_interp}|"${_interp} "*|"${_interpbn}: "*${_procnamebn}*)'
281e68cf3bfSBen Gras	else					# a normal daemon
282e68cf3bfSBen Gras		_fp_args='_arg0 _argv'
283e68cf3bfSBen Gras		_fp_match='case "$_arg0" in
284e68cf3bfSBen Gras		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
285e68cf3bfSBen Gras	fi
286e68cf3bfSBen Gras
287e68cf3bfSBen Gras	_proccheck='
288e68cf3bfSBen Gras		ps -o "pid,command" '"$_psargs"' |
289e68cf3bfSBen Gras		while read _npid '"$_fp_args"'; do
290e68cf3bfSBen Gras			case "$_npid" in
291e68cf3bfSBen Gras			    PID)
292e68cf3bfSBen Gras				continue ;;
293e68cf3bfSBen Gras			esac ; '"$_fp_match"'
294e68cf3bfSBen Gras				echo -n "$_pref$_npid" ;
295e68cf3bfSBen Gras				_pref=" "
296e68cf3bfSBen Gras				;;
297e68cf3bfSBen Gras			esac
298e68cf3bfSBen Gras		done'
299e68cf3bfSBen Gras
300e68cf3bfSBen Gras#echo 1>&2 "proccheck is :$_proccheck:"
301e68cf3bfSBen Gras	eval $_proccheck
302e68cf3bfSBen Gras}
303e68cf3bfSBen Gras
304e68cf3bfSBen Gras#
305e68cf3bfSBen Gras# wait_for_pids pid [pid ...]
306e68cf3bfSBen Gras#	spins until none of the pids exist
307e68cf3bfSBen Gras#
308e68cf3bfSBen Graswait_for_pids()
309e68cf3bfSBen Gras{
310e68cf3bfSBen Gras	_list="$@"
311e68cf3bfSBen Gras	if [ -z "$_list" ]; then
312e68cf3bfSBen Gras		return
313e68cf3bfSBen Gras	fi
314e68cf3bfSBen Gras	_prefix=
315e68cf3bfSBen Gras	while true; do
316e68cf3bfSBen Gras		_nlist="";
317e68cf3bfSBen Gras		for _j in $_list; do
318e68cf3bfSBen Gras			if kill -0 $_j 2>/dev/null; then
319e68cf3bfSBen Gras				_nlist="${_nlist}${_nlist:+ }$_j"
320e68cf3bfSBen Gras			fi
321e68cf3bfSBen Gras		done
322e68cf3bfSBen Gras		if [ -z "$_nlist" ]; then
323e68cf3bfSBen Gras			break
324e68cf3bfSBen Gras		fi
3250a6a1f1dSLionel Sambuc		if [ "$_list" != "$_nlist" ]; then
326e68cf3bfSBen Gras			_list=$_nlist
327e68cf3bfSBen Gras			echo -n ${_prefix:-"Waiting for PIDS: "}$_list
328e68cf3bfSBen Gras			_prefix=", "
3290a6a1f1dSLionel Sambuc		fi
3300a6a1f1dSLionel Sambuc		# We want this to be a tight loop for a fast exit
3310a6a1f1dSLionel Sambuc		sleep 0.05
332e68cf3bfSBen Gras	done
333e68cf3bfSBen Gras	if [ -n "$_prefix" ]; then
334e68cf3bfSBen Gras		echo "."
335e68cf3bfSBen Gras	fi
336e68cf3bfSBen Gras}
337e68cf3bfSBen Gras
338e68cf3bfSBen Gras#
339e68cf3bfSBen Gras# run_rc_command argument [parameters]
340e68cf3bfSBen Gras#	Search for argument in the list of supported commands, which is:
341e68cf3bfSBen Gras#		"start stop restart rcvar status poll ${extra_commands}"
342e68cf3bfSBen Gras#	If there's a match, run ${argument}_cmd or the default method
343e68cf3bfSBen Gras#	(see below), and pass the optional list of parameters to it.
344e68cf3bfSBen Gras#
345e68cf3bfSBen Gras#	If argument has a given prefix, then change the operation as follows:
346e68cf3bfSBen Gras#		Prefix	Operation
347e68cf3bfSBen Gras#		------	---------
348e68cf3bfSBen Gras#		fast	Skip the pid check, and set rc_fast=yes
349e68cf3bfSBen Gras#		force	Set ${rcvar} to YES, and set rc_force=yes
350e68cf3bfSBen Gras#		one	Set ${rcvar} to YES
351e68cf3bfSBen Gras#
352e68cf3bfSBen Gras#	The following globals are used:
353e68cf3bfSBen Gras#
354e68cf3bfSBen Gras#	Name		Needed	Purpose
355e68cf3bfSBen Gras#	----		------	-------
356e68cf3bfSBen Gras#	name		y	Name of script.
357e68cf3bfSBen Gras#
358e68cf3bfSBen Gras#	command		n	Full path to command.
359e68cf3bfSBen Gras#				Not needed if ${rc_arg}_cmd is set for
360e68cf3bfSBen Gras#				each keyword.
361e68cf3bfSBen Gras#
362e68cf3bfSBen Gras#	command_args	n	Optional args/shell directives for command.
363e68cf3bfSBen Gras#
364e68cf3bfSBen Gras#	command_interpreter n	If not empty, command is interpreted, so
365e68cf3bfSBen Gras#				call check_{pidfile,process}() appropriately.
366e68cf3bfSBen Gras#
367e68cf3bfSBen Gras#	extra_commands	n	List of extra commands supported.
368e68cf3bfSBen Gras#
369e68cf3bfSBen Gras#	pidfile		n	If set, use check_pidfile $pidfile $command,
370e68cf3bfSBen Gras#				otherwise use check_process $command.
371e68cf3bfSBen Gras#				In either case, only check if $command is set.
372e68cf3bfSBen Gras#
373e68cf3bfSBen Gras#	procname	n	Process name to check for instead of $command.
374e68cf3bfSBen Gras#
375e68cf3bfSBen Gras#	rcvar		n	This is checked with checkyesno to determine
376e68cf3bfSBen Gras#				if the action should be run.
377e68cf3bfSBen Gras#
378e68cf3bfSBen Gras#	${name}_chroot	n	Directory to chroot to before running ${command}
379e68cf3bfSBen Gras#				Requires /usr to be mounted.
380e68cf3bfSBen Gras#
381e68cf3bfSBen Gras#	${name}_chdir	n	Directory to cd to before running ${command}
382e68cf3bfSBen Gras#				(if not using ${name}_chroot).
383e68cf3bfSBen Gras#
384e68cf3bfSBen Gras#	${name}_flags	n	Arguments to call ${command} with.
385e68cf3bfSBen Gras#				NOTE:	$flags from the parent environment
386e68cf3bfSBen Gras#					can be used to override this.
387e68cf3bfSBen Gras#
388e68cf3bfSBen Gras#	${name}_env	n	Additional environment variable settings
389e68cf3bfSBen Gras#				for running ${command}
390e68cf3bfSBen Gras#
391e68cf3bfSBen Gras#	${name}_nice	n	Nice level to run ${command} at.
392e68cf3bfSBen Gras#
393e68cf3bfSBen Gras#	${name}_user	n	User to run ${command} as, using su(1) if not
394e68cf3bfSBen Gras#				using ${name}_chroot.
395e68cf3bfSBen Gras#				Requires /usr to be mounted.
396e68cf3bfSBen Gras#
397e68cf3bfSBen Gras#	${name}_group	n	Group to run chrooted ${command} as.
398e68cf3bfSBen Gras#				Requires /usr to be mounted.
399e68cf3bfSBen Gras#
400e68cf3bfSBen Gras#	${name}_groups	n	Comma separated list of supplementary groups
401e68cf3bfSBen Gras#				to run the chrooted ${command} with.
402e68cf3bfSBen Gras#				Requires /usr to be mounted.
403e68cf3bfSBen Gras#
404e68cf3bfSBen Gras#	${rc_arg}_cmd	n	If set, use this as the method when invoked;
405e68cf3bfSBen Gras#				Otherwise, use default command (see below)
406e68cf3bfSBen Gras#
407e68cf3bfSBen Gras#	${rc_arg}_precmd n	If set, run just before performing the
408e68cf3bfSBen Gras#				${rc_arg}_cmd method in the default
409e68cf3bfSBen Gras#				operation (i.e, after checking for required
410e68cf3bfSBen Gras#				bits and process (non)existence).
411e68cf3bfSBen Gras#				If this completes with a non-zero exit code,
412e68cf3bfSBen Gras#				don't run ${rc_arg}_cmd.
413e68cf3bfSBen Gras#
414e68cf3bfSBen Gras#	${rc_arg}_postcmd n	If set, run just after performing the
415e68cf3bfSBen Gras#				${rc_arg}_cmd method, if that method
416e68cf3bfSBen Gras#				returned a zero exit code.
417e68cf3bfSBen Gras#
418e68cf3bfSBen Gras#	required_dirs	n	If set, check for the existence of the given
419e68cf3bfSBen Gras#				directories before running the default
420e68cf3bfSBen Gras#				(re)start command.
421e68cf3bfSBen Gras#
422e68cf3bfSBen Gras#	required_files	n	If set, check for the readability of the given
423e68cf3bfSBen Gras#				files before running the default (re)start
424e68cf3bfSBen Gras#				command.
425e68cf3bfSBen Gras#
426e68cf3bfSBen Gras#	required_vars	n	If set, perform checkyesno on each of the
427e68cf3bfSBen Gras#				listed variables before running the default
428e68cf3bfSBen Gras#				(re)start command.
429e68cf3bfSBen Gras#
430e68cf3bfSBen Gras#	Default behaviour for a given argument, if no override method is
431e68cf3bfSBen Gras#	provided:
432e68cf3bfSBen Gras#
433e68cf3bfSBen Gras#	Argument	Default behaviour
434e68cf3bfSBen Gras#	--------	-----------------
435e68cf3bfSBen Gras#	start		if !running && checkyesno ${rcvar}
436e68cf3bfSBen Gras#				${command}
437e68cf3bfSBen Gras#
438e68cf3bfSBen Gras#	stop		if ${pidfile}
439e68cf3bfSBen Gras#				rc_pid=$(check_pidfile $pidfile $command)
440e68cf3bfSBen Gras#			else
441e68cf3bfSBen Gras#				rc_pid=$(check_process $command)
442e68cf3bfSBen Gras#			kill $sig_stop $rc_pid
443e68cf3bfSBen Gras#			wait_for_pids $rc_pid
444e68cf3bfSBen Gras#			($sig_stop defaults to TERM.)
445e68cf3bfSBen Gras#
446e68cf3bfSBen Gras#	reload		Similar to stop, except use $sig_reload instead,
447e68cf3bfSBen Gras#			and doesn't wait_for_pids.
448e68cf3bfSBen Gras#			$sig_reload defaults to HUP.
449e68cf3bfSBen Gras#
450e68cf3bfSBen Gras#	restart		Run `stop' then `start'.
451e68cf3bfSBen Gras#
452e68cf3bfSBen Gras#	status		Show if ${command} is running, etc.
453e68cf3bfSBen Gras#
454e68cf3bfSBen Gras#	poll		Wait for ${command} to exit.
455e68cf3bfSBen Gras#
456e68cf3bfSBen Gras#	rcvar		Display what rc.conf variable is used (if any).
457e68cf3bfSBen Gras#
458e68cf3bfSBen Gras#	Variables available to methods, and after run_rc_command() has
459e68cf3bfSBen Gras#	completed:
460e68cf3bfSBen Gras#
461e68cf3bfSBen Gras#	Variable	Purpose
462e68cf3bfSBen Gras#	--------	-------
463e68cf3bfSBen Gras#	rc_arg		Argument to command, after fast/force/one processing
464e68cf3bfSBen Gras#			performed
465e68cf3bfSBen Gras#
466e68cf3bfSBen Gras#	rc_flags	Flags to start the default command with.
467e68cf3bfSBen Gras#			Defaults to ${name}_flags, unless overridden
468e68cf3bfSBen Gras#			by $flags from the environment.
469e68cf3bfSBen Gras#			This variable may be changed by the precmd method.
470e68cf3bfSBen Gras#
471e68cf3bfSBen Gras#	rc_pid		PID of command (if appropriate)
472e68cf3bfSBen Gras#
473e68cf3bfSBen Gras#	rc_fast		Not empty if "fast" was provided (q.v.)
474e68cf3bfSBen Gras#
475e68cf3bfSBen Gras#	rc_force	Not empty if "force" was provided (q.v.)
476e68cf3bfSBen Gras#
477e68cf3bfSBen Gras#
478e68cf3bfSBen Grasrun_rc_command()
479e68cf3bfSBen Gras{
480e68cf3bfSBen Gras	rc_arg=$1
481e68cf3bfSBen Gras	if [ -z "$name" ]; then
482e68cf3bfSBen Gras		err 3 'run_rc_command: $name is not set.'
483e68cf3bfSBen Gras	fi
484e68cf3bfSBen Gras
485e68cf3bfSBen Gras	_rc_prefix=
486e68cf3bfSBen Gras	case "$rc_arg" in
487e68cf3bfSBen Gras	fast*)				# "fast" prefix; don't check pid
488e68cf3bfSBen Gras		rc_arg=${rc_arg#fast}
489e68cf3bfSBen Gras		rc_fast=yes
490e68cf3bfSBen Gras		;;
491e68cf3bfSBen Gras	force*)				# "force" prefix; always run
492e68cf3bfSBen Gras		rc_force=yes
493e68cf3bfSBen Gras		_rc_prefix=force
494e68cf3bfSBen Gras		rc_arg=${rc_arg#${_rc_prefix}}
495e68cf3bfSBen Gras		if [ -n "${rcvar}" ]; then
496e68cf3bfSBen Gras			eval ${rcvar}=YES
497e68cf3bfSBen Gras		fi
498e68cf3bfSBen Gras		;;
499e68cf3bfSBen Gras	one*)				# "one" prefix; set ${rcvar}=yes
500e68cf3bfSBen Gras		_rc_prefix=one
501e68cf3bfSBen Gras		rc_arg=${rc_arg#${_rc_prefix}}
502e68cf3bfSBen Gras		if [ -n "${rcvar}" ]; then
503e68cf3bfSBen Gras			eval ${rcvar}=YES
504e68cf3bfSBen Gras		fi
505e68cf3bfSBen Gras		;;
506e68cf3bfSBen Gras	esac
507e68cf3bfSBen Gras
508e68cf3bfSBen Gras	_keywords="start stop restart rcvar"
509e68cf3bfSBen Gras	if [ -n "$extra_commands" ]; then
510e68cf3bfSBen Gras		_keywords="${_keywords} ${extra_commands}"
511e68cf3bfSBen Gras	fi
512e68cf3bfSBen Gras	rc_pid=
513e68cf3bfSBen Gras	_pidcmd=
514e68cf3bfSBen Gras	_procname=${procname:-${command}}
515e68cf3bfSBen Gras
516e68cf3bfSBen Gras					# setup pid check command if not fast
517e68cf3bfSBen Gras	if [ -z "$rc_fast" -a -n "$_procname" ]; then
518e68cf3bfSBen Gras		if [ -n "$pidfile" ]; then
519e68cf3bfSBen Gras			_pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
520e68cf3bfSBen Gras		else
521e68cf3bfSBen Gras			_pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
522e68cf3bfSBen Gras		fi
523e68cf3bfSBen Gras		if [ -n "$_pidcmd" ]; then
524e68cf3bfSBen Gras			_keywords="${_keywords} status poll"
525e68cf3bfSBen Gras		fi
526e68cf3bfSBen Gras	fi
527e68cf3bfSBen Gras
528e68cf3bfSBen Gras	if [ -z "$rc_arg" ]; then
529e68cf3bfSBen Gras		rc_usage "$_keywords"
530e68cf3bfSBen Gras	fi
531e68cf3bfSBen Gras	shift	# remove $rc_arg from the positional parameters
532e68cf3bfSBen Gras
533e68cf3bfSBen Gras	if [ -n "$flags" ]; then	# allow override from environment
534e68cf3bfSBen Gras		rc_flags=$flags
535e68cf3bfSBen Gras	else
536e68cf3bfSBen Gras		eval rc_flags=\$${name}_flags
537e68cf3bfSBen Gras	fi
538e68cf3bfSBen Gras	eval _chdir=\$${name}_chdir	_chroot=\$${name}_chroot \
539e68cf3bfSBen Gras	    _nice=\$${name}_nice	_user=\$${name}_user \
540e68cf3bfSBen Gras	    _group=\$${name}_group	_groups=\$${name}_groups \
541e68cf3bfSBen Gras	    _env=\"\$${name}_env\"
542e68cf3bfSBen Gras
543e68cf3bfSBen Gras	if [ -n "$_user" ]; then	# unset $_user if running as that user
544e68cf3bfSBen Gras		if [ "$_user" = "$(id -un)" ]; then
545e68cf3bfSBen Gras			unset _user
546e68cf3bfSBen Gras		fi
547e68cf3bfSBen Gras	fi
548e68cf3bfSBen Gras
549e68cf3bfSBen Gras					# if ${rcvar} is set, and $1 is not
550e68cf3bfSBen Gras					# "rcvar", then run
551e68cf3bfSBen Gras					#	checkyesno ${rcvar}
552e68cf3bfSBen Gras					# and return if that failed or warn
553e68cf3bfSBen Gras					# user and exit when interactive
554e68cf3bfSBen Gras					#
555e68cf3bfSBen Gras	if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
556e68cf3bfSBen Gras		if ! checkyesno ${rcvar}; then
557e68cf3bfSBen Gras					# check whether interactive or not
558e68cf3bfSBen Gras			if [ -n "$_run_rc_script" ]; then
559e68cf3bfSBen Gras				return 0
560e68cf3bfSBen Gras			fi
561e68cf3bfSBen Gras			for _elem in $_keywords; do
562e68cf3bfSBen Gras				if [ "$_elem" = "$rc_arg" ]; then
563e68cf3bfSBen Gras					cat 1>&2 <<EOF
564e68cf3bfSBen Gras\$${rcvar} is not enabled - see ${rcvar_manpage}.
565e68cf3bfSBen GrasUse the following if you wish to perform the operation:
566e68cf3bfSBen Gras  $0 one${rc_arg}
567e68cf3bfSBen GrasEOF
568e68cf3bfSBen Gras					exit 1
569e68cf3bfSBen Gras				fi
570e68cf3bfSBen Gras			done
571e68cf3bfSBen Gras			echo 1>&2 "$0: unknown directive '$rc_arg'."
572e68cf3bfSBen Gras			rc_usage "$_keywords"
573e68cf3bfSBen Gras		fi
574e68cf3bfSBen Gras	fi
575e68cf3bfSBen Gras
576e68cf3bfSBen Gras	eval $_pidcmd			# determine the pid if necessary
577e68cf3bfSBen Gras
578e68cf3bfSBen Gras	for _elem in $_keywords; do
579e68cf3bfSBen Gras		if [ "$_elem" != "$rc_arg" ]; then
580e68cf3bfSBen Gras			continue
581e68cf3bfSBen Gras		fi
582e68cf3bfSBen Gras
583e68cf3bfSBen Gras					# if there's a custom ${XXX_cmd},
584e68cf3bfSBen Gras					# run that instead of the default
585e68cf3bfSBen Gras					#
586e68cf3bfSBen Gras		eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
587e68cf3bfSBen Gras		    _postcmd=\$${rc_arg}_postcmd
588e68cf3bfSBen Gras		if [ -n "$_cmd" ]; then
589e68cf3bfSBen Gras					# if the precmd failed and force
590e68cf3bfSBen Gras					# isn't set, exit
591e68cf3bfSBen Gras					#
592e68cf3bfSBen Gras			if ! eval $_precmd && [ -z "$rc_force" ]; then
593e68cf3bfSBen Gras				return 1
594e68cf3bfSBen Gras			fi
595e68cf3bfSBen Gras
596e68cf3bfSBen Gras			if ! eval $_cmd \"\${@}\" && [ -z "$rc_force" ]; then
597e68cf3bfSBen Gras				return 1
598e68cf3bfSBen Gras			fi
599e68cf3bfSBen Gras			eval $_postcmd
600e68cf3bfSBen Gras			return 0
601e68cf3bfSBen Gras		fi
602e68cf3bfSBen Gras
603e68cf3bfSBen Gras		if [ ${#} -gt 0 ]; then
604e68cf3bfSBen Gras			err 1 "the $rc_arg command does not take any parameters"
605e68cf3bfSBen Gras		fi
606e68cf3bfSBen Gras
607e68cf3bfSBen Gras		case "$rc_arg" in	# default operations...
608e68cf3bfSBen Gras
609e68cf3bfSBen Gras		status)
610e68cf3bfSBen Gras			if [ -n "$rc_pid" ]; then
611e68cf3bfSBen Gras				echo "${name} is running as pid $rc_pid."
612e68cf3bfSBen Gras			else
613e68cf3bfSBen Gras				echo "${name} is not running."
614e68cf3bfSBen Gras				return 1
615e68cf3bfSBen Gras			fi
616e68cf3bfSBen Gras			;;
617e68cf3bfSBen Gras
618e68cf3bfSBen Gras		start)
619e68cf3bfSBen Gras			if [ -n "$rc_pid" ]; then
620e68cf3bfSBen Gras				echo 1>&2 "${name} already running? (pid=$rc_pid)."
621e68cf3bfSBen Gras				exit 1
622e68cf3bfSBen Gras			fi
623e68cf3bfSBen Gras
624e68cf3bfSBen Gras			if [ ! -x ${_chroot}${command} ]; then
625e68cf3bfSBen Gras				return 0
626e68cf3bfSBen Gras			fi
627e68cf3bfSBen Gras
628e68cf3bfSBen Gras					# check for required variables,
629e68cf3bfSBen Gras					# directories, and files
630e68cf3bfSBen Gras					#
631e68cf3bfSBen Gras			for _f in $required_vars; do
632e68cf3bfSBen Gras				if ! checkyesno $_f; then
633e68cf3bfSBen Gras					warn "\$${_f} is not enabled."
634e68cf3bfSBen Gras					if [ -z "$rc_force" ]; then
635e68cf3bfSBen Gras						return 1
636e68cf3bfSBen Gras					fi
637e68cf3bfSBen Gras				fi
638e68cf3bfSBen Gras			done
639e68cf3bfSBen Gras			for _f in $required_dirs; do
640e68cf3bfSBen Gras				if [ ! -d "${_f}/." ]; then
641e68cf3bfSBen Gras					warn "${_f} is not a directory."
642e68cf3bfSBen Gras					if [ -z "$rc_force" ]; then
643e68cf3bfSBen Gras						return 1
644e68cf3bfSBen Gras					fi
645e68cf3bfSBen Gras				fi
646e68cf3bfSBen Gras			done
647e68cf3bfSBen Gras			for _f in $required_files; do
648e68cf3bfSBen Gras				if [ ! -r "${_f}" ]; then
649e68cf3bfSBen Gras					warn "${_f} is not readable."
650e68cf3bfSBen Gras					if [ -z "$rc_force" ]; then
651e68cf3bfSBen Gras						return 1
652e68cf3bfSBen Gras					fi
653e68cf3bfSBen Gras				fi
654e68cf3bfSBen Gras			done
655e68cf3bfSBen Gras
656e68cf3bfSBen Gras					# if the precmd failed and force
657e68cf3bfSBen Gras					# isn't set, exit
658e68cf3bfSBen Gras					#
659e68cf3bfSBen Gras			if ! eval $_precmd && [ -z "$rc_force" ]; then
660e68cf3bfSBen Gras				return 1
661e68cf3bfSBen Gras			fi
662e68cf3bfSBen Gras
663e68cf3bfSBen Gras					# setup the command to run, and run it
664e68cf3bfSBen Gras					#
665e68cf3bfSBen Gras			echo "Starting ${name}."
666e68cf3bfSBen Gras			if [ -n "$_chroot" ]; then
667e68cf3bfSBen Gras				_doit="\
668e68cf3bfSBen Gras${_env:+env $_env }\
669e68cf3bfSBen Gras${_nice:+nice -n $_nice }\
670e68cf3bfSBen Graschroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
671e68cf3bfSBen Gras$_chroot $command $rc_flags $command_args"
672e68cf3bfSBen Gras			else
673e68cf3bfSBen Gras				_doit="\
674e68cf3bfSBen Gras${_chdir:+cd $_chdir; }\
675e68cf3bfSBen Gras${_env:+env $_env }\
676e68cf3bfSBen Gras${_nice:+nice -n $_nice }\
677e68cf3bfSBen Gras$command $rc_flags $command_args"
678e68cf3bfSBen Gras				if [ -n "$_user" ]; then
679e68cf3bfSBen Gras				    _doit="su -m $_user -c 'sh -c \"$_doit\"'"
680e68cf3bfSBen Gras				fi
681e68cf3bfSBen Gras			fi
682e68cf3bfSBen Gras
683e68cf3bfSBen Gras					# if the cmd failed and force
684e68cf3bfSBen Gras					# isn't set, exit
685e68cf3bfSBen Gras					#
686e68cf3bfSBen Gras			if ! eval $_doit && [ -z "$rc_force" ]; then
687e68cf3bfSBen Gras				return 1
688e68cf3bfSBen Gras			fi
689e68cf3bfSBen Gras
690e68cf3bfSBen Gras					# finally, run postcmd
691e68cf3bfSBen Gras					#
692e68cf3bfSBen Gras			eval $_postcmd
693e68cf3bfSBen Gras			;;
694e68cf3bfSBen Gras
695e68cf3bfSBen Gras		stop)
696e68cf3bfSBen Gras			if [ -z "$rc_pid" ]; then
697e68cf3bfSBen Gras				if [ -n "$pidfile" ]; then
698e68cf3bfSBen Gras					echo 1>&2 \
699e68cf3bfSBen Gras				    "${name} not running? (check $pidfile)."
700e68cf3bfSBen Gras				else
701e68cf3bfSBen Gras					echo 1>&2 "${name} not running?"
702e68cf3bfSBen Gras				fi
703e68cf3bfSBen Gras				exit 1
704e68cf3bfSBen Gras			fi
705e68cf3bfSBen Gras
706e68cf3bfSBen Gras					# if the precmd failed and force
707e68cf3bfSBen Gras					# isn't set, exit
708e68cf3bfSBen Gras					#
709e68cf3bfSBen Gras			if ! eval $_precmd && [ -z "$rc_force" ]; then
710e68cf3bfSBen Gras				return 1
711e68cf3bfSBen Gras			fi
712e68cf3bfSBen Gras
713e68cf3bfSBen Gras					# send the signal to stop
714e68cf3bfSBen Gras					#
715e68cf3bfSBen Gras			echo "Stopping ${name}."
716e68cf3bfSBen Gras			_doit="kill -${sig_stop:-TERM} $rc_pid"
717e68cf3bfSBen Gras			if [ -n "$_user" ]; then
718e68cf3bfSBen Gras				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
719e68cf3bfSBen Gras			fi
720e68cf3bfSBen Gras
721e68cf3bfSBen Gras					# if the stop cmd failed and force
722e68cf3bfSBen Gras					# isn't set, exit
723e68cf3bfSBen Gras					#
724e68cf3bfSBen Gras			if ! eval $_doit && [ -z "$rc_force" ]; then
725e68cf3bfSBen Gras				return 1
726e68cf3bfSBen Gras			fi
727e68cf3bfSBen Gras
728e68cf3bfSBen Gras					# wait for the command to exit,
729e68cf3bfSBen Gras					# and run postcmd.
730e68cf3bfSBen Gras			wait_for_pids $rc_pid
731e68cf3bfSBen Gras			eval $_postcmd
732e68cf3bfSBen Gras			;;
733e68cf3bfSBen Gras
734e68cf3bfSBen Gras		reload)
735e68cf3bfSBen Gras			if [ -z "$rc_pid" ]; then
736e68cf3bfSBen Gras				if [ -n "$pidfile" ]; then
737e68cf3bfSBen Gras					echo 1>&2 \
738e68cf3bfSBen Gras				    "${name} not running? (check $pidfile)."
739e68cf3bfSBen Gras				else
740e68cf3bfSBen Gras					echo 1>&2 "${name} not running?"
741e68cf3bfSBen Gras				fi
742e68cf3bfSBen Gras				exit 1
743e68cf3bfSBen Gras			fi
744e68cf3bfSBen Gras			echo "Reloading ${name} config files."
745e68cf3bfSBen Gras			if ! eval $_precmd && [ -z "$rc_force" ]; then
746e68cf3bfSBen Gras				return 1
747e68cf3bfSBen Gras			fi
748e68cf3bfSBen Gras			_doit="kill -${sig_reload:-HUP} $rc_pid"
749e68cf3bfSBen Gras			if [ -n "$_user" ]; then
750e68cf3bfSBen Gras				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
751e68cf3bfSBen Gras			fi
752e68cf3bfSBen Gras			if ! eval $_doit && [ -z "$rc_force" ]; then
753e68cf3bfSBen Gras				return 1
754e68cf3bfSBen Gras			fi
755e68cf3bfSBen Gras			eval $_postcmd
756e68cf3bfSBen Gras			;;
757e68cf3bfSBen Gras
758e68cf3bfSBen Gras		restart)
759e68cf3bfSBen Gras			if ! eval $_precmd && [ -z "$rc_force" ]; then
760e68cf3bfSBen Gras				return 1
761e68cf3bfSBen Gras			fi
762e68cf3bfSBen Gras					# prevent restart being called more
763e68cf3bfSBen Gras					# than once by any given script
764e68cf3bfSBen Gras					#
765e68cf3bfSBen Gras			if ${_rc_restart_done:-false}; then
766e68cf3bfSBen Gras				return 0
767e68cf3bfSBen Gras			fi
768e68cf3bfSBen Gras			_rc_restart_done=true
769e68cf3bfSBen Gras
770e68cf3bfSBen Gras			( $0 ${_rc_prefix}stop )
771e68cf3bfSBen Gras			$0 ${_rc_prefix}start
772e68cf3bfSBen Gras
773e68cf3bfSBen Gras			eval $_postcmd
774e68cf3bfSBen Gras			;;
775e68cf3bfSBen Gras
776e68cf3bfSBen Gras		poll)
777e68cf3bfSBen Gras			if [ -n "$rc_pid" ]; then
778e68cf3bfSBen Gras				wait_for_pids $rc_pid
779e68cf3bfSBen Gras			fi
780e68cf3bfSBen Gras			;;
781e68cf3bfSBen Gras
782e68cf3bfSBen Gras		rcvar)
783e68cf3bfSBen Gras			echo "# $name"
784e68cf3bfSBen Gras			if [ -n "$rcvar" ]; then
785e68cf3bfSBen Gras				if checkyesno ${rcvar}; then
786e68cf3bfSBen Gras					echo "\$${rcvar}=YES"
787e68cf3bfSBen Gras				else
788e68cf3bfSBen Gras					echo "\$${rcvar}=NO"
789e68cf3bfSBen Gras				fi
790e68cf3bfSBen Gras			fi
791e68cf3bfSBen Gras			;;
792e68cf3bfSBen Gras
793e68cf3bfSBen Gras		*)
794e68cf3bfSBen Gras			rc_usage "$_keywords"
795e68cf3bfSBen Gras			;;
796e68cf3bfSBen Gras
797e68cf3bfSBen Gras		esac
798e68cf3bfSBen Gras		return 0
799e68cf3bfSBen Gras	done
800e68cf3bfSBen Gras
801e68cf3bfSBen Gras	echo 1>&2 "$0: unknown directive '$rc_arg'."
802e68cf3bfSBen Gras	rc_usage "$_keywords"
803e68cf3bfSBen Gras	exit 1
804e68cf3bfSBen Gras}
805e68cf3bfSBen Gras
806e68cf3bfSBen Gras#
8070a6a1f1dSLionel Sambuc# _have_rc_postprocessor
8080a6a1f1dSLionel Sambuc#	Test whether the current script is running in a context that
8090a6a1f1dSLionel Sambuc#	was invoked from /etc/rc with a postprocessor.
8100a6a1f1dSLionel Sambuc#
8110a6a1f1dSLionel Sambuc#	If the test fails, some variables may be unset to make
8120a6a1f1dSLionel Sambuc#	such tests more efficient in future.
8130a6a1f1dSLionel Sambuc#
8140a6a1f1dSLionel Sambuc_have_rc_postprocessor()
8150a6a1f1dSLionel Sambuc{
8160a6a1f1dSLionel Sambuc	# Cheap tests that fd and pid are set, fd is writable.
8170a6a1f1dSLionel Sambuc	[ -n "${_rc_postprocessor_fd}" ] || return 1
8180a6a1f1dSLionel Sambuc	[ -n "${_rc_pid}" ] || return 1
8190a6a1f1dSLionel Sambuc	eval ": >&${_rc_postprocessor_fd}" 2>/dev/null || return 1
8200a6a1f1dSLionel Sambuc
8210a6a1f1dSLionel Sambuc	# More expensive test that pid is running.
8220a6a1f1dSLionel Sambuc	# Unset _rc_pid if this fails.
8230a6a1f1dSLionel Sambuc	kill -0 "${_rc_pid}" 2>/dev/null \
8240a6a1f1dSLionel Sambuc	|| { unset _rc_pid; return 1; }
8250a6a1f1dSLionel Sambuc
8260a6a1f1dSLionel Sambuc	# More expensive test that pid appears to be
8270a6a1f1dSLionel Sambuc	# a shell running an rc script.
8280a6a1f1dSLionel Sambuc	# Unset _rc_pid if this fails.
8290a6a1f1dSLionel Sambuc	expr "$(ps -p "${_rc_pid}" -o command=)" : ".*sh .*/rc.*" >/dev/null \
8300a6a1f1dSLionel Sambuc	|| { unset _rc_pid; return 1; }
8310a6a1f1dSLionel Sambuc
8320a6a1f1dSLionel Sambuc	return 0
8330a6a1f1dSLionel Sambuc}
8340a6a1f1dSLionel Sambuc
8350a6a1f1dSLionel Sambuc#
836e68cf3bfSBen Gras# run_rc_script file arg
837e68cf3bfSBen Gras#	Start the script `file' with `arg', and correctly handle the
838e68cf3bfSBen Gras#	return value from the script.  If `file' ends with `.sh', it's
839e68cf3bfSBen Gras#	sourced into the current environment.  If `file' appears to be
840e68cf3bfSBen Gras#	a backup or scratch file, ignore it.  Otherwise if it's
841e68cf3bfSBen Gras#	executable run as a child process.
842e68cf3bfSBen Gras#
843e68cf3bfSBen Gras#	If `file' contains "KEYWORD: interactive" and if we are
8440a6a1f1dSLionel Sambuc#	running inside /etc/rc with postprocessing, then the script's
8450a6a1f1dSLionel Sambuc#	stdout and stderr are redirected to $_rc_original_stdout_fd and
846e68cf3bfSBen Gras#	$_rc_original_stderr_fd, so the output will be displayed on the
847e68cf3bfSBen Gras#	console but not intercepted by /etc/rc's postprocessor.
848e68cf3bfSBen Gras#
849e68cf3bfSBen Grasrun_rc_script()
850e68cf3bfSBen Gras{
851e68cf3bfSBen Gras	_file=$1
852e68cf3bfSBen Gras	_arg=$2
853e68cf3bfSBen Gras	if [ -z "$_file" -o -z "$_arg" ]; then
854e68cf3bfSBen Gras		err 3 'USAGE: run_rc_script file arg'
855e68cf3bfSBen Gras	fi
856e68cf3bfSBen Gras
857e68cf3bfSBen Gras	_run_rc_script=true
858e68cf3bfSBen Gras
859e68cf3bfSBen Gras	unset	name command command_args command_interpreter \
860e68cf3bfSBen Gras		extra_commands pidfile procname \
861e68cf3bfSBen Gras		rcvar required_dirs required_files required_vars
862e68cf3bfSBen Gras	eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
863e68cf3bfSBen Gras
864e68cf3bfSBen Gras	_must_redirect=false
8650a6a1f1dSLionel Sambuc	if _have_rc_postprocessor \
866e68cf3bfSBen Gras	    && _has_rcorder_keyword interactive $_file
867e68cf3bfSBen Gras	then
868e68cf3bfSBen Gras		_must_redirect=true
869e68cf3bfSBen Gras	fi
870e68cf3bfSBen Gras
871e68cf3bfSBen Gras	case "$_file" in
872e68cf3bfSBen Gras	*.sh)				# run in current shell
873e68cf3bfSBen Gras		if $_must_redirect; then
874e68cf3bfSBen Gras			print_rc_metadata \
875e68cf3bfSBen Gras			    "note:Output from ${_file} is not logged"
876e68cf3bfSBen Gras			no_rc_postprocess eval \
877e68cf3bfSBen Gras			    'set $_arg ; . $_file'
878e68cf3bfSBen Gras		else
879e68cf3bfSBen Gras			set $_arg ; . $_file
880e68cf3bfSBen Gras		fi
881e68cf3bfSBen Gras		;;
882e68cf3bfSBen Gras	*[~#]|*.OLD|*.orig|*,v)		# scratch file; skip
883e68cf3bfSBen Gras		warn "Ignoring scratch file $_file"
884e68cf3bfSBen Gras		;;
885e68cf3bfSBen Gras	*)				# run in subshell
886e68cf3bfSBen Gras		if [ -x $_file ] && $_must_redirect; then
887e68cf3bfSBen Gras			print_rc_metadata \
888e68cf3bfSBen Gras			    "note:Output from ${_file} is not logged"
889e68cf3bfSBen Gras			if [ -n "$rc_fast_and_loose" ]; then
890e68cf3bfSBen Gras				no_rc_postprocess eval \
891e68cf3bfSBen Gras				    'set $_arg ; . $_file'
892e68cf3bfSBen Gras			else
893e68cf3bfSBen Gras				no_rc_postprocess eval \
894e68cf3bfSBen Gras				    '( set $_arg ; . $_file )'
895e68cf3bfSBen Gras			fi
896e68cf3bfSBen Gras		elif [ -x $_file ]; then
897e68cf3bfSBen Gras			if [ -n "$rc_fast_and_loose" ]; then
898e68cf3bfSBen Gras				set $_arg ; . $_file
899e68cf3bfSBen Gras			else
900e68cf3bfSBen Gras				( set $_arg ; . $_file )
901e68cf3bfSBen Gras			fi
902e68cf3bfSBen Gras		else
903e68cf3bfSBen Gras			warn "Ignoring non-executable file $_file"
904e68cf3bfSBen Gras		fi
905e68cf3bfSBen Gras		;;
906e68cf3bfSBen Gras	esac
907e68cf3bfSBen Gras}
908e68cf3bfSBen Gras
909e68cf3bfSBen Gras#
910e68cf3bfSBen Gras# load_rc_config command
911e68cf3bfSBen Gras#	Source in the configuration file for a given command.
912e68cf3bfSBen Gras#
913e68cf3bfSBen Grasload_rc_config()
914e68cf3bfSBen Gras{
915e68cf3bfSBen Gras	_command=$1
916e68cf3bfSBen Gras	if [ -z "$_command" ]; then
917e68cf3bfSBen Gras		err 3 'USAGE: load_rc_config command'
918e68cf3bfSBen Gras	fi
919e68cf3bfSBen Gras
920e68cf3bfSBen Gras	if ${_rc_conf_loaded:-false}; then
921e68cf3bfSBen Gras		:
922e68cf3bfSBen Gras	else
923e68cf3bfSBen Gras		. /etc/rc.conf
924e68cf3bfSBen Gras		_rc_conf_loaded=true
925e68cf3bfSBen Gras	fi
926e68cf3bfSBen Gras	if [ -f /etc/rc.conf.d/"$_command" ]; then
927e68cf3bfSBen Gras		. /etc/rc.conf.d/"$_command"
928e68cf3bfSBen Gras	fi
929e68cf3bfSBen Gras}
930e68cf3bfSBen Gras
931e68cf3bfSBen Gras#
932e68cf3bfSBen Gras# load_rc_config_var cmd var
933e68cf3bfSBen Gras#	Read the rc.conf(5) var for cmd and set in the
934e68cf3bfSBen Gras#	current shell, using load_rc_config in a subshell to prevent
935e68cf3bfSBen Gras#	unwanted side effects from other variable assignments.
936e68cf3bfSBen Gras#
937e68cf3bfSBen Grasload_rc_config_var()
938e68cf3bfSBen Gras{
939e68cf3bfSBen Gras	if [ $# -ne 2 ]; then
940e68cf3bfSBen Gras		err 3 'USAGE: load_rc_config_var cmd var'
941e68cf3bfSBen Gras	fi
942e68cf3bfSBen Gras	eval $(eval '(
943e68cf3bfSBen Gras		load_rc_config '$1' >/dev/null;
944e68cf3bfSBen Gras		if [ -n "${'$2'}" -o "${'$2'-UNSET}" != "UNSET" ]; then
945e68cf3bfSBen Gras			echo '$2'=\'\''${'$2'}\'\'';
946e68cf3bfSBen Gras		fi
947e68cf3bfSBen Gras	)' )
948e68cf3bfSBen Gras}
949e68cf3bfSBen Gras
950e68cf3bfSBen Gras#
951e68cf3bfSBen Gras# rc_usage commands
952e68cf3bfSBen Gras#	Print a usage string for $0, with `commands' being a list of
953e68cf3bfSBen Gras#	valid commands.
954e68cf3bfSBen Gras#
955e68cf3bfSBen Grasrc_usage()
956e68cf3bfSBen Gras{
957e68cf3bfSBen Gras	echo -n 1>&2 "Usage: $0 [fast|force|one]("
958e68cf3bfSBen Gras
959e68cf3bfSBen Gras	_sep=
960e68cf3bfSBen Gras	for _elem; do
961e68cf3bfSBen Gras		echo -n 1>&2 "$_sep$_elem"
962e68cf3bfSBen Gras		_sep="|"
963e68cf3bfSBen Gras	done
964e68cf3bfSBen Gras	echo 1>&2 ")"
965e68cf3bfSBen Gras	exit 1
966e68cf3bfSBen Gras}
967e68cf3bfSBen Gras
968e68cf3bfSBen Gras#
969e68cf3bfSBen Gras# err exitval message
970e68cf3bfSBen Gras#	Display message to stderr and log to the syslog, and exit with exitval.
971e68cf3bfSBen Gras#
972e68cf3bfSBen Graserr()
973e68cf3bfSBen Gras{
974e68cf3bfSBen Gras	exitval=$1
975e68cf3bfSBen Gras	shift
976e68cf3bfSBen Gras
977e68cf3bfSBen Gras	if [ -x /usr/bin/logger ]; then
978e68cf3bfSBen Gras		logger "$0: ERROR: $*"
979e68cf3bfSBen Gras	fi
980e68cf3bfSBen Gras	echo 1>&2 "$0: ERROR: $*"
981e68cf3bfSBen Gras	exit $exitval
982e68cf3bfSBen Gras}
983e68cf3bfSBen Gras
984e68cf3bfSBen Gras#
985e68cf3bfSBen Gras# warn message
986e68cf3bfSBen Gras#	Display message to stderr and log to the syslog.
987e68cf3bfSBen Gras#
988e68cf3bfSBen Graswarn()
989e68cf3bfSBen Gras{
990e68cf3bfSBen Gras	if [ -x /usr/bin/logger ]; then
991e68cf3bfSBen Gras		logger "$0: WARNING: $*"
992e68cf3bfSBen Gras	fi
993e68cf3bfSBen Gras	echo 1>&2 "$0: WARNING: $*"
994e68cf3bfSBen Gras}
995e68cf3bfSBen Gras
996e68cf3bfSBen Gras#
997e68cf3bfSBen Gras# backup_file action file cur backup
998e68cf3bfSBen Gras#	Make a backup copy of `file' into `cur', and save the previous
999e68cf3bfSBen Gras#	version of `cur' as `backup' or use rcs for archiving.
1000e68cf3bfSBen Gras#
1001e68cf3bfSBen Gras#	This routine checks the value of the backup_uses_rcs variable,
1002e68cf3bfSBen Gras#	which can be either YES or NO.
1003e68cf3bfSBen Gras#
1004e68cf3bfSBen Gras#	The `action' keyword can be one of the following:
1005e68cf3bfSBen Gras#
1006e68cf3bfSBen Gras#	add		`file' is now being backed up (and is possibly
1007e68cf3bfSBen Gras#			being reentered into the backups system).  `cur'
1008e68cf3bfSBen Gras#			is created and RCS files, if necessary, are
1009e68cf3bfSBen Gras#			created as well.
1010e68cf3bfSBen Gras#
1011e68cf3bfSBen Gras#	update		`file' has changed and needs to be backed up.
1012e68cf3bfSBen Gras#			If `cur' exists, it is copied to to `back' or
1013e68cf3bfSBen Gras#			checked into RCS (if the repository file is old),
1014e68cf3bfSBen Gras#			and then `file' is copied to `cur'.  Another RCS
1015e68cf3bfSBen Gras#			check in done here if RCS is being used.
1016e68cf3bfSBen Gras#
1017e68cf3bfSBen Gras#	remove		`file' is no longer being tracked by the backups
1018e68cf3bfSBen Gras#			system.  If RCS is not being used, `cur' is moved
1019e68cf3bfSBen Gras#			to `back', otherwise an empty file is checked in,
1020e68cf3bfSBen Gras#			and then `cur' is removed.
1021e68cf3bfSBen Gras#
1022e68cf3bfSBen Gras#
1023e68cf3bfSBen Grasbackup_file()
1024e68cf3bfSBen Gras{
1025e68cf3bfSBen Gras	_action=$1
1026e68cf3bfSBen Gras	_file=$2
1027e68cf3bfSBen Gras	_cur=$3
1028e68cf3bfSBen Gras	_back=$4
1029e68cf3bfSBen Gras
1030e68cf3bfSBen Gras	if checkyesno backup_uses_rcs; then
1031e68cf3bfSBen Gras		_msg0="backup archive"
1032e68cf3bfSBen Gras		_msg1="update"
1033e68cf3bfSBen Gras
1034e68cf3bfSBen Gras		# ensure that history file is not locked
1035e68cf3bfSBen Gras		if [ -f $_cur,v ]; then
1036e68cf3bfSBen Gras			rcs -q -u -U -M $_cur
1037e68cf3bfSBen Gras		fi
1038e68cf3bfSBen Gras
1039e68cf3bfSBen Gras		# ensure after switching to rcs that the
1040e68cf3bfSBen Gras		# current backup is not lost
1041e68cf3bfSBen Gras		if [ -f $_cur ]; then
1042e68cf3bfSBen Gras			# no archive, or current newer than archive
1043e68cf3bfSBen Gras			if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
1044e68cf3bfSBen Gras				ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1045e68cf3bfSBen Gras				rcs -q -kb -U $_cur
1046e68cf3bfSBen Gras				co -q -f -u $_cur
1047e68cf3bfSBen Gras			fi
1048e68cf3bfSBen Gras		fi
1049e68cf3bfSBen Gras
1050e68cf3bfSBen Gras		case $_action in
1051e68cf3bfSBen Gras		add|update)
1052e68cf3bfSBen Gras			cp -p $_file $_cur
1053e68cf3bfSBen Gras			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1054e68cf3bfSBen Gras			rcs -q -kb -U $_cur
1055e68cf3bfSBen Gras			co -q -f -u $_cur
1056*77e79d33SDavid van Moolenbroek			chown root:wheel $_cur $_cur,v
1057e68cf3bfSBen Gras			;;
1058e68cf3bfSBen Gras		remove)
1059e68cf3bfSBen Gras			cp /dev/null $_cur
1060e68cf3bfSBen Gras			ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1061e68cf3bfSBen Gras			rcs -q -kb -U $_cur
1062*77e79d33SDavid van Moolenbroek			chown root:wheel $_cur $_cur,v
1063e68cf3bfSBen Gras			rm $_cur
1064e68cf3bfSBen Gras			;;
1065e68cf3bfSBen Gras		esac
1066e68cf3bfSBen Gras	else
1067e68cf3bfSBen Gras		case $_action in
1068e68cf3bfSBen Gras		add|update)
1069e68cf3bfSBen Gras			if [ -f $_cur ]; then
1070e68cf3bfSBen Gras				cp -p $_cur $_back
1071e68cf3bfSBen Gras			fi
1072e68cf3bfSBen Gras			cp -p $_file $_cur
1073*77e79d33SDavid van Moolenbroek			chown root:wheel $_cur
1074e68cf3bfSBen Gras			;;
1075e68cf3bfSBen Gras		remove)
1076e68cf3bfSBen Gras			mv -f $_cur $_back
1077e68cf3bfSBen Gras			;;
1078e68cf3bfSBen Gras		esac
1079e68cf3bfSBen Gras	fi
1080e68cf3bfSBen Gras}
1081e68cf3bfSBen Gras
1082e68cf3bfSBen Gras#
1083e68cf3bfSBen Gras# handle_fsck_error fsck_exit_code
1084e68cf3bfSBen Gras#	Take action depending on the return code from fsck.
1085e68cf3bfSBen Gras#
1086e68cf3bfSBen Grashandle_fsck_error()
1087e68cf3bfSBen Gras{
1088e68cf3bfSBen Gras	case $1 in
1089e68cf3bfSBen Gras	0)	# OK
1090e68cf3bfSBen Gras		return
1091e68cf3bfSBen Gras		;;
1092e68cf3bfSBen Gras	2)	# Needs re-run, still fs errors
1093e68cf3bfSBen Gras		echo "File system still has errors; re-run fsck manually!"
1094e68cf3bfSBen Gras		;;
1095e68cf3bfSBen Gras	4)	# Root modified
1096e68cf3bfSBen Gras		echo "Root file system was modified, rebooting ..."
1097e68cf3bfSBen Gras		reboot -n
1098e68cf3bfSBen Gras		echo "Reboot failed; help!"
1099e68cf3bfSBen Gras		;;
1100e68cf3bfSBen Gras	8)	# Check failed
1101e68cf3bfSBen Gras		echo "Automatic file system check failed; help!"
1102e68cf3bfSBen Gras		;;
1103e68cf3bfSBen Gras	12)	# Got signal
1104e68cf3bfSBen Gras		echo "Boot interrupted."
1105e68cf3bfSBen Gras		;;
1106e68cf3bfSBen Gras	*)
1107e68cf3bfSBen Gras		echo "Unknown error $1; help!"
1108e68cf3bfSBen Gras		;;
1109e68cf3bfSBen Gras	esac
1110e68cf3bfSBen Gras	stop_boot
1111e68cf3bfSBen Gras}
1112e68cf3bfSBen Gras
1113e68cf3bfSBen Gras#
1114e68cf3bfSBen Gras# _has_rcorder_keyword word file
1115e68cf3bfSBen Gras#	Check whether a file contains a "# KEYWORD:" comment with a
1116e68cf3bfSBen Gras#	specified keyword in the style used by rcorder(8).
1117e68cf3bfSBen Gras#
1118e68cf3bfSBen Gras_has_rcorder_keyword()
1119e68cf3bfSBen Gras{
1120e68cf3bfSBen Gras	local word="$1"
1121e68cf3bfSBen Gras	local file="$2"
1122e68cf3bfSBen Gras	local line
1123e68cf3bfSBen Gras
1124e68cf3bfSBen Gras	[ -r "$file" ] || return 1
1125e68cf3bfSBen Gras	while read line; do
1126e68cf3bfSBen Gras		case "${line} " in
1127e68cf3bfSBen Gras		"# KEYWORD:"*[\ \	]"${word}"[\ \	]*)
1128e68cf3bfSBen Gras			return 0
1129e68cf3bfSBen Gras			;;
1130e68cf3bfSBen Gras		"#"*)
1131e68cf3bfSBen Gras			continue
1132e68cf3bfSBen Gras			;;
1133e68cf3bfSBen Gras		*[A-Za-z0-9]*)
1134e68cf3bfSBen Gras			# give up at the first non-empty non-comment line
1135e68cf3bfSBen Gras			return 1
1136e68cf3bfSBen Gras			;;
1137e68cf3bfSBen Gras		esac
1138e68cf3bfSBen Gras	done <"$file"
1139e68cf3bfSBen Gras	return 1
1140e68cf3bfSBen Gras}
1141e68cf3bfSBen Gras
1142e68cf3bfSBen Gras#
1143e68cf3bfSBen Gras# print_rc_metadata string
1144e68cf3bfSBen Gras#	Print the specified string in such a way that the post-processor
1145e68cf3bfSBen Gras#	inside /etc/rc will treat it as meta-data.
1146e68cf3bfSBen Gras#
1147e68cf3bfSBen Gras#	If we are not running inside /etc/rc, do nothing.
1148e68cf3bfSBen Gras#
1149e68cf3bfSBen Gras#	For public use by any rc.d script, the string must begin with
1150e68cf3bfSBen Gras#	"note:", followed by arbitrary text.  The intent is that the text
1151e68cf3bfSBen Gras#	will appear in a log file but not on the console.
1152e68cf3bfSBen Gras#
1153e68cf3bfSBen Gras#	For private use within /etc/rc, the string must contain a
1154e68cf3bfSBen Gras#	keyword recognised by the rc_postprocess_metadata() function
1155e68cf3bfSBen Gras#	defined in /etc/rc, followed by a colon, followed by one or more
1156e68cf3bfSBen Gras#	colon-separated arguments associated with the keyword.
1157e68cf3bfSBen Gras#
1158e68cf3bfSBen Grasprint_rc_metadata()
1159e68cf3bfSBen Gras{
1160e68cf3bfSBen Gras	# _rc_postprocessor fd, if defined, is the fd to which we must
1161e68cf3bfSBen Gras	# print, prefixing the output with $_rc_metadata_prefix.
1162e68cf3bfSBen Gras	#
11630a6a1f1dSLionel Sambuc	if _have_rc_postprocessor; then
1164e68cf3bfSBen Gras		command printf "%s%s\n" "$rc_metadata_prefix" "$1" \
1165e68cf3bfSBen Gras			>&${_rc_postprocessor_fd}
1166e68cf3bfSBen Gras	fi
1167e68cf3bfSBen Gras}
1168e68cf3bfSBen Gras
1169e68cf3bfSBen Gras#
1170e68cf3bfSBen Gras# _flush_rc_output
1171e68cf3bfSBen Gras#	Arrange for output to be flushed, if we are running
1172e68cf3bfSBen Gras#	inside /etc/rc with postprocessing.
1173e68cf3bfSBen Gras#
1174e68cf3bfSBen Gras_flush_rc_output()
1175e68cf3bfSBen Gras{
1176e68cf3bfSBen Gras	print_rc_metadata "nop"
1177e68cf3bfSBen Gras}
1178e68cf3bfSBen Gras
1179e68cf3bfSBen Gras#
1180e68cf3bfSBen Gras# print_rc_normal [-n] string
1181e68cf3bfSBen Gras#	Print the specified string in such way that it is treated as
1182e68cf3bfSBen Gras#	normal output, regardless of whether or not we are running
1183e68cf3bfSBen Gras#	inside /etc/rc with post-processing.
1184e68cf3bfSBen Gras#
1185e68cf3bfSBen Gras#	If "-n" is specified in $1, then the string in $2 is printed
1186e68cf3bfSBen Gras#	without a newline; otherwise, the string in $1 is printed
1187e68cf3bfSBen Gras#	with a newline.
1188e68cf3bfSBen Gras#
1189e68cf3bfSBen Gras#	Intended use cases include:
1190e68cf3bfSBen Gras#
1191e68cf3bfSBen Gras#	o   An rc.d script can use ``print_rc_normal -n'' to print a
1192e68cf3bfSBen Gras#	    partial line in such a way that it appears immediately
1193e68cf3bfSBen Gras#	    instead of being buffered by rc(8)'s post-processor.
1194e68cf3bfSBen Gras#
1195e68cf3bfSBen Gras#	o   An rc.d script that is run via the no_rc_postprocess
1196e68cf3bfSBen Gras#	    function (so most of its output is invisible to rc(8)'s
1197e68cf3bfSBen Gras#	    post-processor) can use print_rc_normal to force some of its
1198e68cf3bfSBen Gras#	    output to be seen by the post-processor.
1199e68cf3bfSBen Gras#
1200e68cf3bfSBen Gras#
1201e68cf3bfSBen Grasprint_rc_normal()
1202e68cf3bfSBen Gras{
12030a6a1f1dSLionel Sambuc	# print to stdout or _rc_postprocessor_fd, depending on
12040a6a1f1dSLionel Sambuc	# whether not we have an rc postprocessor.
1205e68cf3bfSBen Gras	#
12060a6a1f1dSLionel Sambuc	local fd=1
12070a6a1f1dSLionel Sambuc	_have_rc_postprocessor && fd="${_rc_postprocessor_fd}"
1208e68cf3bfSBen Gras	case "$1" in
1209e68cf3bfSBen Gras	"-n")
1210e68cf3bfSBen Gras		command printf "%s" "$2" >&${fd}
1211e68cf3bfSBen Gras		_flush_rc_output
1212e68cf3bfSBen Gras		;;
1213e68cf3bfSBen Gras	*)
1214e68cf3bfSBen Gras		command printf "%s\n" "$1" >&${fd}
1215e68cf3bfSBen Gras		;;
1216e68cf3bfSBen Gras	esac
1217e68cf3bfSBen Gras}
1218e68cf3bfSBen Gras
1219e68cf3bfSBen Gras#
1220e68cf3bfSBen Gras# no_rc_postprocess cmd...
1221e68cf3bfSBen Gras#	Execute the specified command in such a way that its output
1222e68cf3bfSBen Gras#	bypasses the post-processor that handles the output from
1223e68cf3bfSBen Gras#	most commands that are run inside /etc/rc.  If we are not
1224e68cf3bfSBen Gras#	inside /etc/rc, then just execute the command without special
1225e68cf3bfSBen Gras#	treatment.
1226e68cf3bfSBen Gras#
1227e68cf3bfSBen Gras#	The intent is that interactive commands can be run via
1228e68cf3bfSBen Gras#	no_rc_postprocess(), and their output will apear immediately
1229e68cf3bfSBen Gras#	on the console instead of being hidden or delayed by the
1230e68cf3bfSBen Gras#	post-processor.	 An unfortunate consequence of the output
1231e68cf3bfSBen Gras#	bypassing the post-processor is that the output will not be
1232e68cf3bfSBen Gras#	logged.
1233e68cf3bfSBen Gras#
1234e68cf3bfSBen Grasno_rc_postprocess()
1235e68cf3bfSBen Gras{
12360a6a1f1dSLionel Sambuc	if _have_rc_postprocessor; then
1237e68cf3bfSBen Gras		"$@" >&${_rc_original_stdout_fd} 2>&${_rc_original_stderr_fd}
1238e68cf3bfSBen Gras	else
1239e68cf3bfSBen Gras		"$@"
1240e68cf3bfSBen Gras	fi
1241e68cf3bfSBen Gras}
1242e68cf3bfSBen Gras
1243e68cf3bfSBen Gras#
1244e68cf3bfSBen Gras# twiddle
1245e68cf3bfSBen Gras#	On each call, print a different one of "/", "-", "\\", "|",
1246e68cf3bfSBen Gras#	followed by a backspace.  The most recently printed value is
1247e68cf3bfSBen Gras#	saved in $_twiddle_state.
1248e68cf3bfSBen Gras#
1249e68cf3bfSBen Gras#	Output is to /dev/tty, so this function may be useful even inside
1250e68cf3bfSBen Gras#	a script whose output is redirected.
1251e68cf3bfSBen Gras#
1252e68cf3bfSBen Grastwiddle()
1253e68cf3bfSBen Gras{
1254e68cf3bfSBen Gras	case "$_twiddle_state" in
1255e68cf3bfSBen Gras	'/')	_next='-' ;;
1256e68cf3bfSBen Gras	'-')	_next='\' ;;
1257e68cf3bfSBen Gras	'\')	_next='|' ;;
1258e68cf3bfSBen Gras	*)	_next='/' ;;
1259e68cf3bfSBen Gras	esac
1260e68cf3bfSBen Gras	command printf "%s\b" "$_next" >/dev/tty
1261e68cf3bfSBen Gras	_twiddle_state="$_next"
1262e68cf3bfSBen Gras}
1263e68cf3bfSBen Gras
1264e68cf3bfSBen Gras#
1265e68cf3bfSBen Gras# human_exit_code
1266e68cf3bfSBen Gras#	Print the a human version of the exit code.
1267e68cf3bfSBen Gras#
1268e68cf3bfSBen Grashuman_exit_code()
1269e68cf3bfSBen Gras{
1270e68cf3bfSBen Gras	if [ "$1" -lt 127 ]
1271e68cf3bfSBen Gras	then
1272e68cf3bfSBen Gras		echo "exited with code $1"
1273e68cf3bfSBen Gras	elif [ "$(expr $1 % 256)" -eq 127 ]
1274e68cf3bfSBen Gras	then
1275e68cf3bfSBen Gras		# This cannot really happen because the shell will not
1276e68cf3bfSBen Gras		# pass stopped job status out and the exit code is limited
1277e68cf3bfSBen Gras		# to 8 bits. This code is here just for completeness.
1278e68cf3bfSBen Gras		echo "stopped with signal $(expr $1 / 256)"
1279e68cf3bfSBen Gras	else
1280e68cf3bfSBen Gras		echo "terminated with signal $(expr $1 - 128)"
1281e68cf3bfSBen Gras	fi
1282e68cf3bfSBen Gras}
1283e68cf3bfSBen Gras
1284e68cf3bfSBen Gras#
1285e68cf3bfSBen Gras# collapse_backslash_newline
1286e68cf3bfSBen Gras#	Copy input to output, collapsing <backslash><newline>
1287e68cf3bfSBen Gras#	to nothing, but leaving other backslashes alone.
1288e68cf3bfSBen Gras#
1289e68cf3bfSBen Grascollapse_backslash_newline()
1290e68cf3bfSBen Gras{
1291e68cf3bfSBen Gras	local line
1292e68cf3bfSBen Gras	while read -r line ; do
1293e68cf3bfSBen Gras		case "$line" in
1294e68cf3bfSBen Gras		*\\)
1295e68cf3bfSBen Gras			# print it, without the backslash or newline
1296e68cf3bfSBen Gras			command printf "%s" "${line%?}"
1297e68cf3bfSBen Gras			;;
1298e68cf3bfSBen Gras		*)
1299e68cf3bfSBen Gras			# print it, with a newline
1300e68cf3bfSBen Gras			command printf "%s\n" "${line}"
1301e68cf3bfSBen Gras			;;
1302e68cf3bfSBen Gras		esac
1303e68cf3bfSBen Gras	done
1304e68cf3bfSBen Gras}
1305e68cf3bfSBen Gras
130684d9c625SLionel Sambuc# Shell implementations of basename and dirname, usable before
130784d9c625SLionel Sambuc# the /usr file system is mounted.
130884d9c625SLionel Sambuc#
130984d9c625SLionel Sambucbasename()
131084d9c625SLionel Sambuc{
131184d9c625SLionel Sambuc	local file="$1"
131284d9c625SLionel Sambuc	local suffix="$2"
131384d9c625SLionel Sambuc	local base
131484d9c625SLionel Sambuc
131584d9c625SLionel Sambuc	base="${file##*/}"		# remove up to and including last '/'
131684d9c625SLionel Sambuc	base="${base%${suffix}}"	# remove suffix, if any
131784d9c625SLionel Sambuc	command printf "%s\n" "${base}"
131884d9c625SLionel Sambuc}
131984d9c625SLionel Sambuc
132084d9c625SLionel Sambucdirname()
132184d9c625SLionel Sambuc{
132284d9c625SLionel Sambuc	local file="$1"
132384d9c625SLionel Sambuc	local dir
132484d9c625SLionel Sambuc
132584d9c625SLionel Sambuc	case "$file" in
132684d9c625SLionel Sambuc	/*/*)	dir="${file%/*}" ;;	# common case: absolute path
132784d9c625SLionel Sambuc	/*)	dir="/" ;;		# special case: name in root dir
132884d9c625SLionel Sambuc	*/*)	dir="${file%/*}" ;;	# common case: relative path with '/'
132984d9c625SLionel Sambuc	*)	dir="." ;;		# special case: name without '/'
133084d9c625SLionel Sambuc	esac
133184d9c625SLionel Sambuc	command printf "%s\n" "${dir}"
133284d9c625SLionel Sambuc}
133384d9c625SLionel Sambuc
1334e68cf3bfSBen Gras# Override the normal "echo" and "printf" commands, so that
1335e68cf3bfSBen Gras# partial lines printed by rc.d scripts appear immediately,
1336e68cf3bfSBen Gras# instead of being buffered by rc(8)'s post-processor.
1337e68cf3bfSBen Gras#
1338e68cf3bfSBen Gras# Naive use of the echo or printf commands from rc.d scripts,
1339e68cf3bfSBen Gras# elsewhere in rc.subr, or anything else that sources rc.subr,
1340e68cf3bfSBen Gras# will call these functions.  To call the real echo and printf
1341e68cf3bfSBen Gras# commands, use "command echo" or "command printf".
1342e68cf3bfSBen Gras#
1343e68cf3bfSBen Grasecho()
1344e68cf3bfSBen Gras{
1345e68cf3bfSBen Gras	command echo "$@"
1346e68cf3bfSBen Gras	case "$1" in
1347e68cf3bfSBen Gras	'-n')	_flush_rc_output ;;
1348e68cf3bfSBen Gras	esac
1349e68cf3bfSBen Gras}
1350e68cf3bfSBen Grasprintf()
1351e68cf3bfSBen Gras{
1352e68cf3bfSBen Gras	command printf "$@"
1353e68cf3bfSBen Gras	case "$1" in
1354e68cf3bfSBen Gras	*'\n')	: ;;
1355e68cf3bfSBen Gras	*)	_flush_rc_output ;;
1356e68cf3bfSBen Gras	esac
1357e68cf3bfSBen Gras}
1358e68cf3bfSBen Gras
1359e68cf3bfSBen Gras_rc_subr_loaded=:
1360