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