Port-sparc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: 8.2 fails suddenly to boot - /etc/rc issues



Hello Robert,

sorry for the delay...
Before replacing rc.subr with the one from etc

>   | no, I did not change rc.subr
> 
> Good.   Most people don't - it is one of the trickier parts of
> the system.
> 

I try not to touch things without knowing... if not desperate :)

>   | Perhaps some files corrupted in my filesystem?
> 
> That's certainly a possibility - and could be caused by lots of
> thing, anything from a bug, to failing disk, RAM problems, or even
> power fluctuations.

given the diff, appears strange.


> 
>   | extract ./etc/rc.subr
>   | and comare it to my local one. It looks full of differences!
> 
> Differences as in some parts the same, but with changes, but still
> looking like sh code, or differences more like "these two things are
> nothing alike at all"?

To me it looks very different, but with the same file but in different time!
Especially the beninning is telling:

-# $NetBSD: rc.subr,v 1.18 2021/08/30 21:45:02 khorben Exp $
+# $NetBSD: rc.subr,v 1.100.4.1 2018/04/04 16:07:33 martin Exp $
 #
-# Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
+# Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
 # All rights reserved.


Do you recognize something?

Riccardo
--- /etc/rc.subr.bak	2023-03-09 21:21:56.000000000 +0100
+++ /etc/rc.subr	2020-03-31 07:08:40.000000000 +0200
@@ -1,6 +1,6 @@
-# $NetBSD: rc.subr,v 1.18 2021/08/30 21:45:02 khorben Exp $
+# $NetBSD: rc.subr,v 1.100.4.1 2018/04/04 16:07:33 martin Exp $
 #
-# Copyright (c) 1997-2002 The NetBSD Foundation, Inc.
+# Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
 # All rights reserved.
 #
 # This code is derived from software contributed to The NetBSD Foundation
@@ -31,122 +31,19 @@
 #	functions used by various rc scripts
 #
 
-#	global variables
-#	----------------
-
-sysconfbase=/etc
-_RCCMD_chown="/usr/sbin/chown"
-_RCCMD_chroot="/usr/sbin/chroot"
-_RCCMD_ci="/usr/bin/ci"
-_RCCMD_co="/usr/bin/co"
-_RCCMD_cp="/bin/cp"
-_RCCMD_echo="echo"			# use sh builtin
-_RCCMD_kill="/bin/kill"
-_RCCMD_logger="/usr/bin/logger"
-_RCCMD_mount="/sbin/mount"
-_RCCMD_mv="/bin/mv"
-_RCCMD_nice="/usr/bin/nice"
-_RCCMD_ps="/bin/ps"
-_RCCMD_rcs="/usr/bin/rcs"
-_RCCMD_rm="/bin/rm"
-_RCCMD_sh="/bin/sh"
-_RCCMD_su="/usr/bin/su"
-_RCCMD_systrace="/bin/systrace"
-_RCCMD_whoami="/usr/bin/whoami"
-
-_RCARG_psformat="-o pid,command"
-_RCARG_ps="-ax"
-_RCARG_su="-m"
-
-_osname=$(uname -s)
-_osrelease=$(uname -r)
-case $_osname in
-	Darwin)
-		_RCCMD_echo="/bin/echo"
-		;;
-	SunOS)
-		_RCCMD_chown="/bin/chown"
-#		_RCCMD_ci="/usr/bin/ci"			# not in Solaris 9
-#		_RCCMD_co="/usr/bin/co"			# not in Solaris 9
-#		_RCCMD_systrace="/bin/systrace"		# not in Solaris 9
-		_RCARG_psformat="-o pid,comm"
-		_RCARG_ps="-ef"
-		_RCARG_su=""
-		if [ "$_osrelease" = "5.11" ]; then
-			bsd_echo () {
-				if [ "$1" = "-n" ]; then
-					shift; echo "$@\c"
-				else
-					echo "$@"
-				fi
-			}
-			_RCCMD_echo="bsd_echo"
-		else
-			_RCCMD_echo="/usr/ucb/echo"	# not in Solaris 11
-			_RCCMD_whoami="/usr/ucb/whoami"	# not in Solaris 11
-		fi
-		;;
-	Interix)
-		bsd_echo () {
-			if [ "$1" = "-n" ]; then
-				shift; echo "$@\c"
-			else
-				echo "$@"
-			fi
-		}
-		_RCCMD_chown="/usr/bin/chown"
-		_RCCMD_ci="/usr/contrib/bin/ci"
-		_RCCMD_co="/usr/contrib/bin/co"
-		_RCCMD_echo="bsd_echo"
-		_RCCMD_rcs="/usr/contrib/bin/rcs"
-		_RCARG_psformat="-wwo pid,comm"
-		;;
-	IRIX*)
-		_RCCMD_chown="/sbin/chown"
-		_RCCMD_ci="/usr/sbin/ci"
-		_RCCMD_co="/usr/sbin/co"
-		_RCCMD_cp="/sbin/cp"
-		_RCCMD_kill="kill"			# use sh builtin
-#		_RCCMD_logger="/usr/bin/logger"		# not in IRIX
-		_RCCMD_mv="/sbin/mv"
-		_RCCMD_nice="/sbin/nice"
-		_RCCMD_ps="/sbin/ps"
-		_RCCMD_rcs="/usr/sbin/rcs"
-		_RCCMD_rm="/sbin/rm"
-		_RCCMD_sh="/sbin/sh"
-		_RCCMD_su="/sbin/su"
-#		_RCCMD_systrace="/bin/systrace"		# not in IRIX
-		_RCCMD_whoami="/bin/whoami"
-		_RCARG_psformat="-o pid,comm=12345678901234567890"
-			# widen column to try to get full command-name
-		_RCARG_ps="-ef"
-		_RCARG_su=""
-		;;
-	Linux)
-		_RCCMD_chown="/bin/chown"
-#		_RCCMD_ci="/usr/bin/ci"			# not in Slackware 8.1
-#		_RCCMD_co="/usr/bin/co"			# not in Slackware 8.1
-		if [ ! -f /etc/arch-release ] ; then	# which not in Arch
-			_RCCMD_nice=$(which nice)
-		fi
-#		_RCCMD_rcs="/usr/bin/rcs"		# not in Slackware 8.1
-#		_RCCMD_systrace="/bin/systrace"		# not in Slackware 8.1
-		_RCARG_ps="ax"
-		if [ -e /etc/redhat-release ]; then
-			_RCCMD_su="/bin/su"		# for CentOS/RHEL
-		fi
-		;;
-	QNX)
-		_RCCMD_chown="/bin/chown"
-#		_RCCMD_ci="/usr/bin/ci"			# not in QNX
-#		_RCCMD_co="/usr/bin/co"			# not in QNX
-#		_RCCMD_systrace="/bin/systrace"		# not in QNX
-		_RCCMD_whoami="/usr/bin/id -un"
-		_RCARG_psformat="-o pid,comm"
-		_RCARG_ps="-ef"
-		_RCARG_su=""
-		;;
-esac
+: ${rcvar_manpage:='rc.conf(5)'}
+: ${RC_PID:=$$} ; export RC_PID
+nl='
+' # a literal newline
+
+# RC variables to clear on start.
+_env_clear_rc_vars="
+RC_PID=
+_rc_pid=
+_rc_original_stdout_fd=
+_rc_original_stderr_fd=
+_rc_postprocessor_fd=
+"
 
 #
 #	functions
