diff options
Diffstat (limited to 'libexec/rc/rc.subr')
-rw-r--r-- | libexec/rc/rc.subr | 381 |
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 |