Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 07 Jul 2009 07:05:45 +0900 (JST)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        freebsd-rc@FreeBSD.org
Cc:        freebsd-current@FreeBSD.org
Subject:   RFC: set_rcvar in rc.subr
Message-ID:  <20090707.070545.02771440.hrs@allbsd.org>

next in thread | raw e-mail | index | archive | help
----Security_Multipart0(Tue_Jul__7_07_05_45_2009_685)--
Content-Type: Multipart/Mixed;
	boundary="--Next_Part(Tue_Jul__7_07_05_45_2009_646)--"
Content-Transfer-Encoding: 7bit

----Next_Part(Tue_Jul__7_07_05_45_2009_646)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

 I would like to propose an expansion of set_rcvar() in rc.subr.  The
 motivation and the change are the following.

 The current rc.d scripts depend on variables defined in
 /etc/defaults/rc.conf. However, it is unclear that which variables
 are used in a script and assigning a default value to a variable is
 scattered and inconsistent.  Also, it is difficult to detect
 definition of obsolete variables in /etc/rc.conf and
 /etc/defaults/rc.conf.

 The proposed changes are:

 1. Add a functionality to declare a rc.conf variable and its default
    value to set_rcvar().  The syntax is:

    set_rcvar <varname> <defvalue> <desc>

    The declared variables are set by load_rc_config().  Note that
    this behavior of set_rcvar() is backward compatible.

    For example, a script for routed(8) will be something like this:

    ----
    name="routed"
    rcvar=`set_rcvar`

    set_rcvar ${name}_enable NO
    set_rcvar ${name}_flags "-q" \
        "Flags for ${name}(8)."
    set_rcvar ${name}_program "/usr/sbin/routed" \
        "Program name for ${name}(8)."

    load_rc_config $name
    run_rc_command "$1"
    ----

 2. Display the declared variables by "rc.d/foo rcvar" with
    the default value and description like this:

    % /etc/rc.d/routed rcvar
    # routed : network RIP and router discovery routing daemon
    #
    routed_enable="NO"
    #   (default: "NO")
    routed_flags="-q"
    # - Flags for routed(8).
    #   (default: "-q")
    routed_program="/sbin/routed"
    # - Program name for routed(8).
    #   (default: "/usr/sbin/routed")

    It should be easier to understand the variables than the current
    /etc/defaults/rc.conf and always consistent.

    To do this, all of rc.d scripts have to have run_rc_command()
    while currently some scripts which always run have no $rcvar and
    run_rc_command().  Adding run_rc_command() becomes no problem and
    rather good for consistency, IMHO.  Also, $desc is added for
    description of the script displayed in above example.

    Entries for each rc.d script in /etc/defaults/rc.conf can be
    removed, and the equivalent contents can be generated by the
    following command:

    # for F in `rcorder /etc/rc.d/*`; do $F rcvar; done

 3. Add a way to obsolete a variable.  This is done by adding
    set_rcvar_obsolete() function.

    set_rcvar_obsolete <oldvar> <newvar>

    If <oldvar> is defined, do newvar=$oldvar and display a warning in
    load_rc_config().  This makes easier to detect an obsolete
    variable in an old rc.conf file.

 The attached patch is a working example.  If there is no strong
 objection I want to convert all of the current rc.d scripts in this
 way.  Note that this patch include a change not directly related to
 the above; handling $_override_command in run_rc_command() looks
 wrong to me.  When ${name}_program is defined and $command is not the
 former is used as the command, and if $command is defined directly it
 is used by priority.

 Comments or objections?

-- Hiroki

----Next_Part(Tue_Jul__7_07_05_45_2009_646)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="rc_set_rcvar.diff"

Index: rc.subr
===================================================================
--- rc.subr	(revision 195284)
+++ rc.subr	(working copy)
@@ -72,38 +72,64 @@
 #	functions
 #	---------

+# set_rcvar [var] [defval] [desc]
 #
