Page MenuHomeFreeBSD

D43671.id133633.diff
No OneTemporary

D43671.id133633.diff

diff --git a/libexec/rc/Makefile b/libexec/rc/Makefile
--- a/libexec/rc/Makefile
+++ b/libexec/rc/Makefile
@@ -18,6 +18,12 @@
CONFETCDEFAULTS= rc.conf
CONFETCDEFAULTSPACKAGE= rc
+FILESGROUPS= LIBEXEC_SCRIPTS
+LIBEXEC_SCRIPTS= debug.sh safe_eval.sh
+LIBEXEC_SCRIPTSDIR= /libexec
+LIBEXEC_SCRIPTSMODE= 755
+LIBEXEC_SCRIPTSPACKAGE= rc
+
SUBDIR+= rc.d
HAS_TESTS=
diff --git a/libexec/rc/debug.sh b/libexec/rc/debug.sh
new file mode 100755
--- /dev/null
+++ b/libexec/rc/debug.sh
@@ -0,0 +1,266 @@
+:
+# NAME:
+# debug.sh - debug scripts
+#
+# SYNOPSIS:
+# $_DEBUG_SH . debug.sh
+# DebugOn [-e][-o] "e" ...
+# DebugOff "e" ...
+# DebugShell "e" ...
+# DebugEcho ...
+# Debugging
+# DebugLog ...
+# DebugTrace ...
+# Debug "e" ...
+#
+# $DEBUG_SKIP echo skipped when Debug "e" is true.
+# $DEBUG_DO echo only done when Debug "e" is true.
+#
+# DESCRIPTION:
+# DebugOn turns tracing on if any "e" is found in "DEBUG_SH".
+# It turns tracing off if "!e" is found in "DEBUG_SH".
+# It also sets "DEBUG_ON" to the "e" that caused tracing to be
+# enabled, or "DEBUG_OFF" if we matched "!e".
+# If '-e' option given returns 1 if no "e" matched.
+# If the '-o' flag is given, tracing is turned off unless there
+# was a matched "e", useful for functions too noisy to tace.
+#
+# DebugOff turns tracing on if any "e" matches "DEBUG_OFF" or
+# off if any "e" matches "DEBUG_ON". This allows nested
+# functions to not interfere with each other.
+#
+# DebugEcho is just shorthand for:
+#.nf
+# $DEBUG_DO echo "$@"
+#.fi
+#
+# Debugging returns true if tracing is enabled.
+# It is useful for bounding complex debug actions, rather than
+# using lots of "DEBUG_DO" lines.
+#
+# DebugShell runs an interactive shell if any "e" is found in
+# "DEBUG_INTERACTIVE", and there is a tty available.
+# The shell used is defined by "DEBUG_SHELL" or "SHELL" and
+# defaults to '/bin/sh'.
+#
+# Debug calls DebugOn and if that does not turn tracing on, it
+# calls DebugOff to turn it off.
+#
+# The variables "DEBUG_SKIP" and "DEBUG_DO" are set so as to
+# enable/disable code that should be skipped/run when debugging
+# is turned on. "DEBUGGING" is the same as "DEBUG_SKIP" for
+# backwards compatability and is only set by Debug.
+#
+# The use of $_DEBUG_SH is to prevent multiple inclusion, though
+# it does no harm in this case.
+#
+# BUGS:
+# Does not work with some versions of ksh.
+# If a function turns tracing on, ksh turns it off when the
+# function returns - useless.
+# PD ksh works ok ;-)
+#
+# AUTHOR:
+# Simon J. Gerraty <sjg@crufty.net>
+
+# RCSid:
+# $Id: debug.sh,v 1.33 2021/12/03 18:22:37 sjg Exp $
+#
+# @(#) Copyright (c) 1994-2021 Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+_DEBUG_SH=:
+
+Myname=${Myname:-`basename $0 .sh`}
+
+DEBUGGING=
+DEBUG_DO=:
+DEBUG_SKIP=
+export DEBUGGING DEBUG_DO DEBUG_SKIP
+
+_debugOn() {
+ DEBUG_OFF=
+ DEBUG_DO=
+ DEBUG_SKIP=:
+ DEBUG_X=-x
+ set -x
+ DEBUG_ON=$1
+}
+
+_debugOff() {
+ DEBUG_OFF=$1
+ set +x
+ DEBUG_ON=$2
+ DEBUG_DO=:
+ DEBUG_SKIP=
+ DEBUG_X=
+}
+
+DebugEcho() {
+ $DEBUG_DO echo "$@"
+}
+
+Debugging() {
+ test "$DEBUG_SKIP"
+}
+
+DebugLog() {
+ $DEBUG_SKIP return 0
+ echo `date '+@ %s [%Y-%m-%d %H:%M:%S %Z]'` "$@"
+}
+
+# something hard to miss when wading through huge -x output
+DebugTrace() {
+ $DEBUG_SKIP return 0
+ set +x
+ echo "@ ==================== [ $DEBUG_ON ] ===================="
+ DebugLog "$@"
+ echo "@ ==================== [ $DEBUG_ON ] ===================="
+ set -x
+}
+
+# Turn on debugging if appropriate
+DebugOn() {
+ _rc=0 # avoid problems with set -e
+ _off=:
+ while :
+ do
+ case "$1" in
+ -e) _rc=1; shift;; # caller ok with return 1
+ -o) _off=; shift;; # off unless we have a match
+ *) break;;
+ esac
+ done
+ case ",${DEBUG_SH:-$DEBUG}," in
+ ,,) return $_rc;;
+ *,[Dd]ebug,*) ;;
+ *) $DEBUG_DO set +x;; # reduce the noise
+ esac
+ _match=
+ # if debugging is off because of a !e
+ # don't add 'all' to the On list.
+ case "$_off$DEBUG_OFF" in
+ :) _e=all;;
+ *) _e=;;
+ esac
+ for _e in ${*:-$Myname} $_e
+ do
+ : $_e in ,${DEBUG_SH:-$DEBUG},
+ case ",${DEBUG_SH:-$DEBUG}," in
+ *,!$_e,*|*,!$Myname:$_e,*)
+ # only turn it off if it was on
+ _rc=0
+ $DEBUG_DO _debugOff $_e $DEBUG_ON
+ break
+ ;;
+ *,$_e,*|*,$Myname:$_e,*)
+ # only turn it on if it was off
+ _rc=0
+ _match=$_e
+ $DEBUG_SKIP _debugOn $_e
+ break
+ ;;
+ esac
+ done
+ if test -z "$_off$_match"; then
+ # off unless explicit match, but
+ # only turn it off if it was on
+ $DEBUG_DO _debugOff $_e $DEBUG_ON
+ fi
+ $DEBUG_DO set -x # back on if needed
+ $DEBUG_DO set -x # make sure we see it in trace
+ return $_rc
+}
+
+# Only turn debugging off if one of our args was the reason it
+# was turned on.
+# We normally return 0, but caller can pass rc=$? as first arg
+# so that we preserve the status of last statement.
+DebugOff() {
+ case ",${DEBUG_SH:-$DEBUG}," in
+ *,[Dd]ebug,*) ;;
+ *) $DEBUG_DO set +x;; # reduce the noise
+ esac
+ _rc=0 # always happy
+ while :
+ do
+ case "$1" in
+ -[eo]) shift;; # ignore it
+ rc=*) eval "_$1"; shift;;
+ *) break;;
+ esac
+ done
+ for _e in $*
+ do
+ : $_e==$DEBUG_OFF DEBUG_OFF
+ case "$DEBUG_OFF" in
+ "") break;;
+ $_e) _debugOn $DEBUG_ON; return $_rc;;
+ esac
+ done
+ for _e in $*
+ do
+ : $_e==$DEBUG_ON DEBUG_ON
+ case "$DEBUG_ON" in
+ "") break;;
+ $_e) _debugOff; return $_rc;;
+ esac
+ done
+ $DEBUG_DO set -x # back on if needed
+ $DEBUG_DO set -x # make sure we see it in trace
+ return $_rc
+}
+
+_TTY=${_TTY:-`test -t 0 && tty`}; export _TTY
+
+# override this if you like
+_debugShell() {
+ {
+ echo DebugShell "$@"
+ echo "Type 'exit' to continue..."
+ } > $_TTY
+ ${DEBUG_SHELL:-${SHELL:-/bin/sh}} < $_TTY > $_TTY 2>&1
+}
+
+# Run an interactive shell if appropriate
+# Note: you can use $DEBUG_SKIP DebugShell ... to skip unless debugOn
+DebugShell() {
+ case "$_TTY%${DEBUG_INTERACTIVE}" in
+ *%|%*) return 0;; # no tty or no spec
+ esac
+ for _e in ${*:-$Myname} all
+ do
+ case ",${DEBUG_INTERACTIVE}," in
+ *,!$_e,*|*,!$Myname:$_e,*)
+ return 0
+ ;;
+ *,$_e,*|*,$Myname:$_e,*)
+ # Provide clues as to why/where
+ _debugShell "$_e: $@"
+ return $?
+ ;;
+ esac
+ done
+ return 0
+}
+
+# For backwards compatability
+Debug() {
+ case "${DEBUG_SH:-$DEBUG}" in
+ "") ;;
+ *) DEBUG_ON=${DEBUG_ON:-_Debug}
+ DebugOn -e $* || DebugOff $DEBUG_LAST
+ DEBUGGING=$DEBUG_SKIP
+ ;;
+ esac
+}
diff --git a/libexec/rc/rc b/libexec/rc/rc
--- a/libexec/rc/rc
+++ b/libexec/rc/rc
@@ -66,8 +66,11 @@
# to minimize the number of files that are needed on a diskless system,
# and to make the configuration file variables available to rc itself.
#
+# -o verify has no effect if mac_veriexec is not active
+set -o verify
. /etc/rc.subr
-load_rc_config
+set +o verify
+load_rc_config $rc_config_xtra
# If we receive a SIGALRM, re-source /etc/rc.conf; this allows rc.d
# scripts to perform "boot-time configuration" including enabling and
@@ -93,16 +96,7 @@
unset system_rc
find_system_scripts
files=`rcorder ${skip} ${skip_firstboot} ${system_rc} 2>/dev/null`
-
-_rc_elem_done=' '
-for _rc_elem in ${files}; do
- run_rc_script ${_rc_elem} ${_boot}
- _rc_elem_done="${_rc_elem_done}${_rc_elem} "
-
- case "$_rc_elem" in
- */${early_late_divider}) break ;;
- esac
-done
+run_rc_scripts --break ${early_late_divider} ${rc_early_flags} $files
unset files local_rc system_rc
@@ -122,13 +116,13 @@
find_system_scripts
files=`rcorder ${skip} ${skip_firstboot} ${system_rc} ${local_rc} 2>/dev/null`
-for _rc_elem in ${files}; do
- case "$_rc_elem_done" in
- *" $_rc_elem "*) continue ;;
- esac
+run_rc_scripts ${rc_late_flags} $files
+unset files local_rc system_rc
- run_rc_script ${_rc_elem} ${_boot}
-done
+# allow for more complicated setups
+if have run_rc_scripts_final; then
+ run_rc_scripts_final
+fi
# Remove the firstboot sentinel, and reboot if it was requested.
# Be a bit paranoid about removing it to handle the common failure
diff --git a/libexec/rc/rc.subr b/libexec/rc/rc.subr
--- a/libexec/rc/rc.subr
+++ b/libexec/rc/rc.subr
@@ -66,6 +66,121 @@
# functions
# ---------
+# _rc_verify 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()
+{
+ set -o | sed -n '/^verify/s,.*[[:space:]],,p'
+}
+
+##
+# 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`
+
+ test -z "$x" && return 0
+ test -z "$2" || eval $2=$x
+ test "$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 test -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
+ test -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
+ test -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
+}
+
+# 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 test -z "$RC_LEVEL"; then
+ test -f $cf || return
+ test -s $cf &&
+ RC_LEVEL=`sed -n '/^RC_LEVEL=/ { s,.*=,,p;q; }' $cf`
+ RC_LEVEL=${RC_LEVEL:-0}
+ fi
+ test ${RC_LEVEL:-0} -ge ${level:-0} || return
+ rc_log "$@"
+}
+
# list_vars pattern
# List variables matching glob pattern.
#
@@ -924,6 +1039,8 @@
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.
#
@@ -1077,6 +1194,7 @@
_postcmd=\$${rc_arg}_postcmd
if [ -n "$_cmd" ]; then
+ rc_trace 1 "$_cmd"
if [ -n "$_env" ]; then
eval "export -- $_env"
fi
@@ -1449,6 +1567,14 @@
required_vars
eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd
+ rc_trace 0 "$_file $_arg"
+ case "$_file" in
+ *local*.d/*) ;; # allow it ?
+ *) # don't use it if we don't trust it
+ is_verified $_file || return
+ ;;
+ esac
+
rc_service="$_file"
case "$_file" in
/etc/rc.d/*.sh) # no longer allowed in the base
@@ -1459,6 +1585,8 @@
;;
*) # 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
@@ -1469,11 +1597,55 @@
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
@@ -1502,19 +1674,27 @@
#
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=dot
+
+ case "$1" in
+ -s) _dot=sdot _name=$2; shift;;
+ -v) _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
@@ -1526,13 +1706,13 @@
_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
@@ -2286,3 +2466,21 @@
if [ -n "$boottrace_cmd" ] && [ "`${SYSCTL_N} -q kern.boottrace.enabled`" = "1" ]; then
rc_boottrace=YES
fi
+
+# allow for local additions and overrides for rc.subr
+vdot /etc/rc.subr.local
+
+# safe_dot - for unverified files
+$_SAFE_EVAL_SH vdot /libexec/safe_eval.sh
+$_DEBUG_SH vdot /libexec/debug.sh
+
+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
diff --git a/libexec/rc/safe_eval.sh b/libexec/rc/safe_eval.sh
new file mode 100644
--- /dev/null
+++ b/libexec/rc/safe_eval.sh
@@ -0,0 +1,64 @@
+# RCSid:
+# $Id: safe_eval.sh,v 1.12 2023/10/12 18:46:53 sjg Exp $
+#
+# @(#) Copyright (c) 2023 Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+
+_SAFE_EVAL_SH=:
+
+##
+# safe_set
+#
+# return a safe variable setting
+# any non-alphanumeric chars are replaced with '_'
+#
+safe_set() {
+ sed 's/[ ]*#.*//;/^[A-Za-z_][A-Za-z0-9_]*=/!d;s;[^A-Za-z0-9_. "$,/=-];_;g'
+}
+
+##
+# safe_eval [file]
+#
+# eval variable assignments only from file
+# taking care to eliminate any shell meta chars
+#
+safe_eval() {
+ eval `cat "$@" | safe_set`
+}
+
+##
+# safe_dot file [...]
+#
+# feed all "file" that exist to safe_eval
+#
+safe_dot() {
+ local ef= f
+
+ for f in "$@"
+ do
+ test -s $f || continue
+ ef="${ef:+$ef }$f"
+ dotted="$dotted $f"
+ done
+ test -z "$ef" && return 1
+ safe_eval $ef
+ return 0
+}
+
+case /$0 in
+*/safe_eval*)
+ case "$1" in
+ dot|eval|set) op=safe_$1; shift; $op "$@";;
+ *) safe_dot "$@";;
+ esac
+ ;;
+esac

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 29, 6:14 PM (2 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32372374
Default Alt Text
D43671.id133633.diff (15 KB)

Event Timeline