c47a806047
- only load rc.conf if $_rc_conf_loaded is not set - use case instead of if for various string comparisons - print the date at the start of the boot as well as at the end - if $rc_fast_and_loose is set, always run the rc.d scripts in the current shell rather than in a subshell. this is not on by default because it's potentially dangerous (a rogue command could terminate the boot), but it is provided as an optional speedup for people with slow machines that have an expensive fork
594 lines
14 KiB
Plaintext
594 lines
14 KiB
Plaintext
# $NetBSD: rc.subr,v 1.30 2001/02/28 16:49:19 lukem Exp $
|
|
#
|
|
# Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Luke Mewburn.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# 3. All advertising materials mentioning features or use of this software
|
|
# must display the following acknowledgement:
|
|
# This product includes software developed by the NetBSD
|
|
# Foundation, Inc. and its contributors.
|
|
# 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
# contributors may be used to endorse or promote products derived
|
|
# from this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# rc.subr
|
|
# functions used by various rc scripts
|
|
#
|
|
|
|
#
|
|
# functions
|
|
# ---------
|
|
|
|
#
|
|
# checkyesno var
|
|
# Test $1 variable, and warn if not set to YES or NO.
|
|
# Return 0 if it's "yes" (et al), nonzero otherwise.
|
|
#
|
|
checkyesno()
|
|
{
|
|
eval _value=\$${1}
|
|
case $_value in
|
|
|
|
# "yes", "true", "on", or "1"
|
|
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
|
|
return 0
|
|
;;
|
|
|
|
# "no", "false", "off", or "0"
|
|
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
|
|
return 1
|
|
;;
|
|
*)
|
|
warn "\$${1} is not set properly."
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# mount_critical_filesystems
|
|
# Go through the list of critical filesystems, checking each one
|
|
# to see if it is mounted, and if it is not, mounting it.
|
|
#
|
|
mount_critical_filesystems()
|
|
{
|
|
if [ $1 = local ]; then
|
|
_fslist=$critical_filesystems_beforenet
|
|
else
|
|
_fslist=$critical_filesystems
|
|
fi
|
|
for _fs in $_fslist; do
|
|
mount | (
|
|
_ismounted=no
|
|
while read what _on on _type type; do
|
|
if [ $on = $_fs ]; then
|
|
_ismounted=yes
|
|
fi
|
|
done
|
|
if [ $_ismounted = no ]; then
|
|
mount $_fs >/dev/null 2>&1
|
|
fi
|
|
)
|
|
done
|
|
}
|
|
|
|
#
|
|
# check_pidfile pidfile procname
|
|
# Parses the first line of pidfile for a pid, and ensures
|
|
# that the process is running and matches procname.
|
|
# Prints the matching pid upon success, nothing otherwise.
|
|
#
|
|
check_pidfile()
|
|
{
|
|
_pidfile=$1
|
|
_procname=$2
|
|
if [ -z "$_pidfile" -o -z "$_procname" ]; then
|
|
err 3 'USAGE: check_pidfile pidfile procname'
|
|
fi
|
|
if [ ! -f $_pidfile ]; then
|
|
return
|
|
fi
|
|
read _pid _junk < $_pidfile
|
|
if [ -z "$_pid" ]; then
|
|
return
|
|
fi
|
|
_procnamebn=${_procname##*/}
|
|
ps -p $_pid -o 'pid,command' | while read _npid _arg0 _argv; do
|
|
case "$_npid" in
|
|
PID)
|
|
continue ;;
|
|
esac
|
|
case "$_arg0" in
|
|
$_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")
|
|
echo $_npid
|
|
return
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#
|
|
# check_process procname
|
|
# Ensures that a process (or processes) named procname is running.
|
|
# Prints a list of matching pids.
|
|
#
|
|
check_process()
|
|
{
|
|
_procname=$1
|
|
if [ -z "$_procname" ]; then
|
|
err 3 'USAGE: check_process procname'
|
|
fi
|
|
_procnamebn=${_procname##*/}
|
|
_pref=
|
|
ps -ax -o 'pid,command' | while read _npid _arg0 _argv; do
|
|
case "$_npid" in
|
|
PID)
|
|
continue ;;
|
|
esac
|
|
case "$_arg0" in
|
|
$_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")
|
|
echo -n "$_pref$_npid"
|
|
_pref=" "
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
#
|
|
# run_rc_command arg
|
|
# Search for arg in the list of supported commands, which is:
|
|
# "start stop restart rcvar status ${extra_commands}"
|
|
# If there's a match, run ${arg}_cmd or the default command (see below).
|
|
#
|
|
# If arg has a given prefix, then change the operation as follows:
|
|
# prefix operation
|
|
# ------ ---------
|
|
# fast Skip the pid check.
|
|
# force Set ${rcvar} to YES.
|
|
#
|
|
# The following globals are used:
|
|
#
|
|
# name needed function
|
|
# ---- ------ --------
|
|
# name y Name of script.
|
|
#
|
|
# command n Full path to command.
|
|
# Not needed if ${arg}_cmd is set for
|
|
# each keyword.
|
|
#
|
|
# command_args n Optional args/shell directives for command.
|
|
#
|
|
# extra_commands n List of extra commands supported.
|
|
#
|
|
# pidfile n If set, use check_pidfile $pidfile, else if
|
|
# $command is set, use check_process $command.
|
|
#
|
|
# rcvar n This is checked with checkyesno to determine
|
|
# if the action should be run.
|
|
#
|
|
# ${name}_chroot n Directory to chroot to before running ${command}
|
|
#
|
|
# ${name}_chdir n Directory to cd to before running ${command}
|
|
# (if not using ${name}_chroot).
|
|
#
|
|
# ${name}_flags n Arguments to call ${command} with.
|
|
# NOTE: $flags from the parent environment
|
|
# can be used to override this.
|
|
#
|
|
# ${name}_nice n Nice level to run ${command} at.
|
|
#
|
|
# ${name}_user n User to run ${command} as, using su(1) if not
|
|
# using ${name}_chroot.
|
|
#
|
|
# ${name}_group n Group to run chrooted ${command} as.
|
|
#
|
|
# ${name}_groups n Supplementary group list to run chrooted
|
|
# ${command} with.
|
|
#
|
|
# ${_arg}_cmd n If set, use this as the action when invoked;
|
|
# $_arg is available to the action to use.
|
|
# Otherwise, use default command (see below)
|
|
#
|
|
# ${_arg}_precmd n If set, run just before performing the main
|
|
# action in the default command (i.e, after
|
|
# checking for required bits and process
|
|
# (non)existance).
|
|
# If this completes with a non-zero exit code,
|
|
# don't run ${_arg}_cmd.
|
|
#
|
|
# required_dirs n If set, check for the existence of the given
|
|
# directories before running the default
|
|
# (re)start command.
|
|
#
|
|
# required_files n If set, check for the readability of the given
|
|
# files before running the default (re)start
|
|
# command.
|
|
#
|
|
# required_vars n If set, perform checkyesno on each of the
|
|
# listed variables before running the default
|
|
# (re)start command.
|
|
#
|
|
# Default commands for a given arg:
|
|
#
|
|
# arg default
|
|
# --- -------
|
|
# status Show if ${command} is running, etc.
|
|
#
|
|
# start if !running && checkyesno ${rcvar}
|
|
# ${command}
|
|
#
|
|
# stop if ${pidfile}
|
|
# kill $sig_stop `check_pidfile $pidfile`
|
|
# else
|
|
# kill $sig_stop `check_process $command`
|
|
# $sig_stop defaults to TERM.
|
|
#
|
|
# reload As stop, except use $sig_reload instead.
|
|
# $sig_reload defaults to HUP.
|
|
#
|
|
# restart Run `stop' then `start'.
|
|
#
|
|
#
|
|
run_rc_command()
|
|
{
|
|
_arg=$1
|
|
if [ -z "$name" ]; then
|
|
err 3 'run_rc_command: $name is not set.'
|
|
fi
|
|
|
|
case "$_arg" in
|
|
fast*) # "fast" prefix; don't check pid
|
|
_arg=${_arg#fast}
|
|
_rc_fast_run=YES
|
|
;;
|
|
force*) # "force prefix; always start
|
|
_arg=${_arg#force}
|
|
_rc_force_run=YES
|
|
if [ -n "${rcvar}" ]; then
|
|
eval ${rcvar}=YES
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
_keywords="start stop restart rcvar $extra_commands"
|
|
_pid=
|
|
_pidcmd=
|
|
# setup pid check command if not fast
|
|
if [ -z "$_rc_fast_run" ]; then
|
|
if [ -n "$pidfile" ]; then
|
|
_pidcmd='_pid=`check_pidfile '$pidfile' '$command'`'
|
|
elif [ -n "$command" ]; then
|
|
_pidcmd='_pid=`check_process '$command'`'
|
|
fi
|
|
if [ -n "$_pidcmd" ]; then
|
|
_keywords="${_keywords} status"
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$_arg" ]; then
|
|
rc_usage "$_keywords"
|
|
fi
|
|
|
|
if [ -n "$flags" ]; then # allow override from environment
|
|
_flags=$flags
|
|
else
|
|
eval _flags=\$${name}_flags
|
|
fi
|
|
eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \
|
|
_nice=\$${name}_nice _user=\$${name}_user \
|
|
_group=\$${name}_group _groups=\$${name}_groups
|
|
|
|
# if ${rcvar} is set, and $1 is not
|
|
# "rcvar" or "status", then run
|
|
# checkyesno ${rcvar}
|
|
# and return if that failed
|
|
#
|
|
# XXXX use case?
|
|
if [ -n "${rcvar}" -a "$_arg" != "rcvar" -a "$_arg" != "status" ]; then
|
|
if ! checkyesno ${rcvar}; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
eval $_pidcmd # determine the pid if necessary
|
|
|
|
for _elem in $_keywords; do
|
|
if [ "$_elem" != "$_arg" ]; then
|
|
continue
|
|
fi
|
|
|
|
# if there's a custom ${XXX_cmd},
|
|
# run that instead of the default
|
|
#
|
|
eval _cmd=\$${_arg}_cmd _precmd=\$${_arg}_precmd
|
|
if [ -n "$_cmd" ]; then
|
|
# if the precmd failed and force
|
|
# isn't set, exit
|
|
#
|
|
if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
|
|
eval $_cmd
|
|
return 0
|
|
fi
|
|
|
|
case "$_arg" in # default operations...
|
|
|
|
status)
|
|
if [ -n "$_pid" ]; then
|
|
echo "${name} is running as pid $_pid."
|
|
else
|
|
echo "${name} is not running."
|
|
return 1
|
|
fi
|
|
;;
|
|
|
|
start)
|
|
if [ -n "$_pid" ]; then
|
|
echo "${name} already running? (pid=$_pid)."
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -x $command ]; then
|
|
return 0
|
|
fi
|
|
|
|
# check for required variables,
|
|
# directories, and files
|
|
#
|
|
for _f in $required_vars; do
|
|
if ! checkyesno $_f; then
|
|
warn "\$${_f} is not set."
|
|
if [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
fi
|
|
done
|
|
for _f in $required_dirs; do
|
|
if [ ! -d "${_f}/." ]; then
|
|
warn "${_f} is not a directory."
|
|
if [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
fi
|
|
done
|
|
for _f in $required_files; do
|
|
if [ ! -r "${_f}" ]; then
|
|
warn "${_f} is not readable."
|
|
if [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# if the precmd failed and force
|
|
# isn't set, exit
|
|
#
|
|
if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
|
|
|
|
# setup the command to run, and run it
|
|
#
|
|
echo "Starting ${name}."
|
|
if [ -n "$_chroot" ]; then
|
|
_doit="\
|
|
${_nice:+nice -n $_nice }\
|
|
chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
|
|
$_chroot $command $_flags $command_args"
|
|
else
|
|
_doit="\
|
|
${_user:+su -m $_user -c 'sh -c \"}\
|
|
${_chdir:+cd $_chdir; }\
|
|
${_nice:+nice -n $_nice }\
|
|
$command $_flags $command_args\
|
|
${_user:+\"'}"
|
|
fi
|
|
eval $_doit
|
|
;;
|
|
|
|
stop)
|
|
if [ -z "$_pid" ]; then
|
|
if [ -n "$pidfile" ]; then
|
|
echo \
|
|
"${name} not running? (check $pidfile)."
|
|
else
|
|
echo "${name} not running?"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
echo "Stopping ${name}."
|
|
_doit=\
|
|
"${_user:+su -m $_user -c '}kill -${sig_stop:-TERM} $_pid${_user:+'}"
|
|
eval $_doit
|
|
;;
|
|
|
|
reload)
|
|
if [ -z "$_pid" ]; then
|
|
if [ -n "$pidfile" ]; then
|
|
echo \
|
|
"${name} not running? (check $pidfile)."
|
|
else
|
|
echo "${name} not running?"
|
|
fi
|
|
exit 1
|
|
fi
|
|
echo "Reloading ${name} config files."
|
|
if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
_doit=\
|
|
"${_user:+su -m $_user -c '}kill -${sig_reload:-HUP} $_pid${_user:+'}"
|
|
eval $_doit
|
|
;;
|
|
|
|
restart)
|
|
if ! eval $_precmd && [ -z "$_rc_force_run" ]; then
|
|
return 1
|
|
fi
|
|
# prevent restart being called more
|
|
# than once by any given script
|
|
#
|
|
if [ -n "$_rc_restart_done" ]; then
|
|
return 0
|
|
fi
|
|
_rc_restart_done=YES
|
|
( $0 ${_rc_force_run:+force}stop )
|
|
sleep 1
|
|
$0 ${_rc_force_run:+force}start
|
|
|
|
;;
|
|
|
|
rcvar)
|
|
echo "# $name"
|
|
if [ -n "$rcvar" ]; then
|
|
if checkyesno ${rcvar}; then
|
|
echo "\$${rcvar}=YES"
|
|
else
|
|
echo "\$${rcvar}=NO"
|
|
fi
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
rc_usage "$_keywords"
|
|
;;
|
|
|
|
esac
|
|
return 0
|
|
done
|
|
|
|
echo 1>&2 "$0: unknown directive '$_arg'."
|
|
rc_usage "$_keywords"
|
|
exit 1
|
|
}
|
|
|
|
#
|
|
# run_rc_script file arg
|
|
# Start the script `file' with `arg', and correctly handle the
|
|
# return value from the script. If `file' ends with `.sh', it's
|
|
# sourced into the current environment. Otherwise it's run as
|
|
# a child process.
|
|
#
|
|
# Note: because `.sh' files are sourced into the current environment
|
|
# run_rc_command shouldn't be used because its difficult to ensure
|
|
# that the global variable state before and after the sourcing of
|
|
# the .sh file won't adversely affect other scripts.
|
|
#
|
|
run_rc_script()
|
|
{
|
|
_file=$1
|
|
_arg=$2
|
|
if [ -z "$_file" -o -z "$_arg" ]; then
|
|
err 3 'USAGE: run_rc_script file arg'
|
|
fi
|
|
|
|
if [ -n "$rc_fast_and_loose" ]; then
|
|
unset name command command_args extra_commands pidfile rcvar
|
|
unset required_dirs required_files required_vars
|
|
eval unset ${_arg}_cmd ${_arg}_precmd
|
|
set $_arg ; . $_file
|
|
else
|
|
case "$_file" in
|
|
*.sh) # run in current shell
|
|
set $_arg ; . $_file
|
|
;;
|
|
*) # run in subshell
|
|
( set $_arg ; . $_file )
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
#
|
|
# load_rc_config
|
|
# Source in the configuration file for a given command.
|
|
#
|
|
load_rc_config()
|
|
{
|
|
_command=$1
|
|
if [ -z "$_command" ]; then
|
|
err 3 'USAGE: load_rc_config command'
|
|
fi
|
|
|
|
if [ -z "$_rc_conf_loaded" ]; then
|
|
. /etc/rc.conf
|
|
_rc_conf_loaded=YES
|
|
fi
|
|
if [ -f /etc/rc.conf.d/"$_command" ]; then
|
|
. /etc/rc.conf.d/"$_command"
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# rc_usage commands
|
|
# Print a usage string for $0, with `commands' being a list of
|
|
# valid commands.
|
|
#
|
|
rc_usage()
|
|
{
|
|
echo -n 1>&2 "Usage: $0 [fast|force]("
|
|
|
|
_sep=
|
|
for _elem in $*; do
|
|
echo -n 1>&2 "$_sep$_elem"
|
|
_sep="|"
|
|
done
|
|
echo 1>&2 ")"
|
|
exit 1
|
|
}
|
|
|
|
#
|
|
# err exitval message
|
|
# Display message to stderr and log to the syslog, and exit with exitval.
|
|
#
|
|
err()
|
|
{
|
|
exitval=$1
|
|
shift
|
|
|
|
logger "$0: ERROR: $*"
|
|
echo 1>&2 "$0: ERROR: $*"
|
|
exit $exitval
|
|
}
|
|
|
|
#
|
|
# warn message
|
|
# Display message to stderr and log to the syslog.
|
|
#
|
|
warn()
|
|
{
|
|
logger "$0: WARNING: $*"
|
|
echo 1>&2 "$0: WARNING: $*"
|
|
}
|