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