@@ -154,10 +51,10 @@
 
 #
 # checkyesno var
-#	Test $1 variable, and warn if not set to YES or NO.
-#	Return 0 if it's "yes" (et al), nonzero otherwise.
+#	Test $1 variable.
+#	Return 0 if it's "yes" (et al), 1 if it's "no" (et al), 2 otherwise.
 #
-checkyesno()
+checkyesnox()
 {
 	eval _value=\$${1}
 	case $_value in
@@ -172,12 +69,45 @@
 		return 1
 		;;
 	*)
-		warn "\$${1} is not set properly - see rc.conf(5)."
-		return 1
+		return 2
 		;;
 	esac
 }
 
+#
+# 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()
+{
+	local var
+
+	checkyesnox $1
+	var=$?
+	[ $var = 0 -o $var = 1 ] && return $var
+	warn "\$${1} is not set properly - see ${rcvar_manpage}."
+	return 1
+}
+
+#
+# yesno_to_truefalse var
+#	Convert the value of a variable from any of the values
+#	understood by checkyesno() to "true" or "false".
+#
+yesno_to_truefalse()
+{
+	local var=$1
+	if checkyesno $var; then
+		eval $var=true
+		return 0
+	else
+		eval $var=false
+		return 1
+	fi
+}
+
+#
 # reverse_list list
 #	print the list in reverse order
 #
@@ -187,33 +117,84 @@
 	for _revfile; do
 		_revlist="$_revfile $_revlist"
 	done
-	${_RCCMD_echo} $_revlist
+	echo $_revlist
+}
+
+#
+# If booting directly to multiuser, send SIGTERM to
+# the parent (/etc/rc) to abort the boot.
+# Otherwise just exit.
+#
+stop_boot()
+{
+	if [ "$autoboot" = yes ]; then
+		echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!"
+		kill -TERM ${RC_PID}
+	fi
+	exit 1
 }
 
 #
 # mount_critical_filesystems type
-#	Go through the list of critical filesystems as provided in
+#	Go through the list of critical file systems 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.
+#	It's not an error if file systems prefixed with "OPTIONAL:"
+#	are not mentioned in /etc/fstab.
 #
 mount_critical_filesystems()
 {
 	eval _fslist=\$critical_filesystems_${1}
+	_mountcrit_es=0
 	for _fs in $_fslist; do
-		${_RCCMD_mount} | (
-			_ismounted=false
-			while read what _on on _type type; do
-				if [ $on = $_fs ]; then
-					_ismounted=true
+		_optional=false
+		case "$_fs" in
+		OPTIONAL:*)
+			_optional=true
+			_fs="${_fs#*:}"
+			;;
+		esac
+		_ismounted=false
+		# look for a line like "${fs} on * type *"
+		# or "* on ${fs} type *" in the output from mount.
+		case "${nl}$( mount )${nl}" in
+		*" on ${_fs} type "*)
+			_ismounted=true
+			;;
+		*"${nl}${_fs} on "*)
+			_ismounted=true
+			;;
+		esac
+		if $_ismounted; then
+			print_rc_metadata \
+			"note:File system ${_fs} was already mounted"
+		else
+			_mount_output=$( mount $_fs 2>&1 )
+			_mount_es=$?
+			case "$_mount_output" in
+			*"${nl}"*)
+				# multiple lines can't be good,
+				# not even if $_optional is true
+				;;
+			*[uU]'nknown special file or file system'*)
+				if $_optional; then
+					# ignore this error
+					print_rc_metadata \
+			"note:Optional file system ${_fs} is not present"
+					_mount_es=0
+					_mount_output=""
 				fi
