aboutsummaryrefslogtreecommitdiff
path: root/libexec/rc/rc.subr
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rc/rc.subr')
-rw-r--r--libexec/rc/rc.subr381
1 files changed, 356 insertions, 25 deletions
diff --git a/libexec/rc/rc.subr b/libexec/rc/rc.subr
index dc4f49612c29..16b2c9fc5e88 100644
--- a/libexec/rc/rc.subr
+++ b/libexec/rc/rc.subr
@@ -1,5 +1,4 @@
# $NetBSD: rc.subr,v 1.67 2006/10/07 11:25:15 elad Exp $
-# $FreeBSD$
#
# Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -52,6 +51,8 @@ ID="/usr/bin/id"
IDCMD="if [ -x $ID ]; then $ID -un; fi"
PS="/bin/ps -ww"
JID=0
+CPUSET="/bin/cpuset"
+
# rc_service provides the path to the service script that we are executing.
# This is not being set here in an execution context, necessarily, so it's
# really just a reasonable guess, and it will get overwritten later if
@@ -65,9 +66,161 @@ rc_service="$0"
# functions
# ---------
+# is_verified file
+# if VERIEXEC is active check that $file is verified
+#
+VERIEXEC="/sbin/veriexec"
+if test -x $VERIEXEC && $VERIEXEC -i active > /dev/null 2>&1; then
+ is_verified() { $VERIEXEC -x $1; }
+else
+ is_verified() { return 0; }
+fi
+
+# indicate that we have vdot
+_VDOT_SH=:
+
+# current state of O_VERIFY
+o_verify()
+{
+ case $(echo $(set -o)) in
+ *verify" "off*) echo off;;
+ *verify" "on*) echo on;;
+ esac
+}
+
+##
+# o_verify_set want [save]
+#
+# record current state of verify in $save
+# and set it to $want if different
+#
+o_verify_set() {
+ local x=$(o_verify)
+
+ [ -z "$x" ] && return 0
+ [ -z "$2" ] || eval $2=$x
+ [ "$x" = "$1" ] && return 0
+ case "$1" in
+ on)
+ set -o verify
+ ;;
+ off)
+ set +o verify
+ ;;
+ esac
+}
+
+# for unverified files
+dotted=
+dot()
+{
+ local f verify
+
+ o_verify_set off verify
+ for f in "$@"; do
+ if [ -f $f -a -s $f ]; then
+ dotted="$dotted $f"
+ . $f
+ fi
+ done
+ o_verify_set $verify
+}
+
+# try for verified, fallback to safe
+sdot()
+{
+ local f
+
+ for f in "$@"; do
+ [ -f $f -a -s $f ] || continue
+ vdot $f || safe_dot $f
+ done
+}
+
+# convenience function - skip if not verified
+vdot()
+{
+ local f rc=0 verify
+
+ o_verify_set on verify
+ for f in "$@"; do
+ [ -f $f -a -s $f ] || continue
+ if is_verified $f 2> /dev/null; then
+ dotted="$dotted $f"
+ . $f
+ else
+ rc=80 # EAUTH
+ fi
+ done
+ o_verify_set $verify
+ return $rc
+}
+
+# Exists [test] file ...
+# report the first "file" that passes "test" (default -s).
+Exists()
+{
+ local f _t=-s
+
+ while :; do
+ : 1=$1
+ case "$1" in
+ -?)
+ _t=$1
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+
+ for f in "$@"; do
+ [ $_t $f ] || continue
+ echo $f
+ return 0
+ done
+ return 1
+}
+
+# do we have $1 (could be a function)
+have()
+{
+ type "$1" > /dev/null 2>&1
+}
+
+# provide consistent means of logging progress
+rc_log()
+{
+ date "+@ %s [%Y-%m-%d %H:%M:%S %Z] $*"
+}
+
+# only rc_log if tracing enabled
+# and $level >= $RC_LEVEL
+rc_trace()
+{
+ local level=$1; shift
+ local cf=/etc/rc.conf.d/rc_trace
+
+ if [ -z "$RC_LEVEL" ]; then
+ [ -f $cf ] || return
+ if [ -s $cf ]; then
+ # don't try to set RC_LEVEL without sed
+ if [ -n "$SED" ]; then
+ RC_LEVEL=$($SED -n '/^RC_LEVEL=/ { s/.*=//p;q; }' $cf)
+ RC_LEVEL=${RC_LEVEL:-0}
+ fi
+ else
+ RC_LEVEL=0
+ fi
+ fi
+ [ ${RC_LEVEL:-0} -ge ${level:-0} ] || return
+ rc_log "$@"
+}
+
# list_vars pattern
# List variables matching glob pattern.
-#
+#
list_vars()
{
# Localize 'set' option below.
@@ -217,7 +370,7 @@ stop_boot()
case $1 in
# "yes", "true", "on", or "1"
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
always=true
;;
*)
@@ -442,7 +595,7 @@ sort_lite()
local curitem curitem_orig curitem_mod curitem_haskey
local dest dest_orig dest_mod dest_haskey
local d gt n
- local i=1
+ local i=1
while [ $i -le $nitems ]; do
curitem_haskey=1 # Assume sort field (-k POS) exists
eval curitem=\"\$src_$i\"
@@ -777,6 +930,9 @@ startmsg()
# ${name}_chdir n Directory to cd to before running ${command}
# (if not using ${name}_chroot).
#
+# ${name}_cpuset n A list of CPUs to run ${command} on.
+# Requires /usr to be mounted.
+#
# ${name}_flags n Arguments to call ${command} with.
# NOTE: $flags from the parent environment
# can be used to override this.
@@ -791,6 +947,8 @@ startmsg()
#
# ${name}_oomprotect n Don't kill ${command} when swap space is exhausted.
#
+# ${name}_umask n The file creation mask to run ${command} with.
+#
# ${name}_user n User to run ${command} as, using su(1) if not
# using ${name}_chroot.
# Requires /usr to be mounted.
@@ -804,6 +962,8 @@ startmsg()
#
# ${name}_prepend n Command added before ${command}.
#
+# ${name}_setup n Command executed before ${command}.
+#
# ${name}_login_class n Login class to use, else "daemon".
#
# ${name}_limits n limits(1) to apply to ${command}.
@@ -864,7 +1024,7 @@ startmsg()
# ($sig_stop defaults to TERM.)
#
# reload Similar to stop, except use $sig_reload instead,
-# and doesn't wait_for_pids.
+# and don't wait_for_pids.
# $sig_reload defaults to HUP.
# Note that `reload' isn't provided by default,
# it should be enabled via $extra_commands.
@@ -896,8 +1056,8 @@ startmsg()
# by $flags from the environment.
# This variable may be changed by the precmd method.
#
-# rc_service Path to the service being executed, in case the service
-# needs to re-invoke itself.
+# rc_service Path to the service being executed, in case the service
+# needs to re-invoke itself.
#
# rc_pid PID of command (if appropriate)
#
@@ -916,6 +1076,8 @@ run_rc_command()
err 3 'run_rc_command: $name is not set.'
fi
+ DebugOn rc:$name rc:$name:$rc_arg $name:$rc_arg
+
# Don't repeat the first argument when passing additional command-
# line arguments to the command subroutines.
#
@@ -959,6 +1121,23 @@ run_rc_command()
_pidcmd=
_procname=${procname:-${command}}
+ eval _cpuset=\$${name}_cpuset
+
+ # Loose validation of the configured cpuset; just make sure it starts
+ # with a number. There have also been cases in the past where a hyphen
+ # in a service name has caused eval errors, which trickle down into
+ # various variables; don't let a situation like that break a bunch of
+ # services just because of cpuset(1).
+ case "$_cpuset" in
+ [0-9]*) ;;
+ *) _cpuset="" ;;
+ esac
+
+ _cpusetcmd=
+ if [ -n "$_cpuset" ]; then
+ _cpusetcmd="$CPUSET -l $_cpuset"
+ fi
+
# setup pid check command
if [ -n "$_procname" ]; then
if [ -n "$pidfile" ]; then
@@ -993,8 +1172,9 @@ run_rc_command()
_group=\$${name}_group _groups=\$${name}_groups \
_fib=\$${name}_fib _env=\$${name}_env \
_prepend=\$${name}_prepend _login_class=\${${name}_login_class:-daemon} \
- _limits=\$${name}_limits _oomprotect=\$${name}_oomprotect \
- _env_file=\$${name}_env_file
+ _limits=\$${name}_limits _oomprotect=\$${name}_oomprotect \
+ _setup=\$${name}_setup _env_file=\$${name}_env_file \
+ _umask=\$${name}_umask
if [ -n "$_env_file" ] && [ -r "${_env_file}" ]; then # load env from file
set -a
@@ -1015,13 +1195,14 @@ run_rc_command()
continue
fi
# if ${rcvar} is set, $1 is not "rcvar", "describe",
- # "enable" or "delete", and ${rc_pid} is not set, run:
+ # "enable", "delete" or "status", and ${rc_pid} is
+ # not set, run:
# checkyesno ${rcvar}
# and return if that failed
#
if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" -a "$rc_arg" != "stop" \
-a "$rc_arg" != "delete" -a "$rc_arg" != "enable" \
- -a "$rc_arg" != "describe" ] ||
+ -a "$rc_arg" != "describe" -a "$rc_arg" != "status" ] ||
[ -n "${rcvar}" -a "$rc_arg" = "stop" -a -z "${rc_pid}" ]; then
if ! checkyesno ${rcvar}; then
if [ -n "${rc_quiet}" ]; then
@@ -1050,11 +1231,12 @@ run_rc_command()
_postcmd=\$${rc_arg}_postcmd
if [ -n "$_cmd" ]; then
+ rc_trace 1 "$_cmd"
if [ -n "$_env" ]; then
eval "export -- $_env"
fi
_run_rc_precmd || return 1
- _run_rc_doit "$_cmd $rc_extra_args" || return 1
+ _run_rc_doit "$_cpusetcmd $_cmd $rc_extra_args" || return 1
_run_rc_postcmd
return $_return
fi
@@ -1066,19 +1248,19 @@ run_rc_command()
echo "$desc"
fi
;;
-
+
extracommands)
echo "$extra_commands"
;;
enable)
_out=$(/usr/sbin/sysrc -vs "$name" "$rcvar=YES") &&
- echo "$name enabled in ${_out%%:*}"
+ echo "$name enabled in ${_out%%:*}"
;;
disable)
_out=$(/usr/sbin/sysrc -vs "$name" "$rcvar=NO") &&
- echo "$name disabled in ${_out%%:*}"
+ echo "$name disabled in ${_out%%:*}"
;;
delete)
@@ -1125,6 +1307,7 @@ run_rc_command()
_cd=
_doit="\
${_nice:+nice -n $_nice }\
+$_cpusetcmd \
${_fib:+setfib -F $_fib }\
${_env:+env $_env }\
chroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\
@@ -1134,7 +1317,7 @@ $_chroot $command $rc_flags $command_args"
_doit="\
${_fib:+setfib -F $_fib }\
${_env:+env $_env }\
-$command $rc_flags $command_args"
+$_cpusetcmd $command $rc_flags $command_args"
if [ -n "$_user" ]; then
_doit="su -m $_user -c 'sh -c \"$_doit\"'"
fi
@@ -1149,6 +1332,12 @@ $command $rc_flags $command_args"
fi
fi
+ if [ -n "$_setup" ]; then
+ if ! _run_rc_doit "$_setup"; then
+ warn "failed to setup ${name}"
+ fi
+ fi
+
# Prepend default limits
_doit="$_cd limits -C $_login_class $_limits $_doit"
@@ -1289,7 +1478,7 @@ $command $rc_flags $command_args"
[ -z "${rc_pid}" ] && eval $_pidcmd
case $_oomprotect in
[Aa][Ll][Ll])
- ${PROTECT} -i -p ${rc_pid}
+ ${PROTECT} -d -i -p ${rc_pid}
;;
[Yy][Ee][Ss])
${PROTECT} -p ${rc_pid}
@@ -1349,9 +1538,14 @@ _run_rc_postcmd()
_run_rc_doit()
{
+ local _m
+
debug "run_rc_command: doit: $*"
+ _m=$(umask)
+ ${_umask:+umask ${_umask}}
eval "$@"
_return=$?
+ umask ${_m}
# If command failed and force isn't set, request exit.
if [ $_return -ne 0 ] && [ -z "$rc_force" ]; then
@@ -1410,6 +1604,10 @@ run_rc_script()
required_vars
eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
+ rc_trace 0 "$_file $_arg"
+ # don't use it if we don't trust it
+ is_verified $_file || return
+
rc_service="$_file"
case "$_file" in
/etc/rc.d/*.sh) # no longer allowed in the base
@@ -1420,6 +1618,8 @@ run_rc_script()
;;
*) # run in subshell
if [ -x $_file ]; then
+ DebugOn $_file $_file:$_arg rc:${_file##*/} rc:${_file##*/}:$_arg ${_file##*/} ${_file##*/}:$_arg
+
if [ -n "$rc_boottrace" ]; then
boottrace_fn "$_file" "$_arg"
elif [ -n "$rc_fast_and_loose" ]; then
@@ -1430,11 +1630,65 @@ run_rc_script()
trap "echo Script $_file running >&2" 29
set $_arg; . $_file )
fi
+ DebugOff $_file $_file:$_arg rc:${_file##*/} rc:${_file##*/}:$_arg ${_file##*/} ${_file##*/}:$_arg
fi
;;
esac
}
+#
+# run_rc_scripts [options] file [...]
+#
+# Call `run_rc_script' for each "file" unless already listed in
+# $_rc_elem_done.
+#
+# Options:
+#
+# --arg "arg"
+# Pass "arg" to `run_rc_script' default is $_boot.
+#
+# --break "marker"
+# If any "file" matches "marker" stop processing.
+#
+_rc_elem_done=
+run_rc_scripts()
+{
+ local _arg=${_boot}
+ local _rc_elem
+ local _rc_breaks=
+
+ while :; do
+ case "$1" in
+ --arg)
+ _arg="$2"
+ shift 2
+ ;;
+ --break)
+ _rc_breaks="$_rc_breaks $2"
+ shift 2
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+ for _rc_elem in "$@"; do
+ : _rc_elem=$_rc_elem
+ case " $_rc_elem_done " in
+ *" $_rc_elem "*)
+ continue
+ ;;
+ esac
+ run_rc_script ${_rc_elem} ${_arg}
+ _rc_elem_done="$_rc_elem_done $_rc_elem"
+ case " $_rc_breaks " in
+ *" ${_rc_elem##*/} "*)
+ break
+ ;;
+ esac
+ done
+}
+
boottrace_fn()
{
local _file _arg
@@ -1463,19 +1717,42 @@ boottrace_sysctl()
#
load_rc_config()
{
- local _name _rcvar_val _var _defval _v _msg _new _d
+ local _name _rcvar_val _var _defval _v _msg _new _d _dot
_name=$1
+ _dot=${load_rc_config_reader:-dot}
+
+ case "$_dot" in
+ dot|[sv]dot)
+ ;;
+ *) warn "Ignoring invalid load_rc_config_reader"
+ _dot=dot
+ ;;
+ esac
+ case "$1" in
+ -s|--safe)
+ _dot=sdot
+ _name=$2
+ shift
+ ;;
+ -v|--verify)
+ _dot=vdot
+ _name=$2
+ shift
+ ;;
+ esac
+
+ DebugOn rc:$_name $_name
if ${_rc_conf_loaded:-false}; then
:
else
if [ -r /etc/defaults/rc.conf ]; then
debug "Sourcing /etc/defaults/rc.conf"
- . /etc/defaults/rc.conf
+ $_dot /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
+ $_dot /etc/rc.conf
fi
_rc_conf_loaded=true
fi
@@ -1487,13 +1764,13 @@ load_rc_config()
_d=${_d%/rc.d}
if [ -f ${_d}/rc.conf.d/"$_name" ]; then
debug "Sourcing ${_d}/rc.conf.d/$_name"
- . ${_d}/rc.conf.d/"$_name"
+ $_dot ${_d}/rc.conf.d/"$_name"
elif [ -d ${_d}/rc.conf.d/"$_name" ] ; then
local _rc
for _rc in ${_d}/rc.conf.d/"$_name"/* ; do
if [ -f "$_rc" ] ; then
debug "Sourcing $_rc"
- . "$_rc"
+ $_dot "$_rc"
fi
done
fi
@@ -1544,7 +1821,7 @@ load_rc_config_var()
fi
eval $(eval '(
load_rc_config '$1' >/dev/null;
- if [ -n "${'$2'}" -o "${'$2'-UNSET}" != "UNSET" ]; then
+ if [ -n "${'$2'}" -o "${'$2'-UNSET}" != "UNSET" ]; then
echo '$2'=\'\''${'$2'}\'\'';
fi
)' )
@@ -1931,6 +2208,9 @@ load_kld()
return 1
else
info "$1 kernel module loaded."
+ if [ -f "/etc/sysctl.kld.d/$1.conf" ]; then
+ sysctl -f "/etc/sysctl.kld.d/$1.conf"
+ fi
fi
else
debug "load_kld: $1 kernel module already loaded."
@@ -2067,7 +2347,7 @@ find_local_scripts_new() {
if [ -d "${dir}" ]; then
for file in `grep -l '^# PROVIDE:' ${dir}/* 2>/dev/null`; do
case "$file" in
- *.sample) ;;
+ *.sample|*.pkgsave) ;;
*) if [ -x "$file" ]; then
local_rc="${local_rc} ${file}"
fi
@@ -2078,6 +2358,19 @@ find_local_scripts_new() {
done
}
+find_system_scripts() {
+ system_rc=''
+ for file in /etc/rc.d/*; do
+ case "${file##*/}" in
+ *.pkgsave) ;;
+ *) if [ -x "$file" ]; then
+ system_rc="${system_rc} ${file}"
+ fi
+ ;;
+ esac
+ done
+}
+
# check_required_{before|after} command
# Check for things required by the command before and after its precmd,
# respectively. The two separate functions are needed because some
@@ -2187,7 +2480,7 @@ check_kern_features()
# check_namevarlist var
# Return "0" if ${name}_var is reserved in rc.subr.
-_rc_namevarlist="program chroot chdir env flags fib nice user group groups prepend"
+_rc_namevarlist="program chroot chdir env flags fib nice user group groups prepend setup"
check_namevarlist()
{
local _v
@@ -2231,3 +2524,41 @@ boottrace_cmd=`command -v boottrace`
if [ -n "$boottrace_cmd" ] && [ "`${SYSCTL_N} -q kern.boottrace.enabled`" = "1" ]; then
rc_boottrace=YES
fi
+
+SED=${SED:-$(Exists -x /usr/bin/sed /rescue/sed)}
+
+# Allow for local additions and overrides.
+# Use vdot to ensure the file has not been tampered with.
+vdot /etc/local.rc.subr
+
+# Avoid noise - when we do not have /usr mounted,
+# and we cannot use safe_dot without sed.
+if ! have basename; then
+ basename()
+ {
+ local b=${1%$2}
+ echo ${b##*/}
+ }
+ tty()
+ {
+ return 0
+ }
+ # we cannot use safe_dot without sed
+ [ -z "$SED" ] && _SAFE_EVAL_SH=:
+fi
+# safe_eval.sh provides safe_dot - for untrusted files
+$_SAFE_EVAL_SH vdot /libexec/safe_eval.sh
+$_DEBUG_SH vdot /libexec/debug.sh
+
+# Ensure we can still operate if debug.sh and
+# safe_eval.sh are not found.
+if have DebugOn; then
+ # allow DEBUG_SH to be set from loader prompt
+ DEBUG_SH=${DEBUG_SH:-$(kenv -q DEBUG_SH)}
+else
+ DebugOn() { return 0; }
+ DebugOff() { return 0; }
+fi
+if ! have save_dot; then
+ safe_dot() { dot "$@"; }
+fi