freebsd-dev/etc/rc.subr
Brooks Davis 3e091039ee Overhaul the /etc/rc.d/diskless script by splitting it out into
hostname, resolve, tmp, and var scripts.  The latter three are new and
were repo copied.  These scripts no longer depend on being booted with
and NFS root instead attempt to automaticly create mfs /tmp and /var
volumes if the they are not writable.  This behavior can be overridden
in /etc/rc.conf.

Reviewed by:    luigi, pjd
2004-03-23 23:22:35 +00:00

1289 lines
30 KiB
Plaintext

# $NetBSD: rc.subr,v 1.60 2003/07/26 05:13:47 lukem Exp $
# $FreeBSD$
#
# Copyright (c) 1997-2002 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
#
#
# Operating System dependent/independent variables
#
SYSCTL="/sbin/sysctl"
SYSCTL_N="${SYSCTL} -n"
CMD_OSTYPE="${SYSCTL_N} kern.ostype"
OSTYPE=`${CMD_OSTYPE}`
ID="/usr/bin/id"
IDCMD="if [ -x $ID ]; then $ID -un; fi"
case ${OSTYPE} in
FreeBSD)
SYSCTL_W="${SYSCTL}"
;;
NetBSD)
SYSCTL_W="${SYSCTL} -w"
;;
esac
#
# functions
# ---------
#
# set_rcvar base_var
# Set the variable name enabling a specific service.
# FreeBSD uses ${service}_enable, while NetBSD uses
# just the name of the service. For example:
# FreeBSD: sendmail_enable="YES"
# NetBSD : sendmail="YES"
# $1 - if $name is not the base to work of off, specify
# a different one
#
set_rcvar()
{
if [ -z "$1" ]; then
base_var=${name}
else
base_var="$1"
fi
case ${OSTYPE} in
FreeBSD)
echo ${base_var}_enable
;;
NetBSD)
echo ${base_var}
;;
*)
echo 'XXX'
;;
esac
}
#
# force_depend script
# Force a service to start. Intended for use by services
# to resolve dependency issues. It is assumed the caller
# has check to make sure this call is necessary
# $1 - filename of script, in /etc/rc.d, to run
#
force_depend()
{
_depend="$1"
info "${name} depends on ${_depend}, which will be forced to start."
if ! /etc/rc.d/${_depend} forcestart ; then
warn "Unable to force ${_depend}. It may already be running."
return 1
fi
return 0
}
#
# 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}
debug "checkyesno: $1 is set to $_value."
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 - see rc.conf(5)."
return 1
;;
esac
}
# reverse_list list
# print the list in reverse order
#
reverse_list()
{
_revlist=
for _revfile; do
_revlist="$_revfile $_revlist"
done
echo $_revlist
}
#
# mount_critical_filesystems type
# Go through the list of critical filesystems as provided in
# the rc.conf(5) variable $critical_filesystems_${type}, checking
# each one to see if it is mounted, and if it is not, mounting it.
#
mount_critical_filesystems()
{
eval _fslist=\$critical_filesystems_${1}
for _fs in $_fslist; do
mount | (
_ismounted=false
while read what _on on _type type; do
if [ $on = $_fs ]; then
_ismounted=true
fi
done
if $_ismounted; then
:
else
mount $_fs >/dev/null 2>&1
fi
)
done
}
#
# check_pidfile pidfile procname [interpreter]
# 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.
# interpreter is optional; see _find_processes() for details.
#
check_pidfile()
{
_pidfile=$1
_procname=$2
_interpreter=$3
if [ -z "$_pidfile" -o -z "$_procname" ]; then
err 3 'USAGE: check_pidfile pidfile procname [interpreter]'
fi
if [ ! -f $_pidfile ]; then
debug "pid file {$_pidfile): not readable."
return
fi
read _pid _junk < $_pidfile
if [ -z "$_pid" ]; then
debug "pid file {$_pidfile): no pid in file."
return
fi
_find_processes $_procname ${_interpreter:-.} '-p '"$_pid"
}
#
# check_process procname [interpreter]
# Ensures that a process (or processes) named procname is running.
# Prints a list of matching PIDs.
# interpreter is optional; see _find_processes() for details.
#
check_process()
{
_procname=$1
_interpreter=$2
if [ -z "$_procname" ]; then
err 3 'USAGE: check_process procname [interpreter]'
fi
_find_processes $_procname ${_interpreter:-.} '-ax'
}
#
# _find_processes procname interpreter psargs
# Search for procname in the output of ps generated by psargs.
# Prints the PIDs of any matching processes, space separated.
#
# If interpreter == ".", check the following variations of procname
# against the first word of each command:
# procname
# `basename procname`
# `basename procname` + ":"
# "(" + `basename procname` + ")"
#
# If interpreter != ".", read the first line of procname, remove the
# leading #!, normalise whitespace, append procname, and attempt to
# match that against each command, either as is, or with extra words
# at the end.
#
_find_processes()
{
if [ $# -ne 3 ]; then
err 3 'USAGE: _find_processes procname interpreter psargs'
fi
_procname=$1
_interpreter=$2
_psargs=$3
_pref=
if [ $_interpreter != "." ]; then # an interpreted script
read _interp < $_procname # read interpreter name
_interp=${_interp#\#!} # strip #!
set -- $_interp
if [ $_interpreter != $1 ]; then
warn "\$command_interpreter $_interpreter != $1"
fi
_interp="$* $_procname" # cleanup spaces, add _procname
_fp_args='_argv'
_fp_match='case "$_argv" in
${_interp}|"${_interp} "*)'
else # a normal daemon
_procnamebn=${_procname##*/}
_fp_args='_arg0 _argv'
_fp_match='case "$_arg0" in
$_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
fi
_proccheck='
ps 2>/dev/null -o "pid,command" '"$_psargs"' |
while read _npid '"$_fp_args"'; do
case "$_npid" in
PID)
continue ;;
esac ; '"$_fp_match"'
echo -n "$_pref$_npid" ;
_pref=" "
;;
esac
done'
# debug "in _find_processes: proccheck is ($_proccheck)."
eval $_proccheck
}
#
# wait_for_pids pid [pid ...]
# spins until none of the pids exist
#
wait_for_pids()
{
_list="$@"
if [ -z "$_list" ]; then
return
fi
_prefix=
while true; do
_nlist="";
for _j in $_list; do
if kill -0 $_j 2>/dev/null; then
_nlist="${_nlist}${_nlist:+ }$_j"
fi
done
if [ -z "$_nlist" ]; then
break
fi
_list=$_nlist
echo -n ${_prefix:-"Waiting for PIDS: "}$_list
_prefix=", "
sleep 2
done
if [ -n "$_prefix" ]; then
echo "."
fi
}
#
# run_rc_command argument
# Search for argument in the list of supported commands, which is:
# "start stop restart rcvar status poll ${extra_commands}"
# If there's a match, run ${argument}_cmd or the default method
# (see below).
#
# If argument has a given prefix, then change the operation as follows:
# Prefix Operation
# ------ ---------
# fast Skip the pid check, and set rc_fast=yes
# force Set ${rcvar} to YES, and set rc_force=yes
# one Set ${rcvar} to YES
#
# The following globals are used:
#
# Name Needed Purpose
# ---- ------ -------
# name y Name of script.
#
# command n Full path to command.
# Not needed if ${rc_arg}_cmd is set for
# each keyword.
#
# command_args n Optional args/shell directives for command.
#
# command_interpreter n If not empty, command is interpreted, so
# call check_{pidfile,process}() appropriately.
#
# extra_commands n List of extra commands supported.
#
# pidfile n If set, use check_pidfile $pidfile $command,
# otherwise use check_process $command.
# In either case, only check if $command is set.
#
# procname n Process name to check for instead of $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}
# Requires /usr to be mounted.
#
# ${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.
# Requires /usr to be mounted.
#
# ${name}_group n Group to run chrooted ${command} as.
# Requires /usr to be mounted.
#
# ${name}_groups n Comma separated list of supplementary groups
# to run the chrooted ${command} with.
# Requires /usr to be mounted.
#
# ${rc_arg}_cmd n If set, use this as the method when invoked;
# Otherwise, use default command (see below)
#
# ${rc_arg}_precmd n If set, run just before performing the
# ${rc_arg}_cmd method in the default
# operation (i.e, after checking for required
# bits and process (non)existence).
# If this completes with a non-zero exit code,
# don't run ${rc_arg}_cmd.
#
# ${rc_arg}_postcmd n If set, run just after performing the
# ${rc_arg}_cmd method, if that method
# returned a zero exit code.
#
# 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 behaviour for a given argument, if no override method is
# provided:
#
# Argument Default behaviour
# -------- -----------------
# start if !running && checkyesno ${rcvar}
# ${command}
#
# stop if ${pidfile}
# rc_pid=$(check_pidfile $pidfile $command)
# else
# rc_pid=$(check_process $command)
# kill $sig_stop $rc_pid
# wait_for_pids $rc_pid
# ($sig_stop defaults to TERM.)
#
# reload Similar to stop, except use $sig_reload instead,
# and doesn't wait_for_pids.
# $sig_reload defaults to HUP.
#
# restart Run `stop' then `start'.
#
# status Show if ${command} is running, etc.
#
# poll Wait for ${command} to exit.
#
# rcvar Display what rc.conf variable is used (if any).
#
# Variables available to methods, and after run_rc_command() has
# completed:
#
# Variable Purpose
# -------- -------
# rc_arg Argument to command, after fast/force/one processing
# performed
#
# rc_flags Flags to start the default command with.
# Defaults to ${name}_flags, unless overridden
# by $flags from the environment.
# This variable may be changed by the precmd method.
#
# rc_pid PID of command (if appropriate)
#
# rc_fast Not empty if "fast" was provided (q.v.)
#
# rc_force Not empty if "force" was provided (q.v.)
#
#
run_rc_command()
{
_return=0
rc_arg=$1
if [ -z "$name" ]; then
err 3 'run_rc_command: $name is not set.'
fi
_rc_prefix=
case "$rc_arg" in
fast*) # "fast" prefix; don't check pid
rc_arg=${rc_arg#fast}
rc_fast=yes
;;
force*) # "force prefix; always run
rc_force=yes
_rc_prefix=force
rc_arg=${rc_arg#${_rc_prefix}}
if [ -n "${rcvar}" ]; then
eval ${rcvar}=YES
fi
;;
one*) # "one" prefix; set ${rcvar}=yes
_rc_prefix=one
rc_arg=${rc_arg#${_rc_prefix}}
if [ -n "${rcvar}" ]; then
eval ${rcvar}=YES
fi
;;
esac
eval _overide_command=\$${name}_program
if [ -n "$_overide_command" ]; then
command=$_overide_command
fi
_keywords="start stop restart rcvar $extra_commands"
rc_pid=
_pidcmd=
_procname=${procname:-${command}}
# setup pid check command if not fast
if [ -z "$rc_fast" -a -n "$_procname" ]; then
if [ -n "$pidfile" ]; then
_pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')'
else
_pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')'
fi
if [ -n "$_pidcmd" ]; then
_keywords="${_keywords} status poll"
fi
fi
if [ -z "$rc_arg" ]; then
rc_usage "$_keywords"
fi
if [ -n "$flags" ]; then # allow override from environment
rc_flags=$flags
else
eval rc_flags=\$${name}_flags
fi
eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \
_nice=\$${name}_nice _user=\$${name}_user \
_group=\$${name}_group _groups=\$${name}_groups
if [ -n "$_user" ]; then # unset $_user if running as that user
if [ "$_user" = "$(eval $IDCMD)" ]; then
unset _user
fi
fi
# if ${rcvar} is set, and $1 is not
# "rcvar", then run
# checkyesno ${rcvar}
# and return if that failed
#
if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
if ! checkyesno ${rcvar}; then
return 0
fi
fi
eval $_pidcmd # determine the pid if necessary
for _elem in $_keywords; do
if [ "$_elem" != "$rc_arg" ]; then
continue
fi
# if there's a custom ${XXX_cmd},
# run that instead of the default
#
eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \
_postcmd=\$${rc_arg}_postcmd
if [ -n "$_cmd" ]; then
# if the precmd failed and force
# isn't set, exit
#
if [ -n "$_precmd" ]; then
debug "run_rc_command: evaluating ${_precmd}()."
eval $_precmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
return 1
fi
if [ -n "$_cmd" ]; then
debug "run_rc_command: evaluating ${_cmd}()."
eval $_cmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
return 1
fi
if [ -n "$_postcmd" ]; then
debug "run_rc_command: evaluating ${_postcmd}()."
eval $_postcmd
_return=$?
fi
return $_return
fi
case "$rc_arg" in # default operations...
status)
if [ -n "$rc_pid" ]; then
echo "${name} is running as pid $rc_pid."
else
echo "${name} is not running."
return 1
fi
;;
start)
if [ -n "$rc_pid" ]; then
echo "${name} already running? (pid=$rc_pid)."
exit 1
fi
if [ ! -x ${_chroot}${command} ]; then
info "run_rc_command: cannot run ($command)."
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" ]; 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" ]; 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" ]; then
return 1
fi
fi
done
# if the precmd failed and force
# isn't set, exit
#
if [ -n "${_precmd}" ]; then
debug "run_rc_command: evaluating ${_precmd}()."
eval $_precmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
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 $rc_flags $command_args"
else
_doit="\
${_chdir:+cd $_chdir; }\
${_nice:+nice -n $_nice }\
$command $rc_flags $command_args"
if [ -n "$_user" ]; then
_doit="su -m $_user -c 'sh -c \"$_doit\"'"
fi
fi
# if the cmd failed and force
# isn't set, exit
#
debug "run_rc_command: _doit: $_doit"
eval $_doit
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1
# finally, run postcmd
#
if [ -n "${_postcmd}" ]; then
debug "run_rc_command: evaluating ${_postcmd}()."
eval $_postcmd
fi
;;
stop)
if [ -z "$rc_pid" ]; then
if [ -n "$pidfile" ]; then
echo \
"${name} not running? (check $pidfile)."
else
echo "${name} not running?"
fi
exit 1
fi
# if the precmd failed and force
# isn't set, exit
#
if [ -n "$_precmd" ]; then
eval $_precmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
return 1
fi
# send the signal to stop
#
echo "Stopping ${name}."
_doit="kill -${sig_stop:-TERM} $rc_pid"
if [ -n "$_user" ]; then
_doit="su -m $_user -c 'sh -c \"$_doit\"'"
fi
# if the stop cmd failed and force
# isn't set, exit
#
eval $_doit
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1
# wait for the command to exit,
# and run postcmd.
wait_for_pids $rc_pid
if [ -n "$_postcmd" ]; then
eval $_postcmd
_return=$?
fi
;;
reload)
if [ -z "$rc_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 [ -n "$_precmd" ]; then
eval $_precmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
return 1
fi
_doit="kill -${sig_reload:-HUP} $rc_pid"
if [ -n "$_user" ]; then
_doit="su -m $_user -c 'sh -c \"$_doit\"'"
fi
eval $_doit
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] && return 1
if [ -n "$_postcmd" ]; then
eval $_postcmd
_return=$?
fi
;;
restart)
if [ -n "$_precmd" ]; then
eval $_precmd
_return=$?
[ $_return -ne 0 ] && [ -z "$rc_force" ] &&
return 1
fi
# prevent restart being called more
# than once by any given script
#
if ${_rc_restart_done:-false}; then
return 0
fi
_rc_restart_done=true
( $0 ${_rc_prefix}stop )
$0 ${_rc_prefix}start
if [ -n "$_postcmd" ]; then
eval $_postcmd
_return=$?
fi
;;
poll)
if [ -n "$rc_pid" ]; then
wait_for_pids $rc_pid
fi
;;
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 $_return
done
echo 1>&2 "$0: unknown directive '$rc_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. If `file' appears to be
# a backup or scratch file, ignore it. Otherwise if it's
# executable run as a child process.
#
run_rc_script()
{
_file=$1
_arg=$2
if [ -z "$_file" -o -z "$_arg" ]; then
err 3 'USAGE: run_rc_script file arg'
fi
trap "echo 'Reboot interrupted'; exit 1" 3
unset name command command_args command_interpreter \
extra_commands pidfile procname \
rcvar required_dirs required_files required_vars
eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
case "$_file" in
*.sh) # run in current shell
set $_arg ; . $_file
;;
*[~#]|*.OLD|*.orig|*,v) # scratch file; skip
warn "Ignoring scratch file $_file"
;;
*) # run in subshell
if [ -x $_file ]; then
if [ -n "$rc_fast_and_loose" ]; then
set $_arg ; . $_file
else
( trap "echo 'Reboot interrupted'; exit 1" 3
set $_arg ; . $_file )
fi
fi
;;
esac
}
#
# 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 ${_rc_conf_loaded:-false}; then
:
else
if [ -r /etc/defaults/rc.conf ]; then
debug "Sourcing /etc/defaults/rc.conf"
. /etc/defaults/rc.conf
source_rc_confs
elif [ -r /etc/rc.conf ]; then
debug "Sourcing /etc/rc.conf (/etc/defaults/rc.conf doesn't exist)."
. /etc/rc.conf
fi
_rc_conf_loaded=true
fi
if [ -f /etc/rc.conf.d/"$_command" ]; then
debug "Sourcing /etc/rc.conf.d/${_command}"
. /etc/rc.conf.d/"$_command"
fi
# XXX - Deprecated variable name support
#
case ${OSTYPE} in
FreeBSD)
[ -n "$portmap_enable" ] && rpcbind_enable="$portmap_enable"
[ -n "$portmap_program" ] && rpcbind_program="$portmap_program"
[ -n "$portmap_flags" ] && rpcbind_flags="$portmap_flags"
[ -n "$single_mountd_enable" ] && mountd_enable="$single_mountd_enable"
[ -n "$xntpd_enable" ] && ntpd_enable="$xntpd_enable"
[ -n "$xntpd_program" ] && ntpd_program="$xntpd_program"
[ -n "$xntpd_flags" ] && ntpd_flags="$xntpd_flags"
[ -n "$dhcp_program" ] && dhclient_program="$dhcp_program"
[ -n "$dhcp_flags" ] && dhclient_flags="$dhcp_flags"
;;
esac
}
#
# 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|one]("
_sep=
for _elem; 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
if [ -x /usr/bin/logger ]; then
logger "$0: ERROR: $*"
fi
echo 1>&2 "$0: ERROR: $*"
exit $exitval
}
#
# warn message
# Display message to stderr and log to the syslog.
#
warn()
{
if [ -x /usr/bin/logger ]; then
logger "$0: WARNING: $*"
fi
echo 1>&2 "$0: WARNING: $*"
}
#
# info message
# Display informational message to stdout and log to syslog.
#
info()
{
case ${rc_info} in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
if [ -x /usr/bin/logger ]; then
logger "$0: INFO: $*"
fi
echo "$0: INFO: $*"
;;
esac
}
#
# debug message
# If debugging is enabled in rc.conf output message to stderr.
# BEWARE that you don't call any subroutine that itself calls this
# function.
#
debug()
{
case ${rc_debug} in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
if [ -x /usr/bin/logger ]; then
logger "$0: INFO: $*"
fi
echo 1>&2 "$0: DEBUG: $*"
;;
esac
}
#
# backup_file action file cur backup
# Make a backup copy of `file' into `cur', and save the previous
# version of `cur' as `backup' or use rcs for archiving.
#
# This routine checks the value of the backup_uses_rcs variable,
# which can be either YES or NO.
#
# The `action' keyword can be one of the following:
#
# add `file' is now being backed up (and is possibly
# being reentered into the backups system). `cur'
# is created and RCS files, if necessary, are
# created as well.
#
# update `file' has changed and needs to be backed up.
# If `cur' exists, it is copied to to `back' or
# checked into RCS (if the repository file is old),
# and then `file' is copied to `cur'. Another RCS
# check in done here if RCS is being used.
#
# remove `file' is no longer being tracked by the backups
# system. If RCS is not being used, `cur' is moved
# to `back', otherwise an empty file is checked in,
# and then `cur' is removed.
#
#
backup_file()
{
_action=$1
_file=$2
_cur=$3
_back=$4
if checkyesno backup_uses_rcs; then
_msg0="backup archive"
_msg1="update"
# ensure that history file is not locked
if [ -f $_cur,v ]; then
rcs -q -u -U -M $_cur
fi
# ensure after switching to rcs that the
# current backup is not lost
if [ -f $_cur ]; then
# no archive, or current newer than archive
if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
rcs -q -kb -U $_cur
co -q -f -u $_cur
fi
fi
case $_action in
add|update)
cp -p $_file $_cur
ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
rcs -q -kb -U $_cur
co -q -f -u $_cur
chown root:wheel $_cur $_cur,v
;;
remove)
cp /dev/null $_cur
ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
rcs -q -kb -U $_cur
chown root:wheel $_cur $_cur,v
rm $_cur
;;
esac
else
case $_action in
add|update)
if [ -f $_cur ]; then
cp -p $_cur $_back
fi
cp -p $_file $_cur
chown root:wheel $_cur
;;
remove)
mv -f $_cur $_back
;;
esac
fi
}
# make_symlink src link
# Make a symbolic link 'link' to src from basedir. If the
# directory in which link is to be created does not exist
# a warning will be displayed and an error will be returned.
# Returns 0 on sucess, 1 otherwise.
#
make_symlink()
{
local src link linkdir _me
src="$1"
link="$2"
linkdir="`dirname $link`"
_me="make_symlink()"
if [ -z "$src" -o -z "$link" ]; then
warn "$_me: requires two arguments."
return 1
fi
if [ ! -d "$linkdir" ]; then
warn "$_me: the directory $linkdir does not exist"
return 1
fi
if ! ln -sf $src $link ; then
warn "$_me: unable to make a symbolic link from $link to $src"
return 1
fi
return 0
}
# devfs_rulesets_from_file file
# Reads a set of devfs commands from file, and creates
# the specified rulesets with their rules. Returns non-zero
# if there was an error.
#
devfs_rulesets_from_file()
{
local file _err _me
file="$1"
_me="devfs_rulesets_from_file"
_err=0
if [ -z "$file" ]; then
warn "$_me: you must specify a file"
return 1
fi
if [ ! -e "$file" ]; then
debug "$_me: no such file ($file)"
return 0
fi
debug "reading rulesets from file ($file)"
{ while read line
do
case $line in
\#*)
continue
;;
\[*\]*)
rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"`
if [ -z "$rulenum" ]; then
warn "$_me: cannot extract rule number ($line)"
_err=1
break
fi
rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"`
if [ -z "$rulename" ]; then
warn "$_me: cannot extract rule name ($line)"
_err=1
break;
fi
eval $rulename=\$rulenum
debug "found ruleset: $rulename=$rulenum"
if ! /sbin/devfs rule -s $rulenum delset ; then
_err=1
break
fi
;;
*)
rulecmd="${line%%"\#*"}"
# evaluate the command incase it includes
# other rules
if [ -n "$rulecmd" ]; then
debug "adding rule ($rulecmd)"
if ! eval /sbin/devfs rule -s $rulenum $rulecmd
then
_err=1
break
fi
fi
;;
esac
if [ $_err -ne 0 ]; then
debug "error in $_me"
break
fi
done } < $file
return $_err
}
# devfs_init_rulesets
# Initializes rulesets from configuration files. Returns
# non-zero if there was an error.
#
devfs_init_rulesets()
{
local file _me
_me="devfs_init_rulesets"
# Go through this only once
if [ -n "$devfs_rulesets_init" ]; then
debug "$_me: devfs rulesets already initialized"
return
fi
for file in $devfs_rulesets ; do
devfs_rulesets_from_file $file || return 1
done
devfs_rulesets_init=1
debug "$_me: devfs rulesets initialized"
return 0
}
# devfs_set_ruleset ruleset [dir]
# Sets the default ruleset of dir to ruleset. The ruleset arguement
# must be a ruleset name as specified in devfs.rules(5) file.
# Returns non-zero if it could not set it successfully.
#
devfs_set_ruleset()
{
local devdir rs _me
[ -n "$1" ] && eval rs=\$$1 || rs=
[ -n "$2" ] && devdir="-m "$2"" || devdir=
_me="devfs_set_ruleset"
if [ -z "$rs" ]; then
warn "$_me: you must specify a ruleset number"
return 1
fi
debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })"
if ! /sbin/devfs $devdir ruleset $rs ; then
warn "$_me: unable to set ruleset $rs to ${devdir#-m }"
return 1
fi
return 0
}
# devfs_apply_ruleset ruleset [dir]
# Apply ruleset number $ruleset to the devfs mountpoint $dir.
# The ruleset argument must be a ruleset name as specified
# in a devfs.rules(5) file. Returns 0 on success or non-zero
# if it could not apply the ruleset.
#
devfs_apply_ruleset()
{
local devdir rs _me
[ -n "$1" ] && eval rs=\$$1 || rs=
[ -n "$2" ] && devdir="-m "$2"" || devdir=
_me="devfs_apply_ruleset"
if [ -z "$rs" ]; then
warn "$_me: you must specify a ruleset"
return 1
fi
debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })"
if ! /sbin/devfs $devdir rule -s $rs applyset ; then
warn "$_me: unable to apply ruleset $rs to ${devdir#-m }"
return 1
fi
return 0
}
# devfs_domount dir [ruleset]
# Mount devfs on dir. If ruleset is specified it is set
# on the mount-point. It must also be a ruleset name as specified
# in a devfs.rules(5) file. Returns 0 on success.
#
devfs_domount()
{
local devdir rs _me
devdir="$1"
[ -n "$2" ] && rs=$2 || rs=
_me="devfs_domount()"
if [ -z "$devdir" ]; then
warn "$_me: you must specify a mount-point"
return 1
fi
debug "$_me: mount-point is ($devdir), ruleset is ($rs)"
if ! mount -t devfs dev "$devdir" ; then
warn "$_me: Unable to mount devfs on $devdir"
return 1
fi
if [ -n "$rs" ]; then
devfs_init_rulesets
devfs_set_ruleset $rs $devdir
devfs -m $devdir rule applyset
fi
return 0
}
# devfs_mount_jail dir [ruleset]
# Mounts a devfs file system appropriate for jails
# on the directory dir. If ruleset is specified, the ruleset
# it names will be used instead. If present, ruleset must
# be the name of a ruleset as defined in a devfs.rules(5) file.
# This function returns non-zero if an error occurs.
#
devfs_mount_jail()
{
local jdev rs _me
jdev="$1"
[ -n "$2" ] && rs=$2 || rs="devfsrules_jail"
_me="devfs_mount_jail"
devfs_init_rulesets
if ! devfs_domount "$jdev" $rs ; then
warn "$_me: devfs was not mounted on $jdev"
return 1
fi
return 0
}
# Provide a function for normalizing the mounting of memory
# filesystems. This should allow the rest of the code here to remain
# as close as possible between 5-current and 4-stable.
# $1 = size
# $2 = mount point
# $3 = (optional) bytes-per-inode
mount_md() {
if [ -n "$3" ]; then
bpi="-i $3"
fi
/sbin/mdmfs $bpi -s $1 -M md $2
}