-			done
-			if $_ismounted; then
-				:
-			else
-				${_RCCMD_mount} $_fs >/dev/null 2>&1
+				;;
+			esac
+			if [ -n "$_mount_output" ]; then
+				printf >&2 "%s\n" "$_mount_output"
+			fi
+			if [ "$_mount_es" != 0 ]; then
+				_mountcrit_es="$_mount_es"
 			fi
-		)
+		fi
 	done
+	return $_mountcrit_es
 }
 
 #
@@ -254,7 +235,7 @@
 	if [ -z "$_procname" ]; then
 		err 3 'USAGE: check_process procname [interpreter]'
 	fi
-	_find_processes $_procname ${_interpreter:-.} ${_RCARG_ps}
+	_find_processes $_procname ${_interpreter:-.} '-A'
 }
 
 #
@@ -272,7 +253,9 @@
 #	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.
+#	at the end.  As an alternative, to deal with interpreted daemons
+#	using perl, the basename of the interpreter plus a colon is also
+#	tried as the prefix to procname.
 #
 _find_processes()
 {
@@ -284,37 +267,46 @@
 	_psargs=$3
 
 	_pref=
+	_procnamebn=${_procname##*/}
 	if [ $_interpreter != "." ]; then	# an interpreted script
-		read _interp < $_procname	# read interpreter name
+		read _interp < ${_chroot:-}/$_procname	# read interpreter name
 		_interp=${_interp#\#!}		# strip #!
 		set -- $_interp
+		if [ $1 = "/usr/bin/env" ]; then
+			shift
+			set -- $(type $1)
+			shift $(($# - 1))
+			_interp="${1##*/} $_procname"
+		else
+			_interp="$* $_procname"
+		fi
 		if [ $_interpreter != $1 ]; then
 			warn "\$command_interpreter $_interpreter != $1"
 		fi
-		_interp="$* $_procname"		# cleanup spaces, add _procname
+		_interpbn=${1##*/}
 		_fp_args='_argv'
 		_fp_match='case "$_argv" in
-		    ${_interp}|"${_interp} "*)'
+		    ${_interp}|"${_interp} "*|"${_interpbn}: "*${_procnamebn}*)'
 	else					# a normal daemon
-		_procnamebn=${_procname##*/}
 		_fp_args='_arg0 _argv'
 		_fp_match='case "$_arg0" in
-		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})"|"[${_procnamebn}]")'
+		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")'
 	fi
 
 	_proccheck='
-		${_RCCMD_ps} ${_RCARG_psformat} '"$_psargs"' |
+		ps -o "pid,args" '"$_psargs"' |
 		while read _npid '"$_fp_args"'; do
 			case "$_npid" in
 			    PID)
 				continue ;;
 			esac ; '"$_fp_match"'
-				${_RCCMD_echo} -n "$_pref$_npid" ;
+				echo -n "$_pref$_npid" ;
 				_pref=" "
 				;;
 			esac
 		done'
 
+#echo 1>&2 "proccheck is :$_proccheck:"
 	eval $_proccheck
 }
 
@@ -332,35 +324,39 @@
 	while true; do
 		_nlist="";
 		for _j in $_list; do
-			if ${_RCCMD_kill} -0 $_j 2>/dev/null; then
+			if kill -0 $_j 2>/dev/null; then
 				_nlist="${_nlist}${_nlist:+ }$_j"
 			fi
 		done
 		if [ -z "$_nlist" ]; then
 			break
 		fi
-		_list=$_nlist
-		${_RCCMD_echo} -n ${_prefix:-"Waiting for PIDS: "}$_list
-		_prefix=", "
-		sleep 2
+		if [ "$_list" != "$_nlist" ]; then
+			_list=$_nlist
+			echo -n ${_prefix:-"Waiting for PIDS: "}$_list
+			_prefix=", "
+		fi
+		# We want this to be a tight loop for a fast exit
+		sleep 0.05
 	done
 	if [ -n "$_prefix" ]; then
-		${_RCCMD_echo} "."
+		echo "."
 	fi
 }
 
 #
-# run_rc_command argument
+# run_rc_command argument [parameters]
 #	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).
+#	(see below), and pass the optional list of parameters to it.
 #
 #	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:
 #
@@ -398,6 +394,9 @@
 #				NOTE:	$flags from the parent environment
 #					can be used to override this.
 #
