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