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