+#	${name}_env	n	Additional environment variable settings
+#				for running ${command}
+#
 #	${name}_nice	n	Nice level to run ${command} at.
 #
 #	${name}_user	n	User to run ${command} as, using su(1) if not
@@ -411,13 +410,6 @@
 #				to run the chrooted ${command} with.
 #				Requires /usr to be mounted.
 #
-#	${name}_systrace n	Flags passed to systrace(1) if it is used.
-#				Setting this variable enables systracing
-# 				of the given program.  The use of "-a" is
-#				recommended so that the boot process is not
-#				stalled.  In order to pass no flags to
-#				systrace, set this variable to "--".
-#
 #	${rc_arg}_cmd	n	If set, use this as the method when invoked;
 #				Otherwise, use default command (see below)
 #
@@ -477,7 +469,7 @@
 #
 #	Variable	Purpose
 #	--------	-------
-#	rc_arg		Argument to command, after fast/force processing
+#	rc_arg		Argument to command, after fast/force/one processing
 #			performed
 #
 #	rc_flags	Flags to start the default command with.
@@ -499,21 +491,33 @@
 		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 start
-		rc_arg=${rc_arg#force}
+	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
 
-	_keywords="start stop restart rcvar $extra_commands"
+	_keywords="start stop restart rcvar"
+	if [ -n "$extra_commands" ]; then
+		_keywords="${_keywords} ${extra_commands}"
+	fi
 	rc_pid=
 	_pidcmd=
 	_procname=${procname:-${command}}
@@ -533,6 +537,7 @@
 	if [ -z "$rc_arg" ]; then
 		rc_usage "$_keywords"
 	fi
+	shift	# remove $rc_arg from the positional parameters
 
 	if [ -n "$flags" ]; then	# allow override from environment
 		rc_flags=$flags
@@ -542,10 +547,10 @@
 	eval _chdir=\$${name}_chdir	_chroot=\$${name}_chroot \
 	    _nice=\$${name}_nice	_user=\$${name}_user \
 	    _group=\$${name}_group	_groups=\$${name}_groups \
-	    _systrace=\$${name}_systrace
+	    _env=\"\$${name}_env\"
 
 	if [ -n "$_user" ]; then	# unset $_user if running as that user
-		if [ "$_user" = "$($_RCCMD_whoami)" ]; then
+		if [ "$_user" = "$(id -un)" ]; then
 			unset _user
 		fi
 	fi
@@ -553,11 +558,27 @@
 					# if ${rcvar} is set, and $1 is not
 					# "rcvar", then run
 					#	checkyesno ${rcvar}
-					# and return if that failed
+					# and return if that failed or warn
+					# user and exit when interactive
 					#
 	if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then
 		if ! checkyesno ${rcvar}; then
-			return 0
+					# check whether interactive or not
+			if [ -n "$_run_rc_script" ]; then
+				return 0
+			fi
+			for _elem in $_keywords; do
+				if [ "$_elem" = "$rc_arg" ]; then
+					cat 1>&2 <<EOF
+\$${rcvar} is not enabled - see ${rcvar_manpage}.
+Use the following if you wish to perform the operation:
+  $0 one${rc_arg}
+EOF
+					exit 1
+				fi
+			done
+			echo 1>&2 "$0: unknown directive '$rc_arg'."
+			rc_usage "$_keywords"
 		fi
 	fi
 
@@ -581,29 +602,31 @@
 				return 1
 			fi
 
-			if ! eval $_cmd && [ -z "$rc_force" ]; then
+			if ! eval $_cmd \"\${@}\" && [ -z "$rc_force" ]; then
 				return 1
 			fi
 			eval $_postcmd
 			return 0
 		fi
 
+		if [ ${#} -gt 0 ]; then
+			err 1 "the $rc_arg command does not take any parameters"
+		fi
+
 		case "$rc_arg" in	# default operations...
 
 		status)
 			if [ -n "$rc_pid" ]; then
-				${_RCCMD_echo} \
-				    "${name} is running as pid $rc_pid."
+				echo "${name} is running as pid $rc_pid."
 			else
-				${_RCCMD_echo} "${name} is not running."
+				echo "${name} is not running."
 				return 1
 			fi
 			;;
 
 		start)
 			if [ -n "$rc_pid" ]; then
-				${_RCCMD_echo} \
-				    "${name} already running? (pid=$rc_pid)."
+				echo 1>&2 "${name} already running? (pid=$rc_pid)."
 				exit 1
 			fi
 
@@ -616,7 +639,7 @@
 					#
 			for _f in $required_vars; do
 				if ! checkyesno $_f; then
-					warn "\$${_f} is not set."
+					warn "\$${_f} is not enabled."
 					if [ -z "$rc_force" ]; then
 						return 1
 					fi
@@ -648,35 +671,21 @@
 
 					# setup the command to run, and run it
 					#
-			${_RCCMD_echo} "Starting ${name}."
+			echo "Starting ${name}."
 			if [ -n "$_chroot" ]; then
-				if [ "$_osname" = "SunOS" ]; then
-					_doit="\
-${_nice:+${_RCCMD_nice} -n $_nice }\
-${_RCCMD_chroot} $_chroot"
-					if [ -n "$_user" ]; then
-						_doit="\
-$_doit ${_RCCMD_su} ${_RCARG_su} $_user \
--c '${_RCCMD_sh} -c'"
-					fi
-					_doit="\
-$_doit $command $rc_flags $command_args"
-				else
-					_doit="\
-${_nice:+${_RCCMD_nice} -n $_nice }\
-${_systrace:+${_RCCMD_systrace} $_systrace }\
-${_RCCMD_chroot} ${_user:+-u $_user }${_group:+-g $_group }\
-${_groups:+-G $_groups } $_chroot $command $rc_flags $command_args"
-				fi
+				_doit="\
+$_env_clear_rc_vars $_env \
+${_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:+${_RCCMD_nice} -n $_nice }\
-${_systrace:+${_RCCMD_systrace} $_systrace }\
+$_env_clear_rc_vars $_env \
+${_nice:+nice -n $_nice }\
 $command $rc_flags $command_args"
 				if [ -n "$_user" ]; then
-				    _doit="${_RCCMD_su} ${_RCARG_su} $_user \
-					-c '${_RCCMD_sh} -c \"$_doit\"'"
+				    _doit="su -m $_user -c 'sh -c \"$_doit\"'"
 				fi
 			fi
 
@@ -695,10 +704,10 @@
 		stop)
 			if [ -z "$rc_pid" ]; then
 				if [ -n "$pidfile" ]; then
