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