xref: /openbsd-src/usr.sbin/rcctl/rcctl.sh (revision 4f37b6d8348814d18455d660970182911f6f21f8)
1#!/bin/ksh
2#
3# $OpenBSD: rcctl.sh,v 1.120 2024/09/29 14:36:13 kn Exp $
4#
5# Copyright (c) 2014, 2015-2022 Antoine Jacoutot <ajacoutot@openbsd.org>
6# Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
7#
8# Permission to use, copy, modify, and distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20_special_svcs="accounting check_quotas ipsec library_aslr multicast pf
21               spamd_black"
22readonly _special_svcs
23
24# get local functions from rc.subr(8)
25FUNCS_ONLY=1
26. /etc/rc.d/rc.subr
27_rc_parse_conf
28
29usage()
30{
31	local _a _i
32	for _i in ${_rc_actions}; do _a=${_a:+${_a}|}$_i; done
33
34	_rc_err \
35	"usage:	rcctl get|getdef|set daemon|service [variable [argument ...]]
36	rcctl [-df] ${_a} daemon ...
37	rcctl disable|enable|order [daemon ...]
38	rcctl ls all|failed|off|on|rogue|started|stopped"
39}
40
41needs_root()
42{
43	[ "$(id -u)" -ne 0 ] && _rc_err "${0##*/}: \"$*\" needs root privileges"
44}
45
46rcctl_err()
47{
48	_rc_err "${0##*/}: ${1}" ${2}
49}
50
51ls_rcscripts()
52{
53	local _s
54
55	cd /etc/rc.d && set -- *
56	for _s; do
57		[[ ${_s} == +([[:alnum:]_]) ]] || continue
58		[ ! -d "${_s}" ] && echo "${_s}"
59	done
60}
61
62pkg_scripts_append()
63{
64	local _svc=$1
65	[ -n "${_svc}" ] || return
66
67	rcconf_edit_begin
68	if [ -z "${pkg_scripts}" ]; then
69		echo pkg_scripts="${_svc}" >>${_TMP_RCCONF}
70	elif ! echo ${pkg_scripts} | grep -qw -- ${_svc}; then
71		grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF}
72		echo pkg_scripts="${pkg_scripts} ${_svc}" >>${_TMP_RCCONF}
73	fi
74	rcconf_edit_end
75}
76
77pkg_scripts_order()
78{
79	local _svcs="$*"
80	[ -n "${_svcs}" ] || return
81
82	needs_root ${action}
83	local _pkg_scripts _svc
84	for _svc in ${_svcs}; do
85		if svc_is_base ${_svc} || svc_is_special ${_svc}; then
86			rcctl_err "${_svc} is not a pkg script"
87		elif ! svc_get ${_svc} status; then
88			rcctl_err "${_svc} is not enabled"
89		fi
90	done
91	_pkg_scripts=$(echo "${_svcs} ${pkg_scripts}" | tr "[:blank:]" "\n" | \
92		     awk -v ORS=' ' '!x[$0]++')
93	rcconf_edit_begin
94	grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF}
95	echo pkg_scripts=${_pkg_scripts} >>${_TMP_RCCONF}
96	rcconf_edit_end
97}
98
99pkg_scripts_rm()
100{
101	local _svc=$1
102	[ -n "${_svc}" ] || return
103
104	[ -z "${pkg_scripts}" ] && return
105
106	rcconf_edit_begin
107	sed "/^pkg_scripts[[:>:]]/{s/[[:<:]]${_svc}[[:>:]]//g
108	    s/['\"]//g;s/ *= */=/;s/   */ /g;s/ $//;/=$/d;}" \
109	    /etc/rc.conf.local >${_TMP_RCCONF}
110	rcconf_edit_end
111}
112
113rcconf_edit_begin()
114{
115	_TMP_RCCONF=$(mktemp -p /etc -t rc.conf.local.XXXXXXXXXX) || \
116		rcctl_err "cannot create temporary file under /etc"
117	if [ -f /etc/rc.conf.local ]; then
118		cat /etc/rc.conf.local >${_TMP_RCCONF} || \
119			rcctl_err "cannot append to ${_TMP_RCCONF}"
120	else
121		touch /etc/rc.conf.local || \
122			rcctl_err "cannot create /etc/rc.conf.local"
123	fi
124}
125
126rcconf_edit_end()
127{
128	sort -u -o ${_TMP_RCCONF} ${_TMP_RCCONF} || \
129		rcctl_err "cannot modify ${_TMP_RCCONF}"
130	if ! cmp -s ${_TMP_RCCONF} /etc/rc.conf.local; then
131		install -F -m0644 -o0 -g0 ${_TMP_RCCONF} /etc/rc.conf.local ||
132			rcctl_err "cannot write to /etc/rc.conf.local"
133	fi
134	if [ ! -s /etc/rc.conf.local ]; then
135		rm /etc/rc.conf.local || \
136			rcctl_err "cannot remove /etc/rc.conf.local"
137	fi
138	rm -f ${_TMP_RCCONF}
139	_rc_parse_conf # reload new values
140}
141
142svc_is_avail()
143{
144	local _svc=$1
145	_rc_check_name "${_svc}" || return
146
147	[ -x "/etc/rc.d/${_svc}" ] && return
148	svc_is_special ${_svc}
149}
150
151svc_is_base()
152{
153	local _svc=$1
154	[ -n "${_svc}" ] || return
155
156	local _cached _ret
157
158	_cached=$(eval echo \${cached_svc_is_base_${_svc}})
159	[ "${_cached}" ] && return "${_cached}"
160
161	grep -qw "^${_svc}_flags" /etc/rc.conf
162	_ret=$?
163
164	set -A cached_svc_is_base_${_svc} -- ${_ret}
165	return ${_ret}
166}
167
168svc_is_meta()
169{
170	local _svc=$1
171	[ -n "${_svc}" ] || return
172
173	local _cached _ret
174
175	_cached=$(eval echo \${cached_svc_is_meta_${_svc}})
176	[ "${_cached}" ] && return "${_cached}"
177
178	[ -r "/etc/rc.d/${_svc}" ] && ! grep -qw "^rc_cmd" /etc/rc.d/${_svc}
179	_ret=$?
180
181	set -A cached_svc_is_meta_${_svc} -- ${_ret}
182	return ${_ret}
183}
184
185svc_is_special()
186{
187	local _svc=$1
188	[ -n "${_svc}" ] || return
189
190	local _cached _ret
191
192	_cached=$(eval echo \${cached_svc_is_special_${_svc}})
193	[ "${_cached}" ] && return "${_cached}"
194
195	echo ${_special_svcs} | grep -qw -- ${_svc}
196	_ret=$?
197
198	set -A cached_svc_is_special_${_svc} -- ${_ret}
199	return ${_ret}
200}
201
202svc_ls()
203{
204	local _lsarg=$1
205	[ -n "${_lsarg}" ] || return
206
207	# we do not want to return the "status" nor the rc.d(8) script retcode
208	local _ret=0 _on _svc _started
209
210	case ${_lsarg} in
211		all)
212			(
213				ls_rcscripts
214				echo ${_special_svcs} | tr "[:blank:]" "\n"
215			) | sort
216			;;
217		failed)
218			for _svc in $(svc_ls on); do
219				! svc_is_special ${_svc} && \
220					! /etc/rc.d/${_svc} check >/dev/null && \
221					echo ${_svc} && _ret=1
222			done
223			;;
224		off|on)
225			for _svc in $(svc_ls all); do
226				svc_get ${_svc} status && _on=1
227					[ "${_lsarg}" = "on" -a -n "${_on}" ] || \
228						[ "${_lsarg}" = "off" -a -z "${_on}" ] && \
229					echo ${_svc}
230				unset _on
231			done
232			;;
233		rogue)
234			for _svc in $(svc_ls off); do
235				! svc_is_special ${_svc} && \
236					/etc/rc.d/${_svc} check >/dev/null && \
237					echo ${_svc} && _ret=1
238			done
239			;;
240		started|stopped)
241			for _svc in $(ls_rcscripts); do
242				/etc/rc.d/${_svc} check >/dev/null && _started=1
243				[ "${_lsarg}" = "started" -a -n "${_started}" ] || \
244					[ "${_lsarg}" = "stopped" -a -z "${_started}" ] && \
245					echo ${_svc}
246				unset _started
247			done
248			;;
249		*)
250			_ret=1
251			;;
252	esac
253
254	return ${_ret}
255}
256
257svc_get()
258{
259	local _svc=$1
260	[ -n "${_svc}" ] || return
261
262	local _status=0 _val _var=$2
263	local daemon_class daemon_execdir daemon_flags daemon_logger
264	local daemon_rtable daemon_timeout daemon_user
265
266	if svc_is_special ${_svc}; then
267		daemon_flags="$(eval echo \${${_svc}})"
268	else
269		# set pkg daemon_flags to "NO" to match base svc
270		if ! svc_is_base ${_svc}; then
271			if ! echo ${pkg_scripts} | grep -qw -- ${_svc}; then
272				daemon_flags="NO"
273			fi
274		fi
275
276		if ! svc_is_meta ${_svc}; then
277			# these are expensive, make sure they are explicitly requested
278			if [ -z "${_var}" -o "${_var}" = "class" ]; then
279				getcap -f /etc/login.conf.d/${_svc}:/etc/login.conf \
280					${_svc} 1>/dev/null 2>&1 && daemon_class=${_svc}
281				[ -z "${daemon_class}" ] && \
282					daemon_class="$(svc_getdef ${_svc} class)"
283			fi
284			if [ -z "${_var}" -o "${_var}" = "execdir" ]; then
285				[ -z "${daemon_execdir}" ] && \
286					daemon_execdir="$(eval echo \"\${${_svc}_execdir}\")"
287				[ -z "${daemon_execdir}" ] && \
288					daemon_execdir="$(svc_getdef ${_svc} execdir)"
289			fi
290			if [[ -z ${_var} || ${_var} == @(flags|status) ]]; then
291				[ -z "${daemon_flags}" ] && \
292					daemon_flags="$(eval echo \"\${${_svc}_flags}\")"
293				[ -z "${daemon_flags}" ] && \
294					daemon_flags="$(svc_getdef ${_svc} flags)"
295			fi
296			if [ -z "${_var}" -o "${_var}" = "logger" ]; then
297				[ -z "${daemon_logger}" ] && \
298					daemon_logger="$(eval echo \"\${${_svc}_logger}\")"
299				[ -z "${daemon_logger}" ] && \
300					daemon_logger="$(svc_getdef ${_svc} logger)"
301			fi
302			if [ -z "${_var}" -o "${_var}" = "rtable" ]; then
303				[ -z "${daemon_rtable}" ] && \
304					daemon_rtable="$(eval echo \"\${${_svc}_rtable}\")"
305				[ -z "${daemon_rtable}" ] && \
306					daemon_rtable="$(svc_getdef ${_svc} rtable)"
307			fi
308			if [ -z "${_var}" -o "${_var}" = "timeout" ]; then
309				[ -z "${daemon_timeout}" ] && \
310					daemon_timeout="$(eval echo \"\${${_svc}_timeout}\")"
311				[ -z "${daemon_timeout}" ] && \
312					daemon_timeout="$(svc_getdef ${_svc} timeout)"
313			fi
314			if [ -z "${_var}" -o "${_var}" = "user" ]; then
315				[ -z "${daemon_user}" ] && \
316					daemon_user="$(eval echo \"\${${_svc}_user}\")"
317				[ -z "${daemon_user}" ] && \
318					daemon_user="$(svc_getdef ${_svc} user)"
319			fi
320		fi
321	fi
322
323	[ "${daemon_flags}" = "NO" ] && _status=1
324
325	if [ -n "${_var}" ]; then
326		[ "${_var}" = "status" ] && return ${_status}
327		eval _val=\${daemon_${_var}}
328		[ -z "${_val}" ] || print -r -- "${_val}"
329	else
330		svc_is_meta ${_svc} && return ${_status}
331		if svc_is_special ${_svc}; then
332			echo "${_svc}=${daemon_flags}"
333		else
334			echo "${_svc}_class=${daemon_class}"
335			echo "${_svc}_execdir=${daemon_execdir}"
336			echo "${_svc}_flags=${daemon_flags}"
337			echo "${_svc}_logger=${daemon_logger}"
338			echo "${_svc}_rtable=${daemon_rtable}"
339			echo "${_svc}_timeout=${daemon_timeout}"
340			echo "${_svc}_user=${daemon_user}"
341		fi
342		return ${_status}
343	fi
344}
345
346# to prevent namespace pollution, only call in a subshell
347svc_getdef()
348{
349	local _svc=$1
350	[ -n "${_svc}" ] || return
351
352	local _status=0 _val _var=$2
353	local daemon_class daemon_execdir daemon_flags daemon_logger
354	local daemon_rtable daemon_timeout daemon_user
355
356	if svc_is_special ${_svc}; then
357		# unconditionally parse: we always output flags and/or status
358		_rc_parse_conf /etc/rc.conf
359		daemon_flags="$(eval echo \${${_svc}})"
360		[ "${daemon_flags}" = "NO" ] && _status=1
361	else
362		if ! svc_is_base ${_svc}; then
363			_status=1 # all pkg_scripts are off by default
364		else
365			# abuse /etc/rc.conf behavior of only setting flags
366			# to empty or "NO" to get our default status;
367			# we'll get our default flags from the rc.d script
368			[[ -z ${_var} || ${_var} == status ]] && \
369				_rc_parse_conf /etc/rc.conf
370			[ "$(eval echo \${${_svc}_flags})" = "NO" ] && _status=1
371		fi
372
373		if ! svc_is_meta ${_svc}; then
374			rc_cmd() { }
375			. /etc/rc.d/${_svc} >/dev/null 2>&1
376
377			daemon_class=daemon
378			[ -z "${daemon_rtable}" ] && daemon_rtable=0
379			[ -z "${daemon_timeout}" ] && daemon_timeout=30
380			[ -z "${daemon_user}" ] && daemon_user=root
381		fi
382	fi
383
384	if [ -n "${_var}" ]; then
385		[ "${_var}" = "status" ] && return ${_status}
386		eval _val=\${daemon_${_var}}
387		[ -z "${_val}" ] || print -r -- "${_val}"
388	else
389		svc_is_meta ${_svc} && return ${_status}
390		if svc_is_special ${_svc}; then
391			echo "${_svc}=${daemon_flags}"
392		else
393			echo "${_svc}_class=${daemon_class}"
394			echo "${_svc}_execdir=${daemon_execdir}"
395			echo "${_svc}_flags=${daemon_flags}"
396			echo "${_svc}_logger=${daemon_logger}"
397			echo "${_svc}_rtable=${daemon_rtable}"
398			echo "${_svc}_timeout=${daemon_timeout}"
399			echo "${_svc}_user=${daemon_user}"
400		fi
401		return ${_status}
402	fi
403}
404
405svc_rm()
406{
407	local _svc=$1
408	[ -n "${_svc}" ] || return
409
410	rcconf_edit_begin
411	if svc_is_special ${_svc}; then
412		grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF}
413		( svc_getdef ${_svc} status ) && \
414			echo "${_svc}=NO" >>${_TMP_RCCONF}
415	else
416		grep -Ev "^${_svc}_(execdir|flags|logger|rtable|timeout|user).*=" \
417			/etc/rc.conf.local >${_TMP_RCCONF}
418		( svc_getdef ${_svc} status ) && \
419			echo "${_svc}_flags=NO" >>${_TMP_RCCONF}
420	fi
421	rcconf_edit_end
422}
423
424svc_set()
425{
426	local _svc=$1 _var=$2
427	[ -n "${_svc}" -a -n "${_var}" ] || return
428
429	shift 2
430	local _args="$*"
431
432	# don't check if we are already enabled or disabled because rc.conf(8)
433	# defaults may have changed in which case we may have a matching
434	# redundant entry in rc.conf.local that we can drop
435	if [ "${_var}" = "status" ]; then
436		if [ "${_args}" = "on" ]; then
437			_var="flags"
438			# keep our flags if we're already enabled
439			eval "_args=\"\${${_svc}_${_var}}\""
440			[ "${_args}" = "NO" ] && unset _args
441			if ! svc_is_base ${_svc} && ! svc_is_special ${_svc}; then
442				pkg_scripts_append ${_svc}
443			fi
444		elif [ "${_args}" = "off" ]; then
445			if ! svc_is_base ${_svc} && ! svc_is_special ${_svc}; then
446				pkg_scripts_rm ${_svc}
447			fi
448			svc_rm ${_svc}
449			return
450		else
451			rcctl_err "invalid status \"${_args}\""
452		fi
453	else
454		svc_get ${_svc} status || \
455			rcctl_err "${svc} is not enabled"
456	fi
457
458	if svc_is_special ${_svc}; then
459		[ "${_var}" = "flags" ] || return
460		rcconf_edit_begin
461		grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF}
462		( svc_getdef ${_svc} status ) || \
463			echo "${_svc}=YES" >>${_TMP_RCCONF}
464		rcconf_edit_end
465		return
466	fi
467
468	if [ -n "${_args}" ]; then
469		if [ "${_var}" = "execdir" ]; then
470			[[ ${_args%${_args#?}} == / ]] ||
471				rcctl_err "\"${_args}\" must be an absolute path"
472		fi
473		if [ "${_var}" = "logger" ]; then
474			logger -p "${_args}" </dev/null >/dev/null 2>&1 ||
475				rcctl_err "unknown priority name: \"${_args}\""
476		fi
477		if [ "${_var}" = "rtable" ]; then
478			[[ ${_args} != +([[:digit:]]) || ${_args} -lt 0 ]] && \
479				rcctl_err "\"${_args}\" is not an integer"
480		fi
481		if [ "${_var}" = "timeout" ]; then
482			[[ ${_args} != +([[:digit:]]) || ${_args} -le 0 ]] && \
483				rcctl_err "\"${_args}\" is not a positive integer"
484		fi
485		if [ "${_var}" = "user" ]; then
486			getent passwd "${_args}" >/dev/null || \
487				rcctl_err "user \"${_args}\" does not exist"
488		fi
489		# unset flags if they match the default enabled ones
490		[ "${_args}" = "$(svc_getdef ${_svc} ${_var})" ] && \
491			unset _args
492	fi
493
494	# protect leading whitespace
495	[ "${_args}" = "${_args# }" ] || _args="\"${_args}\""
496
497	# reset: value may have changed
498	unset ${_svc}_${_var}
499
500	rcconf_edit_begin
501	grep -v "^${_svc}_${_var}.*=" /etc/rc.conf.local >${_TMP_RCCONF}
502	if [ -n "${_args}" ] || \
503	   ( svc_is_base ${_svc} && ! svc_getdef ${_svc} status && [ "${_var}" == "flags" ] ); then
504		echo "${_svc}_${_var}=${_args}" >>${_TMP_RCCONF}
505	fi
506	rcconf_edit_end
507}
508
509unset _RC_DEBUG _RC_FORCE
510while getopts "df" c; do
511	case "$c" in
512		d) _RC_DEBUG=-d;;
513		f) _RC_FORCE=-f;;
514		*) usage;;
515	esac
516done
517shift $((OPTIND-1))
518[ $# -gt 0 ] || usage
519
520action=$1
521ret=0
522
523case ${action} in
524	ls)
525		lsarg=$2
526		[[ ${lsarg} == @(all|failed|off|on|rogue|started|stopped) ]] || usage
527		;;
528	order)
529		shift 1
530		svcs="$*"
531		for svc in ${svcs}; do
532			svc_is_avail ${svc} || \
533				rcctl_err "service ${svc} does not exist" 2
534		done
535		;;
536	disable|enable|start|stop|restart|reload|check|configtest)
537		shift 1
538		svcs="$*"
539		[ -z "${svcs}" ] && usage
540		for svc in ${svcs}; do
541			# it's ok to disable a non-existing daemon
542			if [ "${action}" != "disable" ]; then
543				svc_is_avail ${svc} || \
544					rcctl_err "service ${svc} does not exist" 2
545			# but still check for bad input
546			else
547				_rc_check_name "${svc}" || \
548					rcctl_err "service ${svc} does not exist" 2
549			fi
550		done
551		;;
552	get|getdef)
553		svc=$2
554		var=$3
555		[ -z "${svc}" ] && usage
556		[ "${svc}" = "all" ] || svc_is_avail ${svc} || \
557			rcctl_err "service ${svc} does not exist" 2
558		if [ -n "${var}" ]; then
559			[ "${svc}" = "all" ] && usage
560			[[ ${var} != @(class|execdir|flags|logger|rtable|status|timeout|user) ]] && usage
561			if svc_is_meta ${svc}; then
562				[ "${var}" != "status" ] && \
563					rcctl_err "/etc/rc.d/${svc} is a meta script, cannot \"${action} ${var}\""
564			fi
565			if svc_is_special ${svc}; then
566				[[ ${var} == @(class|execdir|logger|rtable|timeout|user) ]] && \
567					rcctl_err "\"${svc}\" is a special variable, cannot \"${action} ${var}\""
568			fi
569		fi
570		;;
571	set)
572		svc=$2
573		var=$3
574		[ $# -ge 3 ] && shift 3 || shift $#
575		args="$*"
576		[ -z "${svc}" ] && usage
577		# it's ok to disable a non-existing daemon
578		if [ "${action} ${var} ${args}" != "set status off" ]; then
579			svc_is_avail ${svc} || \
580				rcctl_err "service ${svc} does not exist" 2
581		# but still check for bad input
582		else
583			_rc_check_name "${svc}" || \
584				rcctl_err "service ${svc} does not exist" 2
585		fi
586		[[ ${var} != @(class|execdir|flags|logger|rtable|status|timeout|user) ]] && usage
587		svc_is_meta ${svc} && [ "${var}" != "status" ] && \
588			rcctl_err "/etc/rc.d/${svc} is a meta script, cannot \"${action} ${var}\""
589		[[ ${var} = flags && ${args} = NO ]] && \
590			rcctl_err "\"flags NO\" contradicts \"${action}\""
591		if svc_is_special ${svc}; then
592			[[ ${var} != status ]] && \
593				rcctl_err "\"${svc}\" is a special variable, cannot \"${action} ${var}\""
594		fi
595		[[ ${var} == class ]] && \
596			rcctl_err "\"${svc}_class\" is a read-only variable set in login.conf(5)"
597		;;
598	*)
599		usage
600		;;
601esac
602
603case ${action} in
604	disable)
605		needs_root ${action}
606		for svc in ${svcs}; do
607			svc_set ${svc} status off || ret=$?;
608		done
609		exit ${ret}
610		;;
611	enable)
612		needs_root ${action}
613		for svc in ${svcs}; do
614			svc_set ${svc} status on || ret=$?;
615		done
616		exit ${ret}
617		;;
618	get|getdef)
619		if [ "${svc}" = "all" ]; then
620			for svc in $(svc_ls all); do
621				( svc_${action} ${svc} "${var}" )
622			done
623			return 0 # we do not want the svc status
624		else
625			( svc_${action} ${svc} "${var}" )
626		fi
627		;;
628	ls)
629		# some rc.d(8) scripts need root for rc_check()
630		[[ ${lsarg} == @(started|stopped|failed|rogue) ]] && needs_root ${action} ${lsarg}
631		svc_ls ${lsarg}
632		;;
633	order)
634		if [ -n "${svcs}" ]; then
635			needs_root ${action}
636			pkg_scripts_order ${svcs}
637		else
638			[[ -z ${pkg_scripts} ]] || echo ${pkg_scripts}
639		fi
640		;;
641	set)
642		needs_root ${action}
643		svc_set ${svc} "${var}" "${args}"
644		;;
645	start|stop|restart|reload|check|configtest)
646		for svc in ${svcs}; do
647			if svc_is_special ${svc}; then
648				rcctl_err "\"${svc}\" is a special variable, no rc.d(8) script"
649			fi
650			/etc/rc.d/${svc} ${_RC_DEBUG} ${_RC_FORCE} ${action} || ret=$?;
651		done
652		exit ${ret}
653		;;
654	*)
655		usage
656		;;
657esac
658