Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[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
dc1d1548 362 _interpbn="$1" # the interpreter binary
9c600e7d
MD
363 _fp_args='_argv'
364 _fp_match='case "$_argv" in
dc1d1548 365 "${_interpbn##*/}: "$_procname*|${_interp}|"${_interp} "*)'
9c600e7d
MD
366 else # a normal daemon
367 _procnamebn=${_procname##*/}
368 _fp_args='_arg0 _argv'
369 _fp_match='case "$_arg0" in
370 $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
371 fi
372
373 _proccheck='
374 ps -o "pid,command" '"$_psargs"' |
375 while read _npid '"$_fp_args"'; do
376 case "$_npid" in
377 PID)
378 continue ;;
379 esac ; '"$_fp_match"'
380 echo -n "$_pref$_npid" ;
381 _pref=" "
382 ;;
383 esac
384 done'
385
386# debug "in _find_processes: proccheck is ($_proccheck)."
387 eval $_proccheck
388}
389
390#
391# wait_for_pids pid [pid ...]
392# spins until none of the pids exist
393#
394wait_for_pids()
395{
396 _list=$*
397 if [ -z "$_list" ]; then
398 return
399 fi
400 _prefix=
401 while true; do
402 _nlist="";
403 for _j in $_list; do
404 if kill -0 $_j 2>/dev/null; then
405 _nlist="${_nlist}${_nlist:+ }$_j"
406 fi
407 done
408 if [ -z "$_nlist" ]; then
409 break
410 fi
411 _list=$_nlist
412 echo -n ${_prefix:-"Waiting for PIDS: "}$_list
413 _prefix=", "
414 sleep 2
415 done
416 if [ -n "$_prefix" ]; then
417 echo "."
418 fi
419}
420
421#
422# run_rc_command argument
423# Search for argument in the list of supported commands, which is:
424# "start stop restart rcvar status poll ${extra_commands}"
425# If there's a match, run ${argument}_cmd or the default method
426# (see below).
427#
428# If argument has a given prefix, then change the operation as follows:
429# Prefix Operation
430# ------ ---------
431# fast Skip the pid check, and set rc_fast=yes
432# force Set ${rcvar} to YES, and set rc_force=yes
433#
434# The following globals are used:
435#
436# Name Needed Purpose
437# ---- ------ -------
1f9506ef
MD
438# provide_list (gen) list of keywords provided by current rcng file
439#
9c600e7d
MD
440# name y Name of script.
441#
442# command n Full path to command.
443# Not needed if ${rc_arg}_cmd is set for
444# each keyword.
445#
446# command_args n Optional args/shell directives for command.
447#
448# command_interpreter n If not empty, command is interpreted, so
449# call check_{pidfile,process}() appropriately.
450#
451# extra_commands n List of extra commands supported.
452#
453# pidfile n If set, use check_pidfile $pidfile $command,
454# otherwise use check_process $command.
455# In either case, only check if $command is set.
456#
457# procname n Process name to check for instead of $command.
458#
459# rcvar n This is checked with checkyesno to determine
460# if the action should be run.
461#
462# ${name}_chroot n Directory to chroot to before running ${command}
463# Requires /usr to be mounted.
464#
465# ${name}_chdir n Directory to cd to before running ${command}
466# (if not using ${name}_chroot).
467#
468# ${name}_flags n Arguments to call ${command} with.
469# NOTE: $flags from the parent environment
470# can be used to override this.
471#
472# ${name}_nice n Nice level to run ${command} at.
473#
474# ${name}_user n User to run ${command} as, using su(1) if not
475# using ${name}_chroot.
476# Requires /usr to be mounted.
477#
478# ${name}_group n Group to run chrooted ${command} as.
479# Requires /usr to be mounted.
480#
481# ${name}_groups n Comma separated list of supplementary groups
482# to run the chrooted ${command} with.
483# Requires /usr to be mounted.
484#
485# ${rc_arg}_cmd n If set, use this as the method when invoked;
486# Otherwise, use default command (see below)
487#
488# ${rc_arg}_precmd n If set, run just before performing the
489# ${rc_arg}_cmd method in the default
490# operation (i.e, after checking for required
491# bits and process (non)existence).
492# If this completes with a non-zero exit code,
493# don't run ${rc_arg}_cmd.
494#
495# ${rc_arg}_postcmd n If set, run just after performing the
496# ${rc_arg}_cmd method, if that method
497# returned a zero exit code.
498#
499# required_dirs n If set, check for the existence of the given
500# directories before running the default
501# (re)start command.
502#
503# required_files n If set, check for the readability of the given
504# files before running the default (re)start
505# command.
506#
507# required_vars n If set, perform checkyesno on each of the
508# listed variables before running the default
509# (re)start command.
510#
511# Default behaviour for a given argument, if no override method is
512# provided:
513#
514# Argument Default behaviour
515# -------- -----------------
516# start if !running && checkyesno ${rcvar}
517# ${command}
518#
519# stop if ${pidfile}
520# rc_pid=$(check_pidfile $pidfile $command)
521# else
522# rc_pid=$(check_process $command)
523# kill $sig_stop $rc_pid
524# wait_for_pids $rc_pid
525# ($sig_stop defaults to TERM.)
526#
527# reload Similar to stop, except use $sig_reload instead,
528# and doesn't wait_for_pids.
529# $sig_reload defaults to HUP.
530#
531# restart Run `stop' then `start'.
532#
533# status Show if ${command} is running, etc.
534#
535# poll Wait for ${command} to exit.
536#
537# rcvar Display what rc.conf variable is used (if any).
538#
539# Variables available to methods, and after run_rc_command() has
540# completed:
541#
542# Variable Purpose
543# -------- -------
544# rc_arg Argument to command, after fast/force processing
545# performed
546#
547# rc_flags Flags to start the default command with.
548# Defaults to ${name}_flags, unless overridden
549# by $flags from the environment.
550# This variable may be changed by the precmd method.
551#
552# rc_pid PID of command (if appropriate)
553#
554# rc_fast Not empty if "fast" was provided (q.v.)
555#
556# rc_force Not empty if "force" was provided (q.v.)
557#
558#
1f9506ef
MD
559dummy_rc_command()
560{
561 rc_arg=$1
562
563 case "$rc_arg" in
564 fast*) # "fast" prefix; don't check pid
565 rc_arg=${rc_arg#fast}
566 ;;
567 force*) # "force prefix; always start
568 rc_arg=${rc_arg#force}
569 ;;
570 esac
6d94234b
MD
571 set_provide_list $rc_arg $RC_CONFIGURED
572 return 0
1f9506ef
MD
573}
574
9c600e7d
MD
575run_rc_command()
576{
577 _return=0
578 rc_arg=$1
579 if [ -z "$name" ]; then
580 err 3 'run_rc_command: $name is not set.'
581 fi
582
583 case "$rc_arg" in
584 fast*) # "fast" prefix; don't check pid
585 rc_arg=${rc_arg#fast}
586 rc_fast=yes
587 ;;
588 force*) # "force prefix; always start
589 rc_arg=${rc_arg#force}
590 rc_force=yes
591 if [ -n "${rcvar}" ]; then
592 eval ${rcvar}=YES
593 fi
594 ;;
595 esac
596
a613c1fd
MS
597 eval _override_command=\$${name}_program
598 if [ -n "$_override_command" ]; then
599 command=$_override_command
9c600e7d
MD
600 fi
601
602 _keywords="start stop restart rcvar $extra_commands"
603 rc_pid=
604 _pidcmd=
605 _procname=${procname:-${command}}
606
607 # setup pid check command if not fast
608 if [ -z "$rc_fast" -a -n "$_procname" ]; then
609 if [ -n "$pidfile" ]; then
610 _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
611 else
612 _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
613 fi
614 if [ -n "$_pidcmd" ]; then
615 _keywords="${_keywords} status poll"
616 fi
617 fi
618
619 if [ -z "$rc_arg" ]; then
620 rc_usage "$_keywords"
621 fi
622
623 if [ -n "$flags" ]; then # allow override from environment
624 rc_flags=$flags
625 else
626 eval rc_flags=\$${name}_flags
627 fi
628 eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \
629 _nice=\$${name}_nice _user=\$${name}_user \
630 _group=\$${name}_group _groups=\$${name}_groups
631
632 if [ -n "$_user" ]; then # unset $_user if running as that user
633 if [ "$_user" = "$(id -un)" ]; then
634 unset _user
635 fi
636 fi
637
638 # if ${rcvar} is set, and $1 is not
639 # "rcvar", then run
640 # checkyesno ${rcvar}
641 # and return if that failed
642 #
643 if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
644 if ! checkyesno ${rcvar}; then
6d94234b 645 set_provide_list $rc_arg $RC_DISABLED
9c600e7d
MD
646 return 0
647 fi
648 fi
649
650 eval $_pidcmd # determine the pid if necessary
651
652 for _elem in $_keywords; do
653 if [ "$_elem" != "$rc_arg" ]; then
654 continue
655 fi
656
657 # if there's a custom ${XXX_cmd},
658 # run that instead of the default
659 #
660 eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
661 _postcmd=\$${rc_arg}_postcmd
662 if [ -n "$_cmd" ]; then
663 # if the precmd failed and force
664 # isn't set, exit
665 #
666 if [ -n "$_precmd" ]; then
667 debug "run_rc_command: evaluating ${_precmd}()."
668 eval $_precmd
6d94234b 669
9c600e7d 670 _return=$?
6d94234b 671 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
672 fi
673
674 if [ -n "$_cmd" ]; then
675 debug "run_rc_command: evaluating ${_cmd}()."
676 eval $_cmd
677 _return=$?
6d94234b 678 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
679 fi
680
681 if [ -n "$_postcmd" ]; then
682 debug "run_rc_command: evaluating ${_postcmd}()."
6d94234b 683 eval $_postcmd
9c600e7d 684 _return=$?
6d94234b 685 check_early_term $rc_arg $_return "" || return $(($?-1))
9c600e7d 686 fi
1f9506ef 687 set_provide_list $rc_arg $_return
6d94234b
MD
688 adjust_return_code $_return
689 return $?
9c600e7d
MD
690 fi
691
692 case "$rc_arg" in # default operations...
693
694 status)
695 if [ -n "$rc_pid" ]; then
696 echo "${name} is running as pid $rc_pid."
697 else
698 echo "${name} is not running."
699 return 1
700 fi
701 ;;
702
703 start)
704 if [ -n "$rc_pid" ]; then
705 echo "${name} already running? (pid=$rc_pid)."
706 exit 1
707 fi
708
709 if [ ! -x $command ]; then
710 info "run_rc_command: cannot run ($command)."
6d94234b
MD
711 set_provide_list $rc_arg $RC_FAILED
712 adjust_return_code $RC_FAILED
713 return $?
9c600e7d
MD
714 fi
715
716 # check for required variables,
717 # directories, and files
718 #
719 for _f in $required_vars; do
720 if ! checkyesno $_f; then
721 warn "\$${_f} is not set."
722 if [ -z "$rc_force" ]; then
6d94234b
MD
723 set_provide_list $rc_arg $RC_FAILED
724 adjust_return_code $RC_FAILED
725 return $?
9c600e7d
MD
726 fi
727 fi
728 done
729 for _f in $required_dirs; do
730 if [ ! -d "${_f}/." ]; then
731 warn "${_f} is not a directory."
732 if [ -z "$rc_force" ]; then
6d94234b
MD
733 set_provide_list $rc_arg $RC_FAILED
734 adjust_return_code $RC_FAILED
735 return $?
9c600e7d
MD
736 fi
737 fi
738 done
739 for _f in $required_files; do
740 if [ ! -r "${_f}" ]; then
741 warn "${_f} is not readable."
742 if [ -z "$rc_force" ]; then
6d94234b
MD
743 set_provide_list $rc_arg $RC_FAILED
744 adjust_return_code $RC_FAILED
745 return $?
9c600e7d
MD
746 fi
747 fi
748 done
749
750 # if the precmd failed and force
751 # isn't set, exit
752 #
753 if [ -n "${_precmd}" ]; then
754 debug "run_rc_command: evaluating ${_precmd}()."
755 eval $_precmd
756 _return=$?
6d94234b 757 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
758 fi
759
760 # setup the command to run, and run it
761 #
762 echo "Starting ${name}."
763 if [ -n "$_chroot" ]; then
764 _doit="\
765${_nice:+nice -n $_nice }\
766chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
767$_chroot $command $rc_flags $command_args"
768 else
769 _doit="\
770${_chdir:+cd $_chdir; }\
771${_nice:+nice -n $_nice }\
772$command $rc_flags $command_args"
773 if [ -n "$_user" ]; then
774 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
775 fi
776 fi
777
778 # if the cmd failed and force
779 # isn't set, exit
780 #
781 debug "run_rc_command: _doit: $_doit"
782 eval $_doit
783 _return=$?
6d94234b 784 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
785 # finally, run postcmd
786 #
787 if [ -n "${_postcmd}" ]; then
788 debug "run_rc_command: evaluating ${_postcmd}()."
789 eval $_postcmd
790 fi
791 ;;
792
793 stop)
794 if [ -z "$rc_pid" ]; then
795 if [ -n "$pidfile" ]; then
796 echo \
797 "${name} not running? (check $pidfile)."
798 else
799 echo "${name} not running?"
800 fi
6d94234b 801 set_provide_list $rc_arg $RC_STOPPED
9c600e7d
MD
802 exit 1
803 fi
804
805 # if the precmd failed and force
806 # isn't set, exit
807 #
808 if [ -n $_precmd ]; then
809 eval $_precmd
810 _return=$?
6d94234b 811 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
812 fi
813
814 # send the signal to stop
815 #
816 echo "Stopping ${name}."
817 _doit="kill -${sig_stop:-TERM} $rc_pid"
818 if [ -n "$_user" ]; then
819 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
820 fi
821
822 # if the stop cmd failed and force
823 # isn't set, exit
824 #
825 eval $_doit
826 _return=$?
6d94234b 827 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
828 # wait for the command to exit,
829 # and run postcmd.
c3e1742c 830 sleep 0.1
9c600e7d
MD
831 wait_for_pids $rc_pid
832 if [ -n "$_postcmd" ]; then
833 eval $_postcmd
834 _return=$?
835 fi
836 ;;
837
838 reload)
839 if [ -z "$rc_pid" ]; then
840 if [ -n "$pidfile" ]; then
841 echo \
842 "${name} not running? (check $pidfile)."
843 else
844 echo "${name} not running?"
845 fi
6d94234b 846 set_provide_list $rc_arg $RC_FAILED
9c600e7d
MD
847 exit 1
848 fi
849 echo "Reloading ${name} config files."
850 if [ -n "$_precmd" ]; then
851 eval $_precmd
852 _return=$?
6d94234b 853 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
854 fi
855 _doit="kill -${sig_reload:-HUP} $rc_pid"
856 if [ -n "$_user" ]; then
857 _doit="su -m $_user -c 'sh -c \"$_doit\"'"
858 fi
859 eval $_doit
860 _return=$?
6d94234b 861 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
862 if [ -n "$_postcmd" ]; then
863 eval $_postcmd
864 _return=$?
865 fi
866 ;;
867
868 restart)
869 if [ -n "$_precmd" ]; then
870 eval $_precmd
871 _return=$?
6d94234b 872 check_early_term $rc_arg $_return "$rc_force" || return $(($?-1))
9c600e7d
MD
873 fi
874 # prevent restart being called more
875 # than once by any given script
876 #
877 if [ -n "$_rc_restart_done" ]; then
878 return 0
879 fi
880 _rc_restart_done=YES
881
882 ( $0 ${rc_force:+force}stop )
883 $0 ${rc_force:+force}start
6d94234b 884 _return=$?
9c600e7d
MD
885
886 if [ -n "$_postcmd" ]; then
887 eval $_postcmd
6d94234b 888 adjust_return_code $?
9c600e7d
MD
889 _return=$?
890 fi
6d94234b
MD
891 # Do not set_provide_list(), the start command above
892 # will have done it for us and we do not know the
893 # actual RC code to base a setting on here.
894 #
895 return $_return
9c600e7d
MD
896 ;;
897
898 poll)
899 if [ -n "$rc_pid" ]; then
900 wait_for_pids $rc_pid
901 fi
902 ;;
903
904 rcvar)
905 echo "# $name"
906 if [ -n "$rcvar" ]; then
907 if checkyesno ${rcvar}; then
908 echo "\$${rcvar}=YES"
909 else
910 echo "\$${rcvar}=NO"
911 fi
912 fi
913 ;;
914
915 *)
916 rc_usage "$_keywords"
917 ;;
918
919 esac
6d94234b
MD
920 set_provide_list $rc_arg $_return
921 adjust_return_code $_return
922 return $?
9c600e7d
MD
923 done
924
925 echo 1>&2 "$0: unknown directive '$rc_arg'."
926 rc_usage "$_keywords"
927 exit 1
928}
929
930#
931# run_rc_script file arg
932# Start the script `file' with `arg', and correctly handle the
933# return value from the script. If `file' ends with `.sh', it's
934# sourced into the current environment. If `file' appears to be
935# a backup or scratch file, ignore it. Otherwise if it's
936# executable run as a child process.
937#
938run_rc_script()
939{
940 _file=$1
941 _arg=$2
942 if [ -z "$_file" -o -z "$_arg" ]; then
943 err 3 'USAGE: run_rc_script file arg'
944 fi
945
946 trap "echo 'Reboot interrupted'; exit 1" 3
947
948 unset name command command_args command_interpreter \
949 extra_commands pidfile procname \
950 rcvar required_dirs required_files required_vars
951 eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
952
953 case "$_file" in
954 *.sh) # run in current shell
955 set $_arg ; . $_file
956 ;;
957 *[~#]|*.OLD|*.orig) # scratch file; skip
958 warn "Ignoring scratch file $_file"
959 ;;
960 *) # run in subshell
961 if [ -x $_file ]; then
962 if [ -n "$rc_fast_and_loose" ]; then
963 set $_arg ; . $_file
964 else
965 ( trap "echo 'Reboot interrupted'; exit 1" 3
966 set $_arg ; . $_file )
967 fi
968 fi
969 ;;
970 esac
971}
972
665fe72b
RP
973# ltr str src dst
974# Change every $src in $str to $dst.
975# Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor
976# awk(1).
977ltr()
978{
979 local _str _src _dst _out _com
980 _str=$1
981 _src=$2
982 _dst=$3
983 _out=""
984
985 IFS=${_src}
986 for _com in ${_str}; do
987 if [ -z "${_out}" ]; then
988 _out="${_com}"
989 else
990 _out="${_out}${_dst}${_com}"
991 fi
992 done
993 echo "${_out}"
994}
995
9c600e7d
MD
996#
997# load_rc_config
998# Source in the configuration file for a given command.
999#
1000load_rc_config()
1001{
1002 _command=$1
1003 if [ -z "$_command" ]; then
1004 err 3 'USAGE: load_rc_config command'
1005 fi
1006
1007 if [ -z "$_rc_conf_loaded" ]; then
1008 if [ -r /etc/defaults/rc.conf ]; then
1009 debug "Sourcing /etc/defaults/rc.conf"
1010 . /etc/defaults/rc.conf
1011 source_rc_confs
1012 elif [ -r /etc/rc.conf ]; then
1013 debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)."
1014 . /etc/rc.conf
1015 fi
1016 _rc_conf_loaded=YES
1017 fi
1018 if [ -f /etc/rc.conf.d/"$_command" ]; then
1019 debug "Sourcing /etc/rc.conf.d/${_command}"
1020 . /etc/rc.conf.d/"$_command"
1021 fi
1022
1023 # XXX - Deprecated variable name support
1024 #
9c600e7d
MD
1025 [ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable"
1026 [ -n "$portmap_program" ] && rpcbind_program="$portmap_program"
1027 [ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags"
1028 [ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable"
9c600e7d
MD
1029 [ -n "$dhcp_program" ] && dhclient_program="$dhcp_program"
1030 [ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags"
9c600e7d
MD
1031
1032}
1033
1034#
1035# rc_usage commands
1036# Print a usage string for $0, with `commands' being a list of
1037# valid commands.
1038#
1039rc_usage()
1040{
1041 echo -n 1>&2 "Usage: $0 [fast|force]("
1042
1043 _sep=
1044 for _elem in $*; do
1045 echo -n 1>&2 "$_sep$_elem"
1046 _sep="|"
1047 done
1048 echo 1>&2 ")"
1049 exit 1
1050}
1051
1052#
1053# err exitval message
1054# Display message to stderr and log to the syslog, and exit with exitval.
1055#
1056err()
1057{
1058 exitval=$1
1059 shift
1060
1061 if [ -x /usr/bin/logger ]; then
1062 logger "$0: ERROR: $*"
1063 fi
1064 echo 1>&2 "$0: ERROR: $*"
1065 exit $exitval
1066}
1067
1068#
1069# warn message
1070# Display message to stderr and log to the syslog.
1071#
1072warn()
1073{
1074 if [ -x /usr/bin/logger ]; then
1075 logger "$0: WARNING: $*"
1076 fi
1077 echo 1>&2 "$0: WARNING: $*"
1078}
1079
1080#
1081# info message
1082# Display informational message to stdout and log to syslog.
1083#
1084info()
1085{
778f1b5d
SW
1086 case ${rc_info} in
1087 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1088 if [ -x /usr/bin/logger ]; then
1089 logger "$0: INFO: $*"
1090 fi
1091 echo "$0: INFO: $*"
1092 ;;
1093 esac
9c600e7d
MD
1094}
1095
1096#
1097# debug message
1098# If debugging is enabled in rc.conf output message to stderr.
1099# BEWARE that you don't call any subroutine that itself calls this
1100# function.
1101#
1102debug()
1103{
1104 case ${rc_debug} in
1105 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
1106 if [ -x /usr/bin/logger ]; then
1107 logger "$0: INFO: $*"
1108 fi
1109 echo 1>&2 "$0: DEBUG: $*"
1110 ;;
1111 esac
1112}
1113
1114#
1115# backup_file action file cur backup
1116# Make a backup copy of `file' into `cur', and save the previous
1117# version of `cur' as `backup' or use rcs for archiving.
1118#
1119# This routine checks the value of the backup_uses_rcs variable,
1120# which can be either YES or NO.
1121#
1122# The `action' keyword can be one of the following:
1123#
1124# add `file' is now being backed up (and is possibly
1125# being reentered into the backups system). `cur'
1126# is created and RCS files, if necessary, are
1127# created as well.
1128#
1129# update `file' has changed and needs to be backed up.
1130# If `cur' exists, it is copied to to `back' or
1131# checked into RCS (if the repository file is old),
1132# and then `file' is copied to `cur'. Another RCS
1133# check in done here if RCS is being used.
1134#
1135# remove `file' is no longer being tracked by the backups
1136# system. If RCS is not being used, `cur' is moved
1137# to `back', otherwise an empty file is checked in,
1138# and then `cur' is removed.
1139#
1140#
1141backup_file()
1142{
1143 _action=$1
1f9506ef 1144 _cpfile=$2
9c600e7d
MD
1145 _cur=$3
1146 _back=$4
1147
1148 if checkyesno backup_uses_rcs; then
1149 _msg0="backup archive"
1150 _msg1="update"
1151
1152 # ensure that history file is not locked
1153 if [ -f $_cur,v ]; then
1154 rcs -q -u -U -M $_cur
1155 fi
1156
1157 # ensure after switching to rcs that the
1158 # current backup is not lost
1159 if [ -f $_cur ]; then
1160 # no archive, or current newer than archive
1161 if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
1162 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1163 rcs -q -kb -U $_cur
1164 co -q -f -u $_cur
1165 fi
1166 fi
1167
1168 case $_action in
1169 add|update)
1f9506ef 1170 cp -p $_cpfile $_cur
9c600e7d
MD
1171 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1172 rcs -q -kb -U $_cur
1173 co -q -f -u $_cur
1174 chown root:wheel $_cur $_cur,v
1175 ;;
1176 remove)
1177 cp /dev/null $_cur
1178 ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
1179 rcs -q -kb -U $_cur
1180 chown root:wheel $_cur $_cur,v
1181 rm $_cur
1182 ;;
1183 esac
1184 else
1185 case $_action in
1186 add|update)
1187 if [ -f $_cur ]; then
1188 cp -p $_cur $_back
1189 fi
1f9506ef 1190 cp -p $_cpfile $_cur
9c600e7d
MD
1191 chown root:wheel $_cur
1192 ;;
1193 remove)
1194 mv -f $_cur $_back
1195 ;;
1196 esac
1197 fi
1198}