-					${_RCCMD_echo} \
+					echo 1>&2 \
 				    "${name} not running? (check $pidfile)."
 				else
-					${_RCCMD_echo} "${name} not running?"
+					echo 1>&2 "${name} not running?"
 				fi
 				exit 1
 			fi
@@ -712,11 +721,10 @@
 
 					# send the signal to stop
 					#
-			${_RCCMD_echo} "Stopping ${name}."
-			_doit="${_RCCMD_kill} -${sig_stop:-TERM} $rc_pid"
+			echo "Stopping ${name}."
+			_doit="kill -${sig_stop:-TERM} $rc_pid"
 			if [ -n "$_user" ]; then
-				_doit="${_RCCMD_su} ${_RCARG_su} $_user \
-				    -c '${_RCCMD_sh} -c \"$_doit\"'"
+				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
 			fi
 
 					# if the stop cmd failed and force
@@ -735,20 +743,20 @@
 		reload)
 			if [ -z "$rc_pid" ]; then
 				if [ -n "$pidfile" ]; then
-					${_RCCMD_echo} \
+					echo 1>&2 \
 				    "${name} not running? (check $pidfile)."
 				else
-					${_RCCMD_echo} "${name} not running?"
+					echo 1>&2 "${name} not running?"
 				fi
 				exit 1
 			fi
-			${_RCCMD_echo} "Reloading ${name} config files."
+			echo "Reloading ${name} config files."
 			if ! eval $_precmd && [ -z "$rc_force" ]; then
 				return 1
 			fi
-			_doit="${_RCCMD_kill} -${sig_reload:-HUP} $rc_pid"
+			_doit="kill -${sig_reload:-HUP} $rc_pid"
 			if [ -n "$_user" ]; then
-				_doit="${_RCCMD_su} ${_RCARG_su} $_user -c '${_RCCMD_sh} -c \"$_doit\"'"
+				_doit="su -m $_user -c 'sh -c \"$_doit\"'"
 			fi
 			if ! eval $_doit && [ -z "$rc_force" ]; then
 				return 1
@@ -768,8 +776,8 @@
 			fi
 			_rc_restart_done=true
 
-			( $0 ${rc_force:+force}stop )
-			$0 ${rc_force:+force}start
+			( $0 ${_rc_prefix}stop )
+			$0 ${_rc_prefix}start
 
 			eval $_postcmd
 			;;
@@ -781,12 +789,12 @@
 			;;
 
 		rcvar)
-			${_RCCMD_echo} "# $name"
+			echo "# $name"
 			if [ -n "$rcvar" ]; then
 				if checkyesno ${rcvar}; then
-					${_RCCMD_echo} "\$${rcvar}=YES"
+					echo "\$${rcvar}=YES"
 				else
-					${_RCCMD_echo} "\$${rcvar}=NO"
+					echo "\$${rcvar}=NO"
 				fi
 			fi
 			;;
@@ -799,12 +807,31 @@
 		return 0
 	done
 
-	${_RCCMD_echo} 1>&2 "$0: unknown directive '$rc_arg'."
+	echo 1>&2 "$0: unknown directive '$rc_arg'."
 	rc_usage "$_keywords"
 	exit 1
 }
 
 #
+# _have_rc_postprocessor
+#	Test whether the current script is running in a context that
+#	was invoked from /etc/rc with a postprocessor.
+#
+#	If the test fails, some variables may be unset to make
+#	such tests more efficient in future.
+#
+_have_rc_postprocessor()
+{
+	# Cheap tests that fd and pid are set, fd is writable.
+	[ -n "${_rc_pid}" ] || { unset _rc_pid; return 1; }
+	[ -n "${_rc_postprocessor_fd}" ] || { unset _rc_pid; return 1; }
+	eval ": >&${_rc_postprocessor_fd}" 2>/dev/null \
+	|| { unset _rc_pid; return 1; }
+
+	return 0
+}
+
+#
 # 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