-# set_rcvar base_var
-#	Set the variable name enabling a specific service.
-#	FreeBSD uses ${service}_enable, while NetBSD uses
-#	just the name of the service. For example:
-#	FreeBSD: sendmail_enable="YES"
-#	NetBSD : sendmail="YES"
-#	$1 - if $name is not the base to work of off, specify
-#	     a different one
+#	Echo or define a rc.conf(5) variable name.  Global variable
+#	$rcvars is used.
 #
+#	If no argument is specified, echo "${name}_enable".
+#
+#	If only a var is specified, echo "${var}_enable".
+#
+#	If var and defval are specified, the ${var} is defined as
+#	rc.conf(5) variable and the default value is ${defvar}.  An
+#	optional argument $desc can also be specified to add a
+#	description for that.
+#
 set_rcvar()
 {
-	if [ -z "$1" ]; then
-		base_var=${name}
-	else
-		base_var="$1"
-	fi
-
-	case ${OSTYPE} in
-	FreeBSD)
-		echo ${base_var}_enable
+	case $# in
+	0)
+		echo ${name}_enable
 		;;
-	NetBSD)
-		echo ${base_var}
+	1)
+		echo ${1}_enable
 		;;
 	*)
-		echo 'XXX'
+		debug "rcvar_define: \$$1=$2 is added" \
+		    " as a rc.conf(5) variable."
+
+		local _var
+		_var=$1
+		rcvars="${rcvars# } $_var"
+		eval ${_var}_defval=\"$2\"
+		shift 2
+		# encode multiple lines of _desc
+		for l in "$@"; do
+			eval ${_var}_desc=\"\${${_var}_desc#^^}^^$l\"
+		done
+		eval ${_var}_desc=\"\${${_var}_desc#^^}\"
 		;;
 	esac
 }

+# set_rcvar_obsolete oldvar [newvar] [msg]
+#	Define obsolete variable.
+#	Global variable $rcvars_obsolete is used.
 #
+set_rcvar_obsolete()
+{
+	local _var
+	_var=$1
+	debug "rcvar_obsolete: \$$1(old) -> \$$2(new) is defined"
+
+	rcvars_obsolete="${rcvars_obsolete# } $1"
+	eval ${1}_newvar=\"$2\"
+	shift 2
+	eval ${_var}_obsolete_msg=\"$*\"
+}
+
+#
 # force_depend script
 #	Force a service to start. Intended for use by services
 #	to resolve dependency issues. It is assumed the caller
@@ -401,6 +427,8 @@
 #	command_interpreter n	If not empty, command is interpreted, so
 #				call check_{pidfile,process}() appropriately.
 #
+#	desc		n	Description of script.
+#
 #	extra_commands	n	List of extra commands supported.
 #
 #	pidfile		n	If set, use check_pidfile $pidfile $command,
@@ -574,7 +602,7 @@
 	esac

 	eval _override_command=\$${name}_program
-	command=${command:+${_override_command:-$command}}
+	command=${command:-${_override_command}}

 	_keywords="start stop restart rcvar $extra_commands"
 	rc_pid=
@@ -778,14 +806,49 @@
 			;;

 		rcvar)
-			echo "# $name"
-			if [ -n "$rcvar" ]; then
-				if checkyesno ${rcvar}; then
-					echo "${rcvar}=YES"
-				else
-					echo "${rcvar}=NO"
+			echo -n "# $name"
+			if [ -n "$desc" ]; then
+				echo " : $desc"
+			else
+				echo ""
+			fi
+			echo "#"
+			# Get unique vars in $rcvar $rcvars
+			for _v in $rcvar $rcvars; do
+				case $v in
+				$_v\ *|\ *$_v|*\ $_v\ *) ;;
+				*)	v="${v# } $_v" ;;
+				esac
+			done
+
+			# Display variables.
+			for _v in $v; do
+				if [ -z "$_v" ]; then
+					continue
 				fi
