MFC numerous features from HEAD.
[dragonfly.git] / etc / rc.subr
CommitLineData
9c600e7d
MD
1# $NetBSD: rc.subr,v 1.49 2002/05/21 12:31:01 lukem Exp $
2# $FreeBSD: src/etc/rc.subr,v 1.13 2003/06/09 17:31:06 mtm Exp $
a613c1fd 3# $DragonFly: src/etc/rc.subr,v 1.15 2008/04/05 08:07:11 matthias Exp $
9c600e7d
MD
4#
5# Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
6# All rights reserved.
7#
8# This code is derived from software contributed to The NetBSD Foundation
9# by Luke Mewburn.
10#
11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions
13# are met:
14# 1. Redistributions of source code must retain the above copyright
15# notice, this list of conditions and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright
17# notice, this list of conditions and the following disclaimer in the
18# documentation and/or other materials provided with the distribution.
19# 3. All advertising materials mentioning features or use of this software
20# must display the following acknowledgement:
21# This product includes software developed by the NetBSD
22# Foundation, Inc. and its contributors.
23# 4. Neither the name of The NetBSD Foundation nor the names of its
24# contributors may be used to endorse or promote products derived
25# from this software without specific prior written permission.
26#
27# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37# POSSIBILITY OF SUCH DAMAGE.
38#
39# rc.subr
40# functions used by various rc scripts
41#
42
43#
44# Operating System dependent/independent variables
45#
46
1f9506ef
MD
47if [ "X$_file" = "X" ]; then
48 _file=$0
49fi
50
51provide_list=`rcorder -p $_file`
52
9c600e7d
MD
53SYSCTL="/sbin/sysctl"
54SYSCTL_N="${SYSCTL} -n"
55CMD_OSTYPE="${SYSCTL_N} kern.ostype"
56OSTYPE=`${CMD_OSTYPE}`
57
6d94234b
MD
58RC_RUNNING=0
59RC_FAILED=1
60RC_DISABLED=2
61RC_IRRELEVANT=3
62RC_CONFIGURED=4
63RC_STOPPED=5
f54c6a5c 64SYSCTL_W="${SYSCTL}"
9c600e7d
MD
65
66#
67# functions
68# ---------
69
70#
71# set_rcvar base_var
72# Set the variable name enabling a specific service.
73# FreeBSD uses ${service}_enable, while NetBSD uses
74# just the name of the service. For example:
75# FreeBSD: sendmail_enable="YES"
76# NetBSD : sendmail="YES"
77# $1 - if $name is not the base to work of off, specify
78# a different one
79#
80set_rcvar()
81{
82 if [ -z "$1" ]; then
83 base_var=${name}
84 else
85 base_var="$1"
86 fi
87
3f605c0d 88 echo ${base_var}
9c600e7d
MD
89}
90
1f9506ef
MD
91# set_provide_list
92#
93# $1 should be $rc_arg (start, stop, restart, reload, etc)
6d94234b
MD
94# $2 return value $RC_*
95#
96# Set the rcng_* variables associated with elements in provide_list
97# based on $1 and $2.
1f9506ef 98#
6d94234b
MD
99# Returns non-zero when early termination should occur, in which
100# case the caller should return with a value of $? - 1
1f9506ef
MD
101#
102set_provide_list()
103{
6d94234b
MD
104 # Remember, plret is set to the early termination return code + 1,
105 # or 0 if we want to continue the operation.
106 #
1f9506ef
MD
107 for i in $provide_list; do
108 case $1$2 in
6d94234b 109 start$RC_RUNNING|restart$RC_RUNNING)
1f9506ef
MD
110 varsym -s rcng_$i=running
111 ;;
6d94234b 112 start$RC_FAILED|restart$RC_FAILED)
1f9506ef
MD
113 varsym -s rcng_$i=failed
114 ;;
6d94234b 115 start$RC_DISABLED|restart$RC_DISABLED|reload$RC_DISABLED)
1f9506ef
MD
116 varsym -s rcng_$i=disabled
117 ;;
6d94234b
MD
118 start$RC_IRRELEVANT|restart$RC_IRRELEVANT|reload$RC_IRRELEVANT)
119 varsym -s rcng_$i=irrelevant
0896258f 120 ;;
6d94234b
MD
121 start$RC_CONFIGURED|restart$RC_CONFIGURED)
122 varsym -s rcng_$i=configured
1f9506ef 123 ;;
6d94234b 124 stop$RC_DISABLED)
0896258f
MD
125 varsym -s rcng_$i=disabled
126 ;;
6d94234b
MD
127 stop$RC_IRRELEVANT)
128 varsym -s rcng_$i=irrelevant
1f9506ef 129 ;;
6d94234b
MD
130 stop*)
131 varsym -s rcng_$i=stopped
0896258f 132 ;;
1f9506ef
MD
133 *)
134 ;;
135 esac
136 done
137}
138
6d94234b
MD
139# check_early_term
140# $1 should be $rc_arg (start, stop, restart, reload, etc)
141# $2 return value $RC_*
142# $3 $rc_force "" not to force, "anything" to force.
143#
144# The return code is 0 if early termination is not to occur, non-zero if
145# it is to occur. When early termination is to occur the caller should
146# return check_early_term()'s return code - 1. That is, early termination
147# can occur with or without an error.
148#
149# The provide list will be adjusted when early termination occurs.
150#
151check_early_term()
152{
153 case $2 in
154 $RC_RUNNING)
155 return 0
156 ;;
157 $RC_FAILED)
158 set_provide_list $1 $2
159 [ -z "$3" ] || return 0
160 return 2
161 ;;
162 $RC_DISABLED)
163 set_provide_list $1 $2
164 [ -z "$3" ] || return 0
165 return 1
166 ;;
167 $RC_IRRELEVANT)
168 set_provide_list $1 $2
169 [ -z "$3" ] || return 0
170 return 1
171 ;;
172 $RC_CONFIGURED)
173 return 0
174 ;;
175 $RC_STOPPED)
176 return 0
177 ;;
178 esac
179 set_provide_list $1 $2
180 [ -z "$3" ] || return 0
181 return 2
182}
183
184# adjust_return_code $1
185#
186# Convert the return code to an exit code of 0 (success) or 1 (failure)
187#
188adjust_return_code()
189{
190 if [ $1 = $RC_FAILED ]; then
191 return 1
192 fi
193 return 0
194}
195
9c600e7d
MD
196#
197# force_depend script
198# Force a service to start. Intended for use by services
199# to resolve dependency issues. It is assumed the caller
200# has check to make sure this call is necessary
201# $1 - filename of script, in /etc/rc.d, to run
202#
203force_depend()
204{
205 _depend="$1"
206
207 info "${name} depends on ${_depend}, which will be forced to start."
208 if ! /etc/rc.d/${_depend} forcestart ; then
209 warn "Unable to force ${_depend}. It may already be running."
210 return 1
211 fi
212 return 0
213}
214
215#
216# checkyesno var
217# Test $1 variable, and warn if not set to YES or NO.
218# Return 0 if it's "yes" (et al), nonzero otherwise.
219#
220checkyesno()
221{
3f605c0d
VBD
222 # try foo
223 eval _value=\$${1%_enable}
224 # try foo_enable
225 if [ -z $_value ]
226 then
227 eval _value=\$${1%_enable}_enable;
228 fi
9c600e7d
MD
229 debug "checkyesno: $1 is set to $_value."
230 case $_value in
231
232 # "yes", "true", "on", or "1"
233 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
234 return 0
235 ;;
236
237 # "no", "false", "off", or "0"
238 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
239 return 1
240 ;;
241 *)
242 warn "\$${1} is not set properly - see rc.conf(5)."
243 return 1
244 ;;
245 esac
246}
247
248# reverse_list list
249# print the list in reverse order
250#
251reverse_list()
252{
253 _revlist=
254 for _revfile in $*; do
255 _revlist="$_revfile $_revlist"
256 done
257 echo $_revlist
258}
259
260#
261# mount_critical_filesystems type
262# Go through the list of critical filesystems as provided in
263# the rc.conf(5) variable $critical_filesystems_${type}, checking
264# each one to see if it is mounted, and if it is not, mounting it.
265#
266mount_critical_filesystems()
267{
268 eval _fslist=\$critical_filesystems_${1}
269 for _fs in $_fslist; do
270 mount | (
271 _ismounted=no
272 while read what _on on _type type; do
273 if [ $on = $_fs ]; then
274 _ismounted=yes
275 fi
276 done
277 if [ $_ismounted = no ]; then
278 mount $_fs >/dev/null 2>&1
279 fi
280 )
281 done
282}
283
284#
285# check_pidfile pidfile procname [interpreter]
286# Parses the first line of pidfile for a PID, and ensures
287# that the process is running and matches procname.
288# Prints the matching PID upon success, nothing otherwise.
289# interpreter is optional; see _find_processes() for details.
290#
291check_pidfile()
292{
293 _pidfile=$1
294 _procname=$2
295 _interpreter=$3
296 if [ -z "$_pidfile" -o -z "$_procname" ]; then
297 err 3 'USAGE: check_pidfile pidfile procname [interpreter]'
298 fi
299 if [ ! -f $_pidfile ]; then
300 debug "pid file {$_pidfile): not readable."
301 return
302 fi
303 read _pid _junk < $_pidfile
304 if [ -z "$_pid" ]; then
305 debug "pid file {$_pidfile): no pid in file."
306 return
307 fi
308 _find_processes $_procname ${_interpreter:-.} '-p '"$_pid"
309}
310
311#
312# check_process procname [interpreter]
313# Ensures that a process (or processes) named procname is running.
314# Prints a list of matching PIDs.
315# interpreter is optional; see _find_processes() for details.
316#
317check_process()
318{
319 _procname=$1
320 _interpreter=$2
321 if [ -z "$_procname" ]; then
322 err 3 'USAGE: check_process procname [interpreter]'
323 fi
324 _find_processes $_procname ${_interpreter:-.} '-ax'
325}
326
327#
328# _find_processes procname interpreter psargs
329# Search for procname in the output of ps generated by psargs.
330# Prints the PIDs of any matching processes, space separated.
331#
332# If interpreter == ".", check the following variations of procname
333# against the first word of each command:
334# procname
335# `basename procname`
336# `basename procname` + ":"
337# "(" + `basename procname` + ")"
338#
339# If interpreter != ".", read the first line of procname, remove the
340# leading #!, normalise whitespace, append procname, and attempt to
341# match that against each command, either as is, or with extra words
342# at the end.
343#
344_find_processes()
345{
346 if [ $# -ne 3 ]; then
347 err 3 'USAGE: _find_processes procname interpreter psargs'
348 fi
349 _procname=$1
350 _interpreter=$2
351 _psargs=$3
352
353 _pref=
354 if [ $_interpreter != "." ]; then # an interpreted script
355 read _interp < $_procname # read interpreter name
356 _interp=${_interp#\#!} # strip #!
357 set -- $_interp
358 if [ $_interpreter != $1 ]; then
359 warn "\$command_interpreter $_interpreter != $1"
360 fi
361 _interp="$* $_procname" # cleanup spaces, add _procname
362 _fp_args='_argv'
363 _fp_match='case "$_argv" in
364 ${_interp}|"${_interp} "*)'
365 else # a normal daemon
366 _procnamebn=${_procname##*/}
367 _fp_args='_arg0 _argv'
368 _fp_match='case "$_arg0" in
369 $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
370 fi
371
372 _proccheck='
373 ps -o "pid,command" '"$_psargs"' |
374 while read _npid '"$_fp_args"'; do
375 case "$_npid" in
376 PID)
377 continue ;;
378 esac ; '"$_fp_match"'
379 echo -n "$_pref$_npid" ;
380 _pref=" "
381 ;;
382 esac
383 done'
384
385# debug "in _find_processes: proccheck is ($_proccheck)."
386 eval $_proccheck
387}
388
389#
390# wait_for_pids pid [pid ...]
391# spins until none of the pids exist
392#
393wait_for_pids()
394{
395 _list=$*
396 if [ -z "$_list" ]; then
397 return
398 fi
399 _prefix=
400 while true; do
401 _nlist="";
402 for _j in $_list; do
403 if kill -0 $_j 2>/dev/null; then
404 _nlist="${_nlist}${_nlist:+ }$_j"
405 fi
406 done
407 if [ -z "$_nlist" ]; then
408 break
409 fi
410 _list=$_nlist
411 echo -n ${_prefix:-"Waiting for PIDS: "}$_list
412 _prefix=", "
413 sleep 2
414 done
415 if [ -n "$_prefix" ]; then
416 echo "."
417 fi
418}
419
420#
421# run_rc_command argument
422# Search for argument in the list of supported commands, which is:
423# "start stop restart rcvar status poll ${extra_commands}"
424# If there's a match, run ${argument}_cmd or the default method
425# (see below).
426#
427# If argument has a given prefix, then change the operation as follows:
428# Prefix Operation
429# ------ ---------
430# fast Skip the pid check, and set rc_fast=yes
431# force Set ${rcvar} to YES, and set rc_force=yes
432#
433# The following globals are used:
434#
435# Name Needed Purpose
436# ---- ------ -------
1f9506ef
MD
437# provide_list (gen) list of keywords provided by current rcng file
438#
9c600e7d
MD
439# name y Name of script.
440#
441# command n Full path to command.
442# Not needed if ${rc_arg}_cmd is set for
443# each keyword.
444#
445# command_args n Optional args/shell directives for command.
446#
447# command_interpreter n If not empty, command is interpreted, so
448# call check_{pidfile,process}() appropriately.
449#
450# extra_commands n List of extra commands supported.
451#
452# pidfile n If set, use check_pidfile $pidfile $command,
453# otherwise use check_process $command.
454# In either case, only check if $command is set.
455#
456# procname n Process name to check for instead of $command.
457#
458# rcvar n This is checked with checkyesno to determine
459# if the action should be run.
460#
461# ${name}_chroot n Directory to chroot to before running ${command}
462# Requires /usr to be mounted.
463#
464# ${name}_chdir n Directory to cd to before running ${command}
465# (if not using ${name}_chroot).
466#
467# ${name}_flags n Arguments to call ${command} with.
468# NOTE: $flags from the parent environment
469# can be used to override this.
470#
471# ${name}_nice n Nice level to run ${command} at.
472#
473# ${name}_user n User to run ${command} as, using su(1) if not
474# using ${name}_chroot.
475# Requires /usr to be mounted.
476#
477# ${name}_group n Group to run chrooted ${command} as.
478# Requires /usr to be mounted.
479#
480# ${name}_groups n Comma separated list of supplementary groups
481# to run the chrooted ${command} with.
482# Requires /usr to be mounted.
483#
484# ${rc_arg}_cmd n If set, use this as the method when invoked;
485# Otherwise, use default command (see below)
486#
487# ${rc_arg}_precmd n If set, run just before performing the
488# ${rc_arg}_cmd method in the default
489# operation (i.e, after checking for required
490# bits and process (non)existence).
491# If this completes with a non-zero exit code,
492# don't run ${rc_arg}_cmd.
493#
494# ${rc_arg}_postcmd n If set, run just after performing the
495# ${rc_arg}_cmd method, if that method
496# returned a zero exit code.
497#
498# required_dirs n If set, check for the existence of the given
499# directories before running the default
500# (re)start command.
501#
502# required_files n If set, check for the readability of the given
503# files before running the default (re)start
504# command.
505#
506# required_vars n If set, perform checkyesno on each of the
507# listed variables before running the default
508# (re)start command.
509#
510# Default behaviour for a given argument, if no override method is
511# provided:
512#
513# Argument Default behaviour
514# -------- -----------------
515# start if !running && checkyesno ${rcvar}
516# ${command}
517#
518# stop if ${pidfile}
519# rc_pid=$(check_pidfile $pidfile $command)
520# else
521# rc_pid=$(check_process $command)
522# kill $sig_stop $rc_pid
523# wait_for_pids $rc_pid
524# ($sig_stop defaults to TERM.)
525#
526# reload Similar to stop, except use $sig_reload instead,
527# and doesn't wait_for_pids.
528# $sig_reload defaults to HUP.
529#
530# restart Run `stop' then `start'.
531#
532# status Show if ${command} is running, etc.
533#
534# poll Wait for ${command} to exit.
535#
536# rcvar Display what rc.conf variable is used (if any).
537#
538# Variables available to methods, and after run_rc_command() has
539# completed:
540#
541# Variable Purpose
542# -------- -------
543# rc_arg Argument to command, after fast/force processing
544# performed
545#
546# rc_flags Flags to start the default command with.
547# Defaults to ${name}_flags, unless overridden
548# by $flags from the environment.
549# This variable may be changed by the precmd method.
550#
551# rc_pid PID of command (if appropriate)
552#
553# rc_fast Not empty if "fast" was provided (q.v.)
554#
555# rc_force Not empty if "force" was provided (q.v.)
556#
557#
1f9506ef
MD
558dummy_rc_command()
559{
560 rc_arg=$1
561
562 case "$rc_arg" in
563 fast*) # "fast" prefix; don't check pid
564 rc_arg=${rc_arg#fast}
565 ;;
566 force*) # "force prefix; always start
567 rc_arg=${rc_arg#force}
568 ;;
569 esac
6d94234b
MD
570 set_provide_list $rc_arg $RC_CONFIGURED
571 return 0
1f9506ef
MD
572}
573
9c600e7d
MD
574run_rc_command()
575{
576 _return=0
577 rc_arg=$1
578 if [ -z "$name" ]; then
579 err 3 'run_rc_command: $name is not set.'
580 fi
581
582 case "$rc_arg" in
583 fast*) # "fast" prefix; don't check pid
584 rc_arg=${rc_arg#fast}
585 rc_fast=yes
586 ;;
587 force*) # "force prefix; always start
588 rc_arg=${rc_arg#force}
589 rc_force=yes
590 if [ -n "${rcvar}" ]; then
591 eval ${rcvar}=YES
592 fi
593 ;;
594 esac
595
a613c1fd
MS
596 eval _override_command=\$${name}_program
597 if [ -n "$_override_command" ]; then
598 command=$_override_command
9c600e7d
MD
599 fi
600
601 _keywords="start stop restart rcvar $extra_commands"
602 rc_pid=
603 _pidcmd=
604 _procname=${procname:-${command}}
605
606 # setup pid check command if not fast
607 if [ -z "$rc_fast" -a -n "$_procname" ]; then
608 if [ -n "$pidfile" ]; then
609 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
610 else
611 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
612 fi
613 if [ -n "$_pidcmd" ]; then
614 _keywords="${_keywords} status poll"
615 fi
616 fi
617
618 if [ -z "$rc_arg" ]; then
619 rc_usage "$_keywords"
620 fi
621
622 if [ -n "$flags" ]; then # allow override from environment
623 rc_flags=$flags
624 else
625 eval rc_flags=\$${name}_flags
626 fi
627 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \
628 _nice=\$${name}_nice _user=\$${name}_user \
629 _group=\$${name}_group _groups=\$${name}_groups
630
631 if [ -n "$_user" ]; then # unset $_user if running as that user
632 if [ "$_user" = "$(id -un)" ]; then
633 unset _user
634 fi
635 fi
636
637 # if ${rcvar} is set, and $1 is not
638 # "rcvar", then run
639 # checkyesno ${rcvar}
640 # and return if that failed
641 #
642 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
643 if ! checkyesno ${rcvar}; then
6d94234b 644 set_provide_list $rc_arg $RC_DISABLED
9c600e7d
MD
645 return 0
646 fi
647 fi
648
649 eval $_pidcmd # determine the pid if necessary
650
651 for _elem in $_keywords; do
652 if [ "$_elem" != "$rc_arg" ]; then
653 continue
654 fi
655
656 # if there's a custom ${XXX_cmd},
657 # run that instead of the default
658 #
659 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
660 _postcmd=\$${rc_arg}_postcmd
661 if [ -n "$_cmd" ]; then
662 # if the precmd failed and force
663 # isn't set, exit
664 #
665 if [ -n "$_precmd" ]; then
666 debug "run_rc_command: evaluating ${_precmd}()."
667 eval $_precmd
6d94234b 668
9c600e7d 669 _return=$?
6d94234b 670 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
671 fi
672
673 if [ -n "$_cmd" ]; then
674 debug "run_rc_command: evaluating ${_cmd}()."
675 eval $_cmd
676 _return=$?
6d94234b 677 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
678 fi
679
680 if [ -n "$_postcmd" ]; then
681 debug "run_rc_command: evaluating ${_postcmd}()."
6d94234b 682 eval $_postcmd
9c600e7d 683 _return=$?
6d94234b 684 check_early_term $rc_arg $_return "" || return $(($?-1))
9c600e7d 685 fi
1f9506ef 686 set_provide_list $rc_arg $_return
6d94234b
MD
687 adjust_return_code $_return
688 return $?
9c600e7d
MD
689 fi
690
691 case "$rc_arg" in # default operations...
692
693 status)
694 if [ -n "$rc_pid" ]; then
695 echo "${name} is running as pid $rc_pid."
696 else
697 echo "${name} is not running."
698 return 1
699 fi
700 ;;
701
702 start)
703 if [ -n "$rc_pid" ]; then
704 echo "${name} already running? (pid=$rc_pid)."
705 exit 1
706 fi
707
708 if [ ! -x $command ]; then
709 info "run_rc_command: cannot run ($command)."
6d94234b
MD
710 set_provide_list $rc_arg $RC_FAILED
711 adjust_return_code $RC_FAILED
712 return $?
9c600e7d
MD
713 fi
714
715 # check for required variables,
716 # directories, and files
717 #
718 for _f in $required_vars; do
719 if ! checkyesno $_f; then
720 warn "\$${_f} is not set."
721 if [ -z "$rc_force" ]; then
6d94234b
MD
722 set_provide_list $rc_arg $RC_FAILED
723 adjust_return_code $RC_FAILED
724 return $?
9c600e7d
MD
725 fi
726 fi
727 done
728 for _f in $required_dirs; do
729 if [ ! -d "${_f}/." ]; then
730 warn "${_f} is not a directory."
731 if [ -z "$rc_force" ]; then
6d94234b
MD
732 set_provide_list $rc_arg $RC_FAILED
733 adjust_return_code $RC_FAILED
734 return $?
9c600e7d
MD
735 fi
736 fi
737 done
738 for _f in $required_files; do
739 if [ ! -r "${_f}" ]; then
740 warn "${_f} is not readable."
741 if [ -z "$rc_force" ]; then
6d94234b
MD
742 set_provide_list $rc_arg $RC_FAILED
743 adjust_return_code $RC_FAILED
744 return $?
9c600e7d
MD
745 fi
746 fi
747 done
748
749 # if the precmd failed and force
750 # isn't set, exit
751 #
752 if [ -n "${_precmd}" ]; then
753 debug "run_rc_command: evaluating ${_precmd}()."
754 eval $_precmd
755 _return=$?
6d94234b 756 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
757 fi
758
759 # setup the command to run, and run it
760 #
761 echo "Starting ${name}."
762 if [ -n "$_chroot" ]; then
763 _doit="\
764${_nice:+nice -n $_nice }\
765chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
766$_chroot $command $rc_flags $command_args"
767 else
768 _doit="\
769${_chdir:+cd $_chdir; }\
770${_nice:+nice -n $_nice }\
771$command $rc_flags $command_args"
772 if [ -n "$_user" ]; then
773 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
774 fi
775 fi
776
777 # if the cmd failed and force
778 # isn't set, exit
779 #
780 debug "run_rc_command: _doit: $_doit"
781 eval $_doit
782 _return=$?
6d94234b 783 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
784 # finally, run postcmd
785 #
786 if [ -n "${_postcmd}" ]; then
787 debug "run_rc_command: evaluating ${_postcmd}()."
788 eval $_postcmd
789 fi
790 ;;
791
792 stop)
793 if [ -z "$rc_pid" ]; then
794 if [ -n "$pidfile" ]; then
795 echo \
796 "${name} not running? (check $pidfile)."
797 else
798 echo "${name} not running?"
799 fi
6d94234b 800 set_provide_list $rc_arg $RC_STOPPED
9c600e7d
MD
801 exit 1
802 fi
803
804 # if the precmd failed and force
805 # isn't set, exit
806 #
807 if [ -n $_precmd ]; then
808 eval $_precmd
809 _return=$?
6d94234b 810 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
811 fi
812
813 # send the signal to stop
814 #
815 echo "Stopping ${name}."
816 _doit="kill -${sig_stop:-TERM} $rc_pid"
817 if [ -n "$_user" ]; then
818 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
819 fi
820
821 # if the stop cmd failed and force
822 # isn't set, exit
823 #
824 eval $_doit
825 _return=$?
6d94234b 826 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
827 # wait for the command to exit,
828 # and run postcmd.
c3e1742c 829 sleep 0.1
9c600e7d
MD
830 wait_for_pids $rc_pid
831 if [ -n "$_postcmd" ]; then
832 eval $_postcmd
833 _return=$?
834 fi
835 ;;
836
837 reload)
838 if [ -z "$rc_pid" ]; then
839 if [ -n "$pidfile" ]; then
840 echo \
841 "${name} not running? (check $pidfile)."
842 else
843 echo "${name} not running?"
844 fi
6d94234b 845 set_provide_list $rc_arg $RC_FAILED
9c600e7d
MD
846 exit 1
847 fi
848 echo "Reloading ${name} config files."
849 if [ -n "$_precmd" ]; then
850 eval $_precmd
851 _return=$?
6d94234b 852 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
853 fi
854 _doit="kill -${sig_reload:-HUP} $rc_pid"
855 if [ -n "$_user" ]; then
856 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
857 fi
858 eval $_doit
859 _return=$?
6d94234b 860 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
861 if [ -n "$_postcmd" ]; then
862 eval $_postcmd
863 _return=$?
864 fi
865 ;;
866
867 restart)
868 if [ -n "$_precmd" ]; then
869 eval $_precmd
870 _return=$?
6d94234b 871 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
872 fi
873 # prevent restart being called more
874 # than once by any given script
875 #
876 if [ -n "$_rc_restart_done" ]; then
877 return 0
878 fi
879 _rc_restart_done=YES
880
881 ( $0 ${rc_force:+force}stop )
882 $0 ${rc_force:+force}start
6d94234b 883 _return=$?
9c600e7d
MD
884
885 if [ -n "$_postcmd" ]; then
886 eval $_postcmd
6d94234b 887 adjust_return_code $?
9c600e7d
MD
888 _return=$?
889 fi
6d94234b
MD
890 # Do not set_provide_list(), the start command above
891 # will have done it for us and we do not know the
892 # actual RC code to base a setting on here.
893 #
894 return $_return
9c600e7d
MD
895 ;;
896
897 poll)
898 if [ -n "$rc_pid" ]; then
899 wait_for_pids $rc_pid
900 fi
901 ;;
902
903 rcvar)
904 echo "# $name"
905 if [ -n "$rcvar" ]; then
906 if checkyesno ${rcvar}; then
907 echo "\$${rcvar}=YES"
908 else
909 echo "\$${rcvar}=NO"
910 fi
911 fi
912 ;;
913
914 *)
915 rc_usage "$_keywords"
916 ;;
917
918 esac
6d94234b
MD
919 set_provide_list $rc_arg $_return
920 adjust_return_code $_return
921 return $?
9c600e7d
MD
922 done
923
924 echo 1>&2 "$0: unknown directive '$rc_arg'."
925 rc_usage "$_keywords"
926 exit 1
927}
928
929#
930# run_rc_script file arg
931# Start the script `file' with `arg', and correctly handle the
932# return value from the script. If `file' ends with `.sh', it's
933# sourced into the current environment. If `file' appears to be
934# a backup or scratch file, ignore it. Otherwise if it's
935# executable run as a child process.
936#
937run_rc_script()
938{
939 _file=$1
940 _arg=$2
941 if [ -z "$_file" -o -z "$_arg" ]; then
942 err 3 'USAGE: run_rc_script file arg'
943 fi
944
945 trap "echo 'Reboot interrupted'; exit 1" 3
946
947 unset name command command_args command_interpreter \
948 extra_commands pidfile procname \
949 rcvar required_dirs required_files required_vars
950 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
951
952 case "$_file" in
953 *.sh) # run in current shell
954 set $_arg ; . $_file
955 ;;
956 *[~#]|*.OLD|*.orig) # scratch file; skip
957 warn "Ignoring scratch file $_file"
958 ;;
959 *) # run in subshell
960 if [ -x $_file ]; then
961 if [ -n "$rc_fast_and_loose" ]; then
962 set $_arg ; . $_file
963 else
964 ( trap "echo 'Reboot interrupted'; exit 1" 3
965 set $_arg ; . $_file )
966 fi
967 fi
968 ;;
969 esac
970}
971
972#
973# load_rc_config
974# Source in the configuration file for a given command.
975#
976load_rc_config()
977{
978 _command=$1
979 if [ -z "$_command" ]; then
980 err 3 'USAGE: load_rc_config command'
981 fi
982
983 if [ -z "$_rc_conf_loaded" ]; then
984 if [ -r /etc/defaults/rc.conf ]; then
985 debug "Sourcing /etc/defaults/rc.conf"
986 . /etc/defaults/rc.conf
987 source_rc_confs
988 elif [ -r /etc/rc.conf ]; then
989 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)."
990 . /etc/rc.conf
991 fi
992 _rc_conf_loaded=YES
993 fi
994 if [ -f /etc/rc.conf.d/"$_command" ]; then
995 debug "Sourcing /etc/rc.conf.d/${_command}"
996 . /etc/rc.conf.d/"$_command"
997 fi
998
999 # XXX - Deprecated variable name support
1000 #
9c600e7d
MD
1001 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable"
1002 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program"
1003 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags"
1004 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable"
9c600e7d
MD
1005 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program"
1006 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags"
9c600e7d
MD
1007
1008}
1009
1010#
1011# rc_usage commands
1012# Print a usage string for $0, with `commands' being a list of
1013# valid commands.
1014#
1015rc_usage()
1016{
1017 echo -n 1>&2 "Usage: $0 [fast|force]("
1018
1019 _sep=
1020 for _elem in $*; do
1021 echo -n 1>&2 "$_sep$_elem"
1022 _sep="|"
1023 done
1024 echo 1>&2 ")"
1025 exit 1
1026}
1027
1028#
1029# err exitval message
1030# Display message to stderr and log to the syslog, and exit with exitval.
1031#
1032err()
1033{
1034 exitval=$1
1035 shift
1036
1037 if [ -x /usr/bin/logger ]; then
1038 logger "$0: ERROR: $*"
1039 fi
1040 echo 1>&2 "$0: ERROR: $*"
1041 exit $exitval
1042}
1043
1044#
1045# warn message
1046# Display message to stderr and log to the syslog.
1047#
1048warn()
1049{
1050 if [ -x /usr/bin/logger ]; then
1051 logger "$0: WARNING: $*"
1052 fi
1053 echo 1>&2 "$0: WARNING: $*"
1054}
1055
1056#
1057# info message
1058# Display informational message to stdout and log to syslog.
1059#
1060info()
1061{
778f1b5d
SW
1062 case ${rc_info} in
1063 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1064 if [ -x /usr/bin/logger ]; then
1065 logger "$0: INFO: $*"
1066 fi
1067 echo "$0: INFO: $*"
1068 ;;
1069 esac
9c600e7d
MD
1070}
1071
1072#
1073# debug message
1074# If debugging is enabled in rc.conf output message to stderr.
1075# BEWARE that you don't call any subroutine that itself calls this
1076# function.
1077#
1078debug()
1079{
1080 case ${rc_debug} in
1081 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1082 if [ -x /usr/bin/logger ]; then
1083 logger "$0: INFO: $*"
1084 fi
1085 echo 1>&2 "$0: DEBUG: $*"
1086 ;;
1087 esac
1088}
1089
1090#
1091# backup_file action file cur backup
1092# Make a backup copy of `file' into `cur', and save the previous
1093# version of `cur' as `backup' or use rcs for archiving.
1094#
1095# This routine checks the value of the backup_uses_rcs variable,
1096# which can be either YES or NO.
1097#
1098# The `action' keyword can be one of the following:
1099#
1100# add `file' is now being backed up (and is possibly
1101# being reentered into the backups system). `cur'
1102# is created and RCS files, if necessary, are
1103# created as well.
1104#
1105# update `file' has changed and needs to be backed up.
1106# If `cur' exists, it is copied to to `back' or
1107# checked into RCS (if the repository file is old),
1108# and then `file' is copied to `cur'. Another RCS
1109# check in done here if RCS is being used.
1110#
1111# remove `file' is no longer being tracked by the backups
1112# system. If RCS is not being used, `cur' is moved
1113# to `back', otherwise an empty file is checked in,
1114# and then `cur' is removed.
1115#
1116#
1117backup_file()
1118{
1119 _action=$1
1f9506ef 1120 _cpfile=$2
9c600e7d
MD
1121 _cur=$3
1122 _back=$4
1123
1124 if checkyesno backup_uses_rcs; then
1125 _msg0="backup archive"
1126 _msg1="update"
1127
1128 # ensure that history file is not locked
1129 if [ -f $_cur,v ]; then
1130 rcs -q -u -U -M $_cur
1131 fi
1132
1133 # ensure after switching to rcs that the
1134 # current backup is not lost
1135 if [ -f $_cur ]; then
1136 # no archive, or current newer than archive
1137 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
1138 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1139 rcs -q -kb -U $_cur
1140 co -q -f -u $_cur
1141 fi
1142 fi
1143
1144 case $_action in
1145 add|update)
1f9506ef 1146 cp -p $_cpfile $_cur
9c600e7d
MD
1147 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1148 rcs -q -kb -U $_cur
1149 co -q -f -u $_cur
1150 chown root:wheel $_cur $_cur,v
1151 ;;
1152 remove)
1153 cp /dev/null $_cur
1154 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1155 rcs -q -kb -U $_cur
1156 chown root:wheel $_cur $_cur,v
1157 rm $_cur
1158 ;;
1159 esac
1160 else
1161 case $_action in
1162 add|update)
1163 if [ -f $_cur ]; then
1164 cp -p $_cur $_back
1165 fi
1f9506ef 1166 cp -p $_cpfile $_cur
9c600e7d
MD
1167 chown root:wheel $_cur
1168 ;;
1169 remove)
1170 mv -f $_cur $_back
1171 ;;
1172 esac
1173 fi
1174}