@@ -812,6 +839,12 @@
 #	a backup or scratch file, ignore it.  Otherwise if it's
 #	executable run as a child process.
 #
+#	If `file' contains "KEYWORD: interactive" and if we are
+#	running inside /etc/rc with postprocessing, then the script's
+#	stdout and stderr are redirected to $_rc_original_stdout_fd and
+#	$_rc_original_stderr_fd, so the output will be displayed on the
+#	console but not intercepted by /etc/rc's postprocessor.
+#
 run_rc_script()
 {
 	_file=$1
@@ -820,32 +853,60 @@
 		err 3 'USAGE: run_rc_script file arg'
 	fi
 
+	_run_rc_script=true
+
 	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
 
+	_must_redirect=false
+	if _have_rc_postprocessor \
+	    && _has_rcorder_keyword interactive $_file
+	then
+		_must_redirect=true
+	fi
+
 	case "$_file" in
 	*.sh)				# run in current shell
-		set $_arg ; . $_file
+		if $_must_redirect; then
+			print_rc_metadata \
+			    "note:Output from ${_file} is not logged"
+			no_rc_postprocess eval \
+			    'set $_arg ; . $_file'
+		else
+			set $_arg ; . $_file
+		fi
 		;;
-	*[~#]|*.OLD|*.orig)		# scratch file; skip
+	*[~#]|*.OLD|*.orig|*,v)		# scratch file; skip
 		warn "Ignoring scratch file $_file"
 		;;
 	*)				# run in subshell
-		if [ -x $_file ]; then
+		if [ -x $_file ] && $_must_redirect; then
+			print_rc_metadata \
+			    "note:Output from ${_file} is not logged"
+			if [ -n "$rc_fast_and_loose" ]; then
+				no_rc_postprocess eval \
+				    'set $_arg ; . $_file'
+			else
+				no_rc_postprocess eval \
+				    '( set $_arg ; . $_file )'
+			fi
+		elif [ -x $_file ]; then
 			if [ -n "$rc_fast_and_loose" ]; then
 				set $_arg ; . $_file
 			else
 				( set $_arg ; . $_file )
 			fi
+		else
+			warn "Ignoring non-executable file $_file"
 		fi
 		;;
 	esac
 }
 
 #
-# load_rc_config
+# load_rc_config command
 #	Source in the configuration file for a given command.
 #
 load_rc_config()
@@ -858,14 +919,11 @@
 	if ${_rc_conf_loaded:-false}; then
 		:
 	else
-		. ${sysconfbase}/rc.conf
+		. /etc/rc.conf
 		_rc_conf_loaded=true
 	fi
-	if [ "$_osname" = "OpenBSD" ] && [ -f ${sysconfbase}/rc.conf.local ]; then
-		. ${sysconfbase}/rc.conf.local
-	fi
-	if [ -f ${sysconfbase}/rc.conf.d/"$_command" ]; then
-		. ${sysconfbase}/rc.conf.d/"$_command"
+	if [ -f /etc/rc.conf.d/"$_command" ]; then
+		. /etc/rc.conf.d/"$_command"
 	fi
 }
 
@@ -882,13 +940,12 @@
 	fi
 	eval $(eval '(
 		load_rc_config '$1' >/dev/null;
-		if [ -n "${'$2'}" ] || [ "${'$2'-UNSET}" != "UNSET" ]; then
+		if [ -n "${'$2'}" -o "${'$2'-UNSET}" != "UNSET" ]; then
 			echo '$2'=\'\''${'$2'}\'\'';
 		fi
 	)' )
 }
 
-
 #
 # rc_usage commands
 #	Print a usage string for $0, with `commands' being a list of
@@ -896,14 +953,14 @@
 #
 rc_usage()
 {
-	${_RCCMD_echo} -n 1>&2 "Usage: $0 [fast|force]("
+	echo -n 1>&2 "Usage: $0 [fast|force|one]("
 
 	_sep=
 	for _elem; do
-		${_RCCMD_echo} -n 1>&2 "$_sep$_elem"
+		echo -n 1>&2 "$_sep$_elem"
 		_sep="|"
 	done
-	${_RCCMD_echo} 1>&2 ")"
+	echo 1>&2 ")"
 	exit 1
 }
 
@@ -916,10 +973,10 @@
 	exitval=$1
 	shift
 
-	if [ -x ${_RCCMD_logger} ]; then
-		${_RCCMD_logger} "$0: ERROR: $*"
+	if [ -x /usr/bin/logger ]; then
+		logger "$0: ERROR: $*"
 	fi
-	${_RCCMD_echo} 1>&2 "$0: ERROR: $*"
+	echo 1>&2 "$0: ERROR: $*"
 	exit $exitval
 }
 
@@ -929,10 +986,10 @@
 #
 warn()
 {
-	if [ -x ${_RCCMD_logger} ]; then
-		${_RCCMD_logger} "$0: WARNING: $*"
+	if [ -x /usr/bin/logger ]; then
+		logger "$0: WARNING: $*"
 	fi
-	${_RCCMD_echo} 1>&2 "$0: WARNING: $*"
+	echo 1>&2 "$0: WARNING: $*"
 }
 
 #
