Subject: misc/34693: /etc/rc.d/bootconf.sh enhancements (patch supplied)
To: None <misc-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <j+nbsd@2006.salmi.ch>
List: netbsd-bugs
Date: 10/02/2006 11:10:01
>Number:         34693
>Category:       misc
>Synopsis:       /etc/rc.d/bootconf.sh enhancements (patch supplied)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    misc-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Oct 02 11:10:00 +0000 2006
>Originator:     Jukka Salmi
>Release:        NetBSD 4.99.2
>Environment:
System: NetBSD moray.salmi.ch 4.99.2 NetBSD 4.99.2 (MORAY.APM) #0: Thu Sep 21 10:16:57 CEST 2006 build@moray.salmi.ch:/build/nbsd/i386/sys/arch/i386/compile/MORAY.APM i386
Architecture: i386
Machine: i386
>Description:

This patch changes the bootconf.sh rc.d script and achieves the
following:

* Each boot-up configuration (which you still create manually or using
  newbtconf(8) as before) may have zero or more options. Such options
  can be used for boot-up configurations which are similar but differ
  in a few details. Consider the following example setup:

    - configurations: `home', `work' and `away'
    - `home' has options `nonet', `lan' and `wlan'
    - `work' has options `lan', `customer1' and `customer2'
    - `away' has no options

  With the current bootconf.sh, you'd need seven /etc/etc.* directories
  for this setup. With this patch, you'd need only three of them, each
  with some additional options. These options can then be use in rc.conf
  like this:

	case "$bootconf_option" in
		lan|wlan)
			sshd=YES
			;;
		nonet)
			inetd=NO
			;;
	esac

* Print countdown timer with user-settable delay ($bootconf_delay).
  If the countdown elapses or enter is hit while it is still running,
  the default configuration is started (with the option it was last
  used with, in case that configuration has options). If the countdown
  is interrupted (Ctrl-C), a (very basic) menu is printed, prompting
  for configuration and option names.


To try the new bootconf.sh's options feature, apply the attached patch
and add some options to your existing boot-up configurations, e.g.

$ echo "bootconf_options='opt1 opt2 opt3'" >/etc/etc.conf1/bootconf.options
$ echo "bootconf_options='opt4 opt5 opt6'" >/etc/etc.conf2/bootconf.options
$ [...]

and change the rc.conf files to make use of these options (see above).
Then copy the bootconf.options file (also in the patch) to /etc and
source it in the rc.conf files before you first refer to
${bootconf_option} in rc.conf.

BTW: I [1]proposed this some months ago on current-users. The problem
I mentioned there about the "Terminated" message was fixed in the
meantime.

[1] http://mail-index.netbsd.org/current-users/2006/01/21/0007.html

>How-To-Repeat:
n/a
>Fix:
The following patch is also available from

http://salmi.ch/~jukka/patches/nbsd/HEAD/etc/rc.d/bootconf.patch

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	bootconf.patch
#
echo x - bootconf.patch
sed 's/^X//' >bootconf.patch << 'END-of-bootconf.patch'
Xhttp://mail-index.netbsd.org/current-users/2006/01/21/0007.html
X
XIndex: etc/rc.d/bootconf.sh
X===================================================================
XRCS file: /cvsroot/src/etc/rc.d/bootconf.sh,v
Xretrieving revision 1.9
Xdiff -u -p -r1.9 bootconf.sh
X+++ etc/rc.d/bootconf.sh	2 Jun 2006 11:28:00 -0000
X@@ -6,10 +6,11 @@
X # PROVIDE: bootconf
X # REQUIRE: mountcritlocal
X 
X+# Refer to newbtconf(8) for more information.
X+
X bootconf_start()
X {
X-		# Refer to newbtconf(8) for more information
X-		#
X+	local def= default=
X 
X 	if [ ! -e /etc/etc.current ]; then
X 		return 0
X@@ -18,54 +19,23 @@ bootconf_start()
X 		def=$(ls -ld /etc/etc.default 2>&1)
X 		default="${def##*-> *etc.}"
X 	else
X-		default=current
X+		default='current'
X 	fi
X-	if [ "$default" = "current" ]; then
X+	if [ "$default" = 'current' ]; then
X 		def=$(ls -ld /etc/etc.current 2>&1)
X 		default="${def##*-> *etc.}"
X 	fi
X+	conf="$default"
X 
X-	spc=""
X-	for i in /etc/etc.*; do
X-		name="${i##/etc/etc.}"
X-		case $name in
X-		current|default|\*)
X-			continue
X-			;;	
X-		*)
X-			if [ "$name" = "$default" ]; then
X-				echo -n "${spc}[${name}]"
X-			else
X-				echo -n "${spc}${name}"
X-			fi
X-			spc=" "
X-			;;
X-		esac
X-	done
X-	echo
X-	master=$$
X-	_DUMMY=/etc/passwd
X-	conf=${_DUMMY}
X-	while [ ! -d /etc/etc.$conf/. ]; do
X-		trap "conf=$default; echo; echo Using default of $default" ALRM
X-		echo -n "Which configuration [$default] ? "
X-		(sleep 30 && kill -ALRM $master) >/dev/null 2>&1 &
X-		read conf
X-		if [ -z $conf ] ; then
X-			conf=$default
X-		fi
X-		if [ ! -d /etc/etc.$conf/. ]; then
X-			conf=${_DUMMY}
X-		fi
X-	done
X+	bootconf
X 
X-	case  $conf in
X-	current|default)
X+	case "$conf" in
X+	current|default|"$default")
X+		#sleep 0 # flush "Terminated" message
X 		;;
X 	*)
X 		rm -f /etc/etc.current
X-		ln -s etc.$conf /etc/etc.current
X+		ln -s etc."$conf" /etc/etc.current
X 		;;
X 	esac
X 
X@@ -74,8 +44,155 @@ bootconf_start()
X 	fi
X }
X 
X-case "$1" in
X-*start)
X-	bootconf_start
X-	;;
X+# suppress SIGTERM message from shell when killing process running
X+# in the background (thanks to the anonymous poster!)
X+quiet_kill()
X+{
X+	exec 3>&2	# Duplicate stderr.
X+	exec 2>&-	# Close stderr (redirection to /dev/null works, too).
X+	kill $1
X+	sleep 0		# This allows the terminate message to flush.
X+			# XXX - There must be a better way to flush this!
X+	exec 2>&3	# Restore stderr.
X+	exec 3>&-	# Close copy of stderr.
X+}
X+
X+bootconf()
X+{
X+	local bc_opt= bc_opt_str=
X+	local pid= line=
X+
X+	bc_opt="$(get_bc_opt)" && bc_opt_str=", $bc_opt"
X+
X+	echo 'bootconf: Ctrl-C to select configuration, enter for default'
X+	countdown "$conf$bc_opt_str" ${bootconf_delay:-30} &
X+	pid=$!
X+
X+	# set up self-resetting traps:
X+	#  SIGCHLD: countdown elapsed
X+	#  SIGINT:  user typed ^C
X+	trap 'trap - CHLD; echo; return' CHLD
X+	trap "trap - CHLD; trap : INT; quiet_kill $pid; select_conf; return" INT
X+
X+	# if this read returns, the user must have hit enter while the
X+	# countdown was running -> reset traps and and kill countdown
X+	read line
X+	trap - CHLD
X+	trap : INT
X+
X+	# if `kill $pid' is used here or from the INT trap, shell prints
X+	# [1]   Terminated             countdown "${con...
X+	# after boot-up continues...
X+	quiet_kill $pid
X+}
X+
X+countdown()
X+{
X+	local bc="$1"
X+	local delay=$2
X+	local i=$delay
X+
X+	while [ $i -gt 0 ]; do
X+		printf "\rUsing boot-up configuration \`%s' in %*d" \
X+		    "$bc" ${#delay} $i
X+		i=$(($i-1))
X+		sleep 1
X+	done
X+	printf "\rUsing boot-up configuration \`%s' in %*d" \
X+	    "$bc" ${#delay} 0
X+}
X+
X+#
X+# Prompt for boot-up configuration name.
X+# If the chosen configuration has options, i.e. the file
X+# /etc/etc.$conf/bootconf.options sets the `bootconf_options' variable to
X+# contain option names, additionally prompt for desired option.
X+#
X+select_conf()
X+{
X+	local default="$conf"
X+	local dir= name=
X+	local bootconf_options= bc_opt= bc_opt_def=
X+
X+	echo
X+	while : ; do
X+		echo -n 'Boot-up configurations:'
X+		for dir in /etc/etc.*; do
X+			name="${dir##/etc/etc.}"
X+			case "$name" in
X+			current|default|\*)
X+				continue
X+				;;	
X+			*)
X+				[ "$name" = "$default" ] && name="[$name]"
X+				echo -n " $name"
X+				;;
X+			esac
X+		done
X+		echo
X+
X+		echo -n "Configuration [$default]: "
X+		read conf
X+		[ -z "$conf" ] && conf="$default"
X+
X+		if [ ! -d /etc/etc."$conf"/. ]; then
X+			echo "Invalid configuration \`$conf'"
X+			conf=
X+			continue
X+		fi
X+
X+		# if there are no config options, we're done
X+		[ -f /etc/etc."$conf"/bootconf.options ] || break
X+		bootconf_options=
X+		. /etc/etc."$conf"/bootconf.options
X+		[ -z "$bootconf_options" ] && break
X+
X+		bc_opt=
X+		bc_opt_def="$(get_bc_opt)"
X+
X+		# read until we get a valid option
X+		while :; do
X+			echo -n "Configuration options for \`$conf':"
X+			for name in $bootconf_options; do
X+				[ "$name" = "$bc_opt_def" ] && name="[$name]"
X+				echo -n " $name"
X+			done
X+			echo
X+
X+			echo -n "Option${bc_opt_def:+ [$bc_opt_def]}: "
X+			read bc_opt
X+			[ -z "$bc_opt" ] && bc_opt="$bc_opt_def"
X+
X+			# c: choose different configuration
X+			[ "$bc_opt" = 'c' ] && break
X+
X+			# check if desired option is valid
X+			for name in $bootconf_options; do
X+				[ "$bc_opt" != "$name" ] && continue
X+				# remember choice
X+				echo "bc_opt='$bc_opt'" \
X+				    >/etc/etc."$conf"/.bootconf.option
X+				break 3
X+			done
X+			[ -z "$bc_opt" ] || echo "Invalid option \`$bc_opt'"
X+		done
X+	done
X+
X+	echo "Using boot-up configuration \`$conf${bc_opt:+, $bc_opt}'"
X+}
X+
X+get_bc_opt()
X+{
X+	local bc_opt=
X+
X+	[ -f /etc/etc."$conf"/.bootconf.option ] && \
X+	    . /etc/etc."$conf"/.bootconf.option
X+
X+	[ -z "$bc_opt" ] && return 1
X+	echo "$bc_opt"
X+}
X+
X+
X+case "$1" in *start)
X+	bootconf_start ;;
X esac
X+++ etc/bootconf.option	2006-10-02 12:10:50.000000000 +0200
X@@ -0,0 +1,7 @@
X+# /etc/bootconf.option
X+
X+bc_opt=
X+[ -f /etc/etc.current/.bootconf.option ] && \
X+    . /etc/etc.current/.bootconf.option
X+bootconf_option="$bc_opt"
X+unset bc_opt
END-of-bootconf.patch
exit