]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - etc/rc.subr
Remove unused static variable quantum.
[FreeBSD/FreeBSD.git] / etc / rc.subr
1 # $NetBSD: rc.subr,v 1.28 2000/11/06 00:08:30 lukem Exp $
2 #
3 # Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
4 # All rights reserved.
5 #
6 # This code is derived from software contributed to The NetBSD Foundation
7 # by Luke Mewburn.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions
11 # are met:
12 # 1. Redistributions of source code must retain the above copyright
13 #    notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 #    notice, this list of conditions and the following disclaimer in the
16 #    documentation and/or other materials provided with the distribution.
17 # 3. All advertising materials mentioning features or use of this software
18 #    must display the following acknowledgement:
19 #        This product includes software developed by the NetBSD
20 #        Foundation, Inc. and its contributors.
21 # 4. Neither the name of The NetBSD Foundation nor the names of its
22 #    contributors may be used to endorse or promote products derived
23 #    from this software without specific prior written permission.
24 #
25 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 # POSSIBILITY OF SUCH DAMAGE.
36 #
37 # rc.subr
38 #       functions used by various rc scripts
39 #
40
41 #
42 #       functions
43 #       ---------
44
45 #
46 # checkyesno var
47 #       Test $1 variable, and warn if not set to YES or NO.
48 #       Return 0 if it's "yes" (et al), nonzero otherwise.
49 #
50 checkyesno()
51 {
52         eval _value=\$${1}
53         case $_value in
54
55                 #       "yes", "true", "on", or "1"
56         [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
57                 return 0
58                 ;;
59
60                 #       "no", "false", "off", or "0"
61         [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
62                 return 1
63                 ;;
64         *)
65                 warn "\$${1} is not set properly."
66                 return 1
67                 ;;
68         esac
69 }
70
71 #
72 # mount_critical_filesystems
73 #       Go through the list of critical filesystems, checking each one
74 #       to see if it is mounted, and if it is not, mounting it.
75 #
76 mount_critical_filesystems()
77 {
78         if [ $1 = local ]; then
79                 _fslist=$critical_filesystems_beforenet
80         else
81                 _fslist=$critical_filesystems
82         fi
83         for _fs in $_fslist; do
84                 mount | (
85                         _ismounted=no
86                         while read what _on on _type type; do
87                                 if [ $on = $_fs ]; then
88                                         _ismounted=yes
89                                 fi
90                         done
91                         if [ $_ismounted = no ]; then 
92                                 mount $_fs >/dev/null 2>&1
93                         fi
94                 )  
95         done
96 }
97
98 #
99 # check_pidfile pidfile procname
100 #       Parses the first line of pidfile for a pid, and ensures
101 #       that the process is running and matches procname.
102 #       Prints the matching pid upon success, nothing otherwise.
103 #
104 check_pidfile()
105 {
106         _pidfile=$1
107         _procname=$2
108         if [ -z "$_pidfile" -o -z "$_procname" ]; then
109                 err 3 'USAGE: check_pidfile pidfile procname'
110         fi
111         if [ ! -f $_pidfile ]; then
112                 return
113         fi
114         read _pid _junk < $_pidfile
115         if [ -z "$_pid" ]; then
116                 return
117         fi
118         _procnamebn=${_procname##*/}
119         ps -p $_pid -o 'pid,command' | while read _npid _arg0 _argv; do
120                 if [ "$_npid" = "PID" ]; then
121                         continue
122                 fi
123                 if [   "$_arg0" = "$_procname" \
124                     -o "$_arg0" = "$_procnamebn" \
125                     -o "$_arg0" = "${_procnamebn}:" \
126                     -o "$_arg0" = "(${_procnamebn})" ]; then
127                         echo $_npid
128                         return
129                 fi
130         done
131 }
132
133 #
134 # check_process procname
135 #       Ensures that a process (or processes) named procname is running.
136 #       Prints a list of matching pids.
137 #
138 check_process()
139 {
140         _procname=$1
141         if [ -z "$_procname" ]; then
142                 err 3 'USAGE: check_process procname'
143         fi
144         _procnamebn=${_procname##*/}
145         _pref=
146         ps -ax -o 'pid,command' | while read _npid _arg0 _argv; do
147                 if [ "$_npid" = "PID" ]; then
148                         continue
149                 fi
150                 if [   "$_arg0" = "$_procname" \
151                     -o "$_arg0" = "$_procnamebn" \
152                     -o "$_arg0" = "${_procnamebn}:" \
153                     -o "$_arg0" = "(${_procnamebn})" ]; then
154                         echo -n "$_pref$_npid"
155                         _pref=" "
156                 fi
157         done
158 }
159
160 #
161 # run_rc_command arg
162 #       Search for arg in the list of supported commands, which is:
163 #               "start stop restart rcvar status ${extra_commands}"
164 #       If there's a match, run ${arg}_cmd or the default command (see below).
165 #
166 #       If arg has a given prefix, then change the operation as follows:
167 #               prefix  operation
168 #               ------  ---------
169 #               fast    Skip the pid check.
170 #               force   Set ${rcvar} to YES.
171 #
172 #       The following globals are used:
173 #
174 #       name            needed  function
175 #       ----            ------  --------
176 #       name            y       Name of script.
177 #
178 #       command         n       Full path to command.
179 #                               Not needed if ${arg}_cmd is set for
180 #                               each keyword.
181 #
182 #       command_args    n       Optional args/shell directives for command.
183 #
184 #       extra_commands  n       List of extra commands supported.
185 #
186 #       pidfile         n       If set, use check_pidfile $pidfile, else if
187 #                               $command is set, use check_process $command.
188 #
189 #       rcvar           n       This is checked with checkyesno to determine
190 #                               if the action should be run.
191 #
192 #       ${name}_chroot  n       Directory to chroot to before running ${command}
193 #
194 #       ${name}_chdir   n       Directory to cd to before running ${command}
195 #                               (if not using ${name}_chroot).
196 #
197 #       ${name}_flags   n       Arguments to call ${command} with.
198 #                               NOTE:   $flags from the parent environment
199 #                                       can be used to override this.
200 #
201 #       ${name}_nice    n       Nice level to run ${command} at.
202 #
203 #       ${name}_user    n       User to run ${command} as, using su(1) if not
204 #                               using ${name}_chroot.
205 #
206 #       ${name}_group   n       Group to run chrooted ${command} as.
207 #
208 #       ${name}_groups  n       Supplementary group list to run chrooted
209 #                               ${command} with.
210 #
211 #       ${_arg}_cmd     n       If set, use this as the action when invoked;
212 #                               $_arg is available to the action to use.
213 #                               Otherwise, use default command (see below)
214 #
215 #       ${_arg}_precmd  n       If set, run just before performing the main
216 #                               action in the default command (i.e, after
217 #                               checking for required bits and process
218 #                               (non)existance).
219 #                               If this completes with a non-zero exit code,
220 #                               don't run ${_arg}_cmd.
221 #
222 #       required_dirs   n       If set, check for the existence of the given
223 #                               directories before running the default
224 #                               (re)start command.
225 #
226 #       required_files  n       If set, check for the readability of the given
227 #                               files before running the default (re)start
228 #                               command.
229 #
230 #       required_vars   n       If set, perform checkyesno on each of the
231 #                               listed variables before running the default
232 #                               (re)start command.
233 #
234 #       Default commands for a given arg:
235 #
236 #       arg             default
237 #       ---             -------
238 #       status          Show if ${command} is running, etc.
239 #
240 #       start           if !running && checkyesno ${rcvar}
241 #                               ${command}
242 #
243 #       stop            if ${pidfile}
244 #                               kill $sig_stop `check_pidfile $pidfile`
245 #                       else
246 #                               kill $sig_stop `check_process $command`
247 #                       $sig_stop defaults to TERM.
248 #
249 #       reload          As stop, except use $sig_reload instead.
250 #                       $sig_reload defaults to HUP.
251 #
252 #       restart         Run `stop' then `start'.
253 #
254 #
255 run_rc_command()
256 {
257         _arg=$1
258         if [ -z "$name" ]; then
259                 err 3 '$name is not set.'
260         fi
261
262         case "$_arg" in
263         fast*)                          # "fast" prefix; don't check pid
264                 _arg=${_arg#fast}
265                 _rc_fast_run=YES
266                 ;;
267         force*)                         # "force prefix; always start
268                 _arg=${_arg#force}
269                 _rc_force_run=YES
270                 if [ -n "${rcvar}" ]; then
271                         eval ${rcvar}=YES
272                 fi
273                 ;;
274         esac
275
276         _keywords="start stop restart rcvar $extra_commands"
277         _pid=
278         _pidcmd=
279                                         # setup pid check command if not fast
280         if [ -z "$_rc_fast_run" ]; then
281                 if [ -n "$pidfile" ]; then
282                         _pidcmd='_pid=`check_pidfile '$pidfile' '$command'`'
283                 elif [ -n "$command" ]; then
284                         _pidcmd='_pid=`check_process '$command'`'
285                 fi
286                 if [ -n "$_pidcmd" ]; then
287                         _keywords="${_keywords} status"
288                 fi
289         fi
290
291         if [ -z "$_arg" ]; then
292                 rc_usage "$_keywords"
293         fi
294
295         if [ -n "$flags" ]; then        # allow override from environment
296                 _flags=$flags
297         else
298                 eval _flags=\$${name}_flags
299         fi
300         eval _chdir=\$${name}_chdir
301         eval _chroot=\$${name}_chroot
302         eval _nice=\$${name}_nice
303         eval _user=\$${name}_user
304         eval _group=\$${name}_group
305         eval _groups=\$${name}_groups
306
307                                         # if ${rcvar} is set, and $1 is not
308                                         # "rcvar" or "status", then run
309                                         #       checkyesno ${rcvar}
310                                         # and return if that failed
311                                         #
312         if [ -n "${rcvar}" -a "$_arg" != "rcvar" -a "$_arg" != "status" ]; then
313                 if ! checkyesno ${rcvar}; then
314                         return 0
315                 fi
316         fi
317
318         eval $_pidcmd                   # determine the pid if necessary
319
320         for _elem in $_keywords; do
321                 if [ "$_elem" != "$_arg" ]; then
322                         continue
323                 fi
324
325                                         # if there's a custom ${XXX_cmd},
326                                         # run that instead of the default
327                                         #
328                 eval _cmd=\$${_arg}_cmd
329                 eval _precmd=\$${_arg}_precmd
330                 if [ -n "$_cmd" ]; then
331                                         # if the precmd failed and force
332                                         # isn't set, exit
333                                         #
334                         if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
335                                 return 1
336                         fi
337
338                         eval $_cmd
339                         return 0
340                 fi
341
342                 case "$_arg" in         # default operations...
343
344                 status)
345                         if [ -n "$_pid" ]; then
346                                 echo "${name} is running as pid $_pid."
347                         else
348                                 echo "${name} is not running."
349                                 return 1
350                         fi
351                         ;;
352
353                 start)
354                         if [ -n "$_pid" ]; then
355                                 echo "${name} already running? (pid=$_pid)."
356                                 exit 1
357                         fi
358
359                         if [ ! -x $command ]; then
360                                 return 0
361                         fi
362
363                                         # check for required variables,
364                                         # directories, and files
365                                         #
366                         for _f in $required_vars; do
367                                 if ! checkyesno $_f; then
368                                         warn "\$${_f} is not set."
369                                         if [ -z "$_rc_force_run" ]; then
370                                                 return 1
371                                         fi
372                                 fi
373                         done
374                         for _f in $required_dirs; do
375                                 if [ ! -d "${_f}/." ]; then
376                                         warn "${_f} is not a directory."
377                                         if [ -z "$_rc_force_run" ]; then
378                                                 return 1
379                                         fi
380                                 fi
381                         done
382                         for _f in $required_files; do
383                                 if [ ! -r "${_f}" ]; then
384                                         warn "${_f} is not readable."
385                                         if [ -z "$_rc_force_run" ]; then
386                                                 return 1
387                                         fi
388                                 fi
389                         done
390
391                                         # if the precmd failed and force
392                                         # isn't set, exit
393                                         #
394                         if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
395                                 return 1
396                         fi
397
398
399                                         # setup the command to run, and run it
400                                         #
401                         echo "Starting ${name}."
402                         if [ -n "$_chroot" ]; then
403                                 _doit="\
404 ${_nice:+nice -n $_nice }\
405 chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
406 $_chroot $command $_flags $command_args"
407                         else
408                                 _doit="\
409 ${_user:+su -m $_user -c 'sh -c \"}\
410 ${_chdir:+cd $_chdir; }\
411 ${_nice:+nice -n $_nice }\
412 $command $_flags $command_args\
413 ${_user:+\"'}"
414                         fi
415                         eval $_doit
416                         ;;
417
418                 stop)
419                         if [ -z "$_pid" ]; then
420                                 if [ -n "$pidfile" ]; then
421                                         echo \
422                                     "${name} not running? (check $pidfile)."
423                                 else
424                                         echo "${name} not running?"
425                                 fi
426                                 exit 1
427                         fi
428
429                         if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
430                                 return 1
431                         fi
432                         echo "Stopping ${name}."
433                         _doit=\
434 "${_user:+su -m $_user -c '}kill -${sig_stop:-TERM} $_pid${_user:+'}"
435                         eval $_doit
436                         ;;
437
438                 reload)
439                         if [ -z "$_pid" ]; then
440                                 if [ -n "$pidfile" ]; then
441                                         echo \
442                                     "${name} not running? (check $pidfile)."
443                                 else
444                                         echo "${name} not running?"
445                                 fi
446                                 exit 1
447                         fi
448                         echo "Reloading ${name} config files."
449                         if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
450                                 return 1
451                         fi
452                         _doit=\
453 "${_user:+su -m $_user -c '}kill -${sig_reload:-HUP} $_pid${_user:+'}"
454                         eval $_doit
455                         ;;
456
457                 restart)
458                         if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
459                                 return 1
460                         fi
461                                         # prevent restart being called more
462                                         # than once by any given script
463                                         #
464                         if [ -n "$_rc_restart_done" ]; then
465                                 return 0
466                         fi
467                         _rc_restart_done=YES
468                         ( $0 ${_rc_force_run:+force}stop )
469                         sleep 1
470                         $0 ${_rc_force_run:+force}start
471
472                         ;;
473
474                 rcvar)
475                         echo "# $name"
476                         if [ -n "$rcvar" ]; then
477                                 if checkyesno ${rcvar}; then
478                                         echo "\$${rcvar}=YES"
479                                 else
480                                         echo "\$${rcvar}=NO"
481                                 fi
482                         fi
483                         ;;
484
485                 *)
486                         rc_usage "$_keywords"
487                         ;;
488
489                 esac
490                 return 0
491         done
492
493         echo 1>&2 "$0: unknown directive '$_arg'."
494         rc_usage "$_keywords"
495         exit 1
496 }
497
498 #
499 # run_rc_script file arg
500 #       Start the script `file' with `arg', and correctly handle the
501 #       return value from the script.  If `file' ends with `.sh', it's
502 #       sourced into the current environment.  Otherwise it's run as
503 #       a child process.
504 #
505 #       Note: because `.sh' files are sourced into the current environment
506 #       run_rc_command shouldn't be used because its difficult to ensure
507 #       that the global variable state before and after the sourcing of 
508 #       the .sh file won't adversely affect other scripts.
509 #
510 run_rc_script()
511 {
512         _file=$1
513         _arg=$2
514         if [ -z "$_file" -o -z "$_arg" ]; then
515                 err 3 'USAGE: run_rc_script file arg'
516         fi
517
518         case "$_file" in
519         *.sh)                           # run in current shell
520                 set $_arg ; . $_file
521                 ;;
522         *)                              # run in subshell
523                 ( set $_arg ; . $_file )
524                 ;;
525         esac
526 }
527
528 #
529 # load_rc_config
530 #       Source in the configuration file for a given command.
531 #
532 load_rc_config()
533 {
534         _command=$1
535         if [ -z "$_command" ]; then
536                 err 3 'USAGE: load_rc_config command'
537         fi
538
539         . /etc/rc.conf
540         if [ -f /etc/rc.conf.d/"$_command" ]; then
541                 . /etc/rc.conf.d/"$_command"
542         fi
543 }
544
545
546 #
547 # rc_usage commands
548 #       Print a usage string for $0, with `commands' being a list of
549 #       valid commands.
550 #
551 rc_usage()
552 {
553         echo -n 1>&2 "usage: $0 [fast|force]("
554
555         _sep=
556         for _elem in $*; do
557                 echo -n 1>&2 "$_sep$_elem"
558                 _sep="|"
559         done
560         echo 1>&2 ")"
561         exit 1
562 }
563
564 #
565 # err exitval message
566 #       Display message to stderr and log to the syslog, and exit with exitval.
567 #
568 err()
569 {
570         exitval=$1
571         shift
572
573         logger "$0: ERROR: $*"
574         echo 1>&2 "$0: ERROR: $*"
575         exit $exitval
576 }
577
578 #
579 # warn message
580 #       Display message to stderr and log to the syslog.
581 #
582 warn()
583 {
584         logger "$0: WARNING: $*"
585         echo 1>&2 "$0: WARNING: $*"
586 }