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