rc.subr revision 1.104
1#	$OpenBSD: rc.subr,v 1.104 2015/12/21 09:29:12 ajacoutot Exp $
2#
3# Copyright (c) 2010, 2011, 2014 Antoine Jacoutot <ajacoutot@openbsd.org>
4# Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5# Copyright (c) 2010, 2011, 2014 Robert Nagy <robert@openbsd.org>
6#
7# Permission to use, copy, modify, and distribute this software for any
8# purpose with or without fee is hereby granted, provided that the above
9# copyright notice and this permission notice appear in all copies.
10#
11# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19_rc_actions="start stop restart reload check"
20readonly _rc_actions
21
22_rc_err() {
23	[ -n "${1}" ] && echo "${1}" 1>&2
24	[ -n "${2}" ] && exit "${2}" || exit 1
25}
26
27_rc_not_supported() {
28	local _a _enotsup
29	for _a in ${_rc_actions}; do
30		if [ "${1}" == "${_a}" ]; then
31			eval _enotsup=\${rc_$1}
32			break
33		fi
34	done
35	[ X"${_enotsup}" == X"NO" ]
36}
37
38_rc_usage() {
39	local _a _allsup
40	for _a in ${_rc_actions}; do
41		_rc_not_supported ${_a} || _allsup="${_allsup:+$_allsup|}${_a}"
42	done
43	_rc_err "usage: $0 [-df] ${_allsup}"
44}
45
46_rc_write_runfile() {
47	[ -d ${_RC_RUNDIR} ] || mkdir -p ${_RC_RUNDIR} && \
48		print -rn -- "${pexp}" > ${_RC_RUNFILE}
49}
50
51_rc_read_runfile() {
52	local _new_pexp
53	[ -f ${_RC_RUNFILE} ] && _new_pexp=$(< ${_RC_RUNFILE})
54	[ -n "${_new_pexp}" ] && pexp="${_new_pexp}"
55}
56
57_rc_rm_runfile() {
58	rm -f ${_RC_RUNFILE}
59}
60
61_rc_do() {
62	if [ -n "${_RC_DEBUG}" ]; then
63		echo "doing $@" && "$@"
64	else
65		"$@" >/dev/null 2>&1
66	fi
67}
68
69_rc_exit() {
70	local _pfix
71	[ -z "${INRC}" -o X"$1" != X"ok" ] && _pfix="($1)"
72	echo ${INRC:+'-n'} "${_pfix}"
73	[ X"$1" = X"ok" ] && exit 0 || exit 1
74}
75
76_rc_wait() {
77	local _i=0
78	while [ $_i -lt ${daemon_timeout} ]; do
79    		case "$1" in
80		reload|start)
81			_rc_do rc_check && return 0 ;;
82		stop)
83			_rc_do rc_check || return 0 ;;
84		*)
85			break ;;
86		esac
87		sleep 1
88		_i=$((_i+1))
89	done
90	return 1
91}
92
93_rc_quirks() {
94	# special care needed for spamlogd to avoid starting it up and failing
95	# all the time
96	if [  X"${spamd_flags}" = X"NO" -o X"${spamd_black}" != X"NO" ]; then
97		spamlogd_flags=NO
98	fi
99
100	# special care needed for pflogd to avoid starting it up and failing
101	# if pf is not enabled
102	if [ X"${pf}" = X"NO" ]; then
103		pflogd_flags=NO
104	fi
105
106	# special care needed if nfs_server=YES to startup nfsd and mountd with
107	# sane default flags
108	if [ X"${nfs_server}" = X"YES" ]; then
109		[ X"${nfsd_flags}" = X"NO" ] && nfsd_flags="-tun 4"
110		[ X"${mountd_flags}" = X"NO" ] && mountd_flags=
111	fi
112
113	# in case domainname is set and /var/yp/binding exists enable ypbind
114	if [ X"`domainname`" != X"" -a -d /var/yp/binding ]; then
115		ypbind_flags=
116	fi
117}
118
119_rc_parse_conf() {
120	typeset -l _key
121	local _l _rcfile _val
122	set -A _allowed_keys -- \
123		spamd_black pf ipsec check_quotas accounting \
124		multicast amd_master \
125		shlib_dirs pkg_scripts nfs_server
126
127	[ $# -gt 0 ] || set -- /etc/rc.conf /etc/rc.conf.local
128	for _rcfile; do
129		[[ -f $_rcfile ]] || continue
130		while IFS=' 	' read -r _l; do
131			[[ $_l == [!#=]*=* ]] || continue
132			_key=${_l%%*([[:blank:]])=*}
133			[[ $_key == *_@(flags|user|timeout) ]] || \
134				[[ " ${_allowed_keys[*]} " == *" $_key "* ]] || \
135				continue
136			[[ $_key == "" ]] && continue
137			_val=${_l##*([!=])=*([[:blank:]])}
138			_val=${_val%%#*}
139			_val=${_val%%*([[:blank:]])}
140			# remove leading and trailing quotes (backwards compat)
141			[[ $_val == @(\"*\"|\'*\') ]] && _val=${_val#?} _val=${_val%?}
142			eval "${_key}=\${_val}"
143		done < $_rcfile
144	done
145
146	_rc_do _rc_quirks
147}
148
149# return if we only want internal functions
150[ -n "${FUNCS_ONLY}" ] && return
151
152rc_start() {
153	${rcexec} "${daemon} ${daemon_flags} ${_bg}"
154}
155
156rc_check() {
157	pgrep -q -xf "${pexp}"
158}
159
160rc_reload() {
161	pkill -HUP -xf "${pexp}"
162}
163
164rc_stop() {
165	pkill -xf "${pexp}"
166}
167
168rc_cmd() {
169	local _bg _n
170
171	[ "$(id -u)" -eq 0 ] || \
172		[ X"${rc_usercheck}" != X"NO" -a X"$1" = "Xcheck" ] || \
173		_rc_err "$0: need root privileges"
174
175	if _rc_not_supported start || _rc_not_supported stop; then
176		rc_restart=NO
177	fi
178
179	if _rc_not_supported $1; then
180		[ -n "${INRC}" ] && exit 1
181		_rc_err "$0: $1 is not supported"
182	fi
183
184	[ X"${rc_bg}" = X"YES" ] && _bg="&"
185	[ -n "${_RC_DEBUG}" ] || _n="-n"
186
187	_rc_do _rc_read_runfile
188
189	case "$1" in
190	check)
191		echo $_n "${INRC:+ }${_name}"
192		_rc_do rc_check && _rc_exit ok
193		_rc_exit failed
194		;;
195	start)
196		if [ X"${daemon_flags}" = X"NO" ]; then
197			_rc_err "$0: need -f to force $1 since ${_name}_flags=NO"
198		fi
199		[ -z "${INRC}" ] && _rc_do rc_check && exit 0
200		echo $_n "${INRC:+ }${_name}"
201		while true; do  # no real loop, only needed to break
202			if type rc_pre >/dev/null; then
203				_rc_do rc_pre || break
204			fi
205			_rc_do rc_start || break
206			#_rc_do _rc_wait start || break
207			_rc_do _rc_write_runfile
208			_rc_exit ok
209		done
210		# handle failure
211		type rc_post >/dev/null && _rc_do rc_post
212		_rc_do _rc_rm_runfile
213		_rc_exit failed
214		;;
215	stop)
216		_rc_do rc_check || exit 0
217		echo $_n "${INRC:+ }${_name}"
218		_rc_do rc_stop || _rc_exit failed
219		_rc_do _rc_wait stop || _rc_exit failed
220		if type rc_post >/dev/null; then \
221			_rc_do rc_post || _rc_exit failed
222		fi
223		_rc_do _rc_rm_runfile
224		_rc_exit ok
225		;;
226	reload)
227		echo $_n "${INRC:+ }${_name}"
228		_rc_do rc_check && _rc_do rc_reload || _rc_exit failed
229		_rc_do _rc_wait reload || _rc_exit failed
230		_rc_exit ok
231		;;
232	restart)
233		$0 ${_RC_DEBUG} ${_RC_FORCE} stop &&
234			$0 ${_RC_DEBUG} ${_RC_FORCE} start
235		;;
236	*)
237		_rc_usage
238		;;
239	esac
240}
241
242[ -n "${daemon}" ] || _rc_err "$0: daemon is not set"
243
244unset _RC_DEBUG _RC_FORCE
245while getopts "df" c; do
246	case "$c" in
247		d) _RC_DEBUG=-d;;
248		f) _RC_FORCE=-f;;
249		*) _rc_usage;;
250	esac
251done
252shift $((OPTIND-1))
253
254_name=$(basename $0)
255_RC_RUNDIR=/var/run/rc.d
256_RC_RUNFILE=${_RC_RUNDIR}/${_name}
257
258# parse /etc/rc.conf{.local} for the daemon_flags
259_rc_do _rc_parse_conf
260
261eval _rcflags=\${${_name}_flags}
262eval _rcuser=\${${_name}_user}
263eval _rctimeout=\${${_name}_timeout}
264
265# set default values; duplicated in rcctl(8)
266getcap -f /etc/login.conf ${_name} 1>/dev/null 2>&1 && \
267	daemon_class=${_name} || daemon_class=daemon
268[ -z "${daemon_user}" ] && daemon_user=root
269[ -z "${daemon_timeout}" ] && daemon_timeout=30
270
271# use flags from the rc.d script if daemon is not enabled
272[ -n "${_RC_FORCE}" -o "$1" != "start" ] && [ X"${_rcflags}" = X"NO" ] && \
273	unset _rcflags
274
275[ -n "${_rcflags}" ] && daemon_flags=${_rcflags}
276[ -n "${_rcuser}" ] && daemon_user=${_rcuser}
277[ -n "${_rctimeout}" ] && daemon_timeout=${_rctimeout}
278
279if [ -n "${_RC_DEBUG}" ]; then
280	echo -n "${_name}_flags "
281	[ -n "${_rcflags}" ] || echo -n "empty, using default "
282	echo ">${daemon_flags}<"
283fi
284
285readonly daemon_class
286unset _rcflags _rcuser _rctimeout
287pexp="${daemon}${daemon_flags:+ ${daemon_flags}}"
288rcexec="su -l -c ${daemon_class} -s /bin/sh ${daemon_user} -c"
289