@@ -975,7 +1032,7 @@
 
 		# ensure that history file is not locked
 		if [ -f $_cur,v ]; then
-			${_RCCMD_rcs} -q -u -U -M $_cur
+			rcs -q -u -U -M $_cur
 		fi
 
 		# ensure after switching to rcs that the
@@ -983,41 +1040,333 @@
 		if [ -f $_cur ]; then
 			# no archive, or current newer than archive
 			if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then
-				${_RCCMD_ci} -q -f -u -t-"$_msg0" \
-				    -m"$_msg1" $_cur
-				${_RCCMD_rcs} -q -kb -U $_cur
-				${_RCCMD_co} -q -f -u $_cur
+				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)
-			${_RCCMD_cp} -p $_file $_cur
-			${_RCCMD_ci} -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
-			${_RCCMD_rcs} -q -kb -U $_cur
-			${_RCCMD_co} -q -f -u $_cur
-			${_RCCMD_chown} root:wheel $_cur $_cur,v
+			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)
-			${_RCCMD_cp} /dev/null $_cur
-			${_RCCMD_ci} -q -f -u -t-"$_msg0" -m"$_msg1" $_cur
-			${_RCCMD_rcs} -q -kb -U $_cur
-			${_RCCMD_chown} root:wheel $_cur $_cur,v
-			${_RCCMD_rm} $_cur
+			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
-				${_RCCMD_cp} -p $_cur $_back
+				cp -p $_cur $_back
 			fi
-			${_RCCMD_cp} -p $_file $_cur
-			${_RCCMD_chown} root:wheel $_cur
+			cp -p $_file $_cur
+			chown root:wheel $_cur
 			;;
 		remove)
-			${_RCCMD_mv} -f $_cur $_back
+			mv -f $_cur $_back
 			;;
 		esac
 	fi
 }