-			fi
+
+				eval _desc=\$${_v}_desc
+				eval _defval=\$${_v}_defval
+				_h="-"
+
+				eval echo \"$_v=\\\"\$$_v\\\"\"
+				# decode multiple lines of _desc
+				while [ -n "$_desc" ]; do
+					case $_desc in
+					*^^*)
+						echo "# $_h ${_desc%%^^*}"
+						_desc=${_desc#*^^}
+						_h=" "
+						;;
+					*)
+						echo "# $_h ${_desc}"
+						break
+						;;
+					esac
+				done
+				echo "#   (default: \"$_defval\")"
+			done
+			echo ""
 			;;

 		*)
@@ -896,7 +959,8 @@

 	unset	name command command_args command_interpreter \
 		extra_commands pidfile procname \
-		rcvar required_dirs required_files required_vars
+		rcvar rcvars rcvars_obsolete required_dirs required_files \
+		required_vars
 	eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd

 	case "$_file" in
@@ -927,6 +991,7 @@
 #
 load_rc_config()
 {
+	local _name _var _defval _v _msg _new
 	_name=$1
 	if [ -z "$_name" ]; then
 		err 3 'USAGE: load_rc_config name'
@@ -953,6 +1018,36 @@
 	# Old variable names support
 	#
 	[ -n "$enable_quotas" ] && quota_enable="$enable_quotas"
+
+	# Set defaults if defined.
+	for _var in $rcvar $rcvars; do
+		_defval=`eval echo "\\\$${_var}_defval"`
+		if [ -n "$_defval" ]; then
+			eval : \${$_var:=\$${_var}_defval}
+		fi
+	done
+
+	# check obsolete rc.conf variables
+	for _var in $rcvars_obsolete; do
+		_v=`eval echo \\$$_var`
+		_msg=`eval echo \\$${_var}_obsolete_msg`
+		_new=`eval echo \\$${_var}_newvar`
+		case $_v in
+		"")
+			;;
+		*)
+			if [ -z "$_new" ]; then
+				_msg="Ignored."
+			else
+				eval $_new=\"\$$_var\"
+				if [ -z "$_msg" ]; then
+					_msg="Use \$$_new instead."
+				fi
+			fi
+			warn "\$$_var is obsolete.  $_msg"
+			;;
+		esac
+	done
 }

 #
Index: rc.d/routed
===================================================================
--- rc.d/routed	(revision 195284)
+++ rc.d/routed	(working copy)
@@ -10,13 +10,17 @@
 . /etc/rc.subr

 name="routed"
+desc="network RIP and router discovery routing daemon"
+rcvar=`set_rcvar`

-# XXX - Executable may be in a different location. The $name variable
-#       is different from the variable in rc.conf(5) so the
-#       subroutines in rc.subr won't catch it.
-#
+set_rcvar ${name}_enable NO
+set_rcvar ${name}_flags "-q" \
+    "Flags for ${name}(8)."
+set_rcvar ${name}_program "/sbin/routed" \
+    "Program name for ${name}(8)."
+set_rcvar_obsolete router_enable routed_enable
+set_rcvar_obsolete router routed_program
+set_rcvar_obsolete router_flags	routed_flags
+
 load_rc_config $name
-rcvar="router_enable"
-command="${router:-/sbin/${name}}"
-eval ${name}_flags=\"${router_flags}\"
 run_rc_command "$1"

----Next_Part(Tue_Jul__7_07_05_45_2009_646)----

----Security_Multipart0(Tue_Jul__7_07_05_45_2009_685)--
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (FreeBSD)

iEYEABECAAYFAkpSdTkACgkQTyzT2CeTzy3ZeACfTdSNAkynvEEwSXu9Y3/voeUb
gdgAoJcBSN5Pljxqo0y/SCK2AkQjUlw0
=wRkO
-----END PGP SIGNATURE-----

----Security_Multipart0(Tue_Jul__7_07_05_45_2009_685)----



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090707.070545.02771440.hrs>