+
+#
+# handle_fsck_error fsck_exit_code
+#	Take action depending on the return code from fsck.
+#
+handle_fsck_error()
+{
+	case $1 in
+	0)	# OK
+		return
+		;;
+	2)	# Needs re-run, still fs errors
+		echo "File system still has errors; re-run fsck manually!"
+		;;
+	4)	# Root modified
+		echo "Root file system was modified, rebooting ..."
+		reboot -n
+		echo "Reboot failed; help!"
+		;;
+	8)	# Check failed
+		echo "Automatic file system check failed; help!"
+		;;
+	12)	# Got signal
+		echo "Boot interrupted."
+		;;
+	*)
+		echo "Unknown error $1; help!"
+		;;
+	esac
+	stop_boot
+}
+
+#
+# _has_rcorder_keyword word file
+#	Check whether a file contains a "# KEYWORD:" comment with a
+#	specified keyword in the style used by rcorder(8).
+#
+_has_rcorder_keyword()
+{
+	local word="$1"
+	local file="$2"
+	local line
+
+	[ -r "$file" ] || return 1
+	while read line; do
+		case "${line} " in
+		"# KEYWORD:"*[\ \	]"${word}"[\ \	]*)
+			return 0
+			;;
+		"#"*)
+			continue
+			;;
+		*[A-Za-z0-9]*)
+			# give up at the first non-empty non-comment line
+			return 1
+			;;
+		esac
+	done <"$file"
+	return 1
+}
+
+#
+# print_rc_metadata string
+#	Print the specified string in such a way that the post-processor
+#	inside /etc/rc will treat it as meta-data.
+#
+#	If we are not running inside /etc/rc, do nothing.
+#
+#	For public use by any rc.d script, the string must begin with
+#	"note:", followed by arbitrary text.  The intent is that the text
+#	will appear in a log file but not on the console.
+#
+#	For private use within /etc/rc, the string must contain a
+#	keyword recognised by the rc_postprocess_metadata() function
+#	defined in /etc/rc, followed by a colon, followed by one or more
+#	colon-separated arguments associated with the keyword.
+#
+print_rc_metadata()
+{
+	# _rc_postprocessor fd, if defined, is the fd to which we must
+	# print, prefixing the output with $_rc_metadata_prefix.
+	#
+	if _have_rc_postprocessor; then
+		command printf "%s%s\n" "$rc_metadata_prefix" "$1" \
+			>&${_rc_postprocessor_fd}
+	fi
+}
+
+#
+# _flush_rc_output
+#	Arrange for output to be flushed, if we are running
+#	inside /etc/rc with postprocessing.
+#
+_flush_rc_output()
+{
+	print_rc_metadata "nop"
+}
+
+#
+# print_rc_normal [-n] string
+#	Print the specified string in such way that it is treated as
+#	normal output, regardless of whether or not we are running
+#	inside /etc/rc with post-processing.
+#
+#	If "-n" is specified in $1, then the string in $2 is printed
+#	without a newline; otherwise, the string in $1 is printed
+#	with a newline.
+#
+#	Intended use cases include:
+#
+#	o   An rc.d script can use ``print_rc_normal -n'' to print a
+#	    partial line in such a way that it appears immediately
+#	    instead of being buffered by rc(8)'s post-processor.
+#
+#	o   An rc.d script that is run via the no_rc_postprocess
+#	    function (so most of its output is invisible to rc(8)'s
+#	    post-processor) can use print_rc_normal to force some of its
+#	    output to be seen by the post-processor.
+#
+#
+print_rc_normal()
+{
+	# print to stdout or _rc_postprocessor_fd, depending on
+	# whether not we have an rc postprocessor.
+	#
+	local fd=1
+	_have_rc_postprocessor && fd="${_rc_postprocessor_fd}"
+	case "$1" in
+	"-n")
+		command printf "%s" "$2" >&${fd}
+		_flush_rc_output
+		;;
+	*)
+		command printf "%s\n" "$1" >&${fd}
+		;;
+	esac
+}
+
+#
+# no_rc_postprocess cmd...
+#	Execute the specified command in such a way that its output
+#	bypasses the post-processor that handles the output from
+#	most commands that are run inside /etc/rc.  If we are not
+#	inside /etc/rc, then just execute the command without special
+#	treatment.
+#
+#	The intent is that interactive commands can be run via
+#	no_rc_postprocess(), and their output will apear immediately
+#	on the console instead of being hidden or delayed by the
+#	post-processor.	 An unfortunate consequence of the output
+#	bypassing the post-processor is that the output will not be
+#	logged.
+#
+no_rc_postprocess()
+{
+	if _have_rc_postprocessor; then
+		"$@" >&${_rc_original_stdout_fd} 2>&${_rc_original_stderr_fd}
+	else
+		"$@"
+	fi
+}
+
+#
+# twiddle
+#	On each call, print a different one of "/", "-", "\\", "|",
+#	followed by a backspace.  The most recently printed value is
+#	saved in $_twiddle_state.
+#
+#	Output is to /dev/tty, so this function may be useful even inside
+#	a script whose output is redirected.
+#
+twiddle()
+{
+	case "$_twiddle_state" in
+	'/')	_next='-' ;;
+	'-')	_next='\' ;;
+	'\')	_next='|' ;;
+	*)	_next='/' ;;
+	esac
+	command printf "%s\b" "$_next" >/dev/tty
+	_twiddle_state="$_next"
+}
+
+#
+# human_exit_code
+#	Print the a human version of the exit code.
+#
+human_exit_code()
+{
+	if [ "$1" -lt 127 ]
+	then
+		echo "exited with code $1"
+	elif [ "$(expr $1 % 256)" -eq 127 ]
+	then
+		# This cannot really happen because the shell will not
+		# pass stopped job status out and the exit code is limited
+		# to 8 bits. This code is here just for completeness.
+		echo "stopped with signal $(expr $1 / 256)"
+	else
+		echo "terminated with signal $(expr $1 - 128)"
+	fi
+}
+
+#
+# collapse_backslash_newline
+#	Copy input to output, collapsing <backslash><newline>
+#	to nothing, but leaving other backslashes alone.
+#
+collapse_backslash_newline()
+{
+	local line
+	while read -r line ; do
+		case "$line" in
+		*\\)
+			# print it, without the backslash or newline
+			command printf "%s" "${line%?}"
+			;;
+		*)
+			# print it, with a newline
+			command printf "%s\n" "${line}"
+			;;
+		esac
+	done
+}
+
+# Shell implementations of basename and dirname, usable before
+# the /usr file system is mounted.
+#
+basename()
+{
+	local file="$1"
+	local suffix="$2"
+	local base
+
+	base="${file##*/}"		# remove up to and including last '/'
+	base="${base%${suffix}}"	# remove suffix, if any
+	command printf "%s\n" "${base}"
+}
+
+dirname()
+{
+	local file="$1"
+	local dir
+
+	case "$file" in
+	/*/*)	dir="${file%/*}" ;;	# common case: absolute path
+	/*)	dir="/" ;;		# special case: name in root dir
+	*/*)	dir="${file%/*}" ;;	# common case: relative path with '/'
+	*)	dir="." ;;		# special case: name without '/'
+	esac
+	command printf "%s\n" "${dir}"
+}
+
+# Override the normal "echo" and "printf" commands, so that
+# partial lines printed by rc.d scripts appear immediately,
+# instead of being buffered by rc(8)'s post-processor.
+#
+# Naive use of the echo or printf commands from rc.d scripts,
+# elsewhere in rc.subr, or anything else that sources rc.subr,
+# will call these functions.  To call the real echo and printf
+# commands, use "command echo" or "command printf".
+#
+echo()
+{
+	command echo "$@"
+	case "$1" in
+	'-n')	_flush_rc_output ;;
+	esac
+}
+printf()
+{
+	command printf "$@"
+	case "$1" in
+	*'\n')	: ;;
+	*)	_flush_rc_output ;;
+	esac
+}
+
+kat() {
+	local i
+	local v
+	for i; do
+		while read -r v; do
+			v="${v%%#*}"
+			if [ -z "$v" ]; then
+				continue
+			fi
+			echo "$v"
+		done < "$i"
+	done
+}
+
+_rc_subr_loaded=:


Home | Main Index | Thread Index | Old Index