Subject: Re: admin script for ipfilter
To: Geert Hendrickx <ghen@NetBSD.org>
From: Darren Reed <darrenr@NetBSD.org>
List: tech-userlevel
Date: 12/27/2006 15:32:42
--6c2NcOVqGQ03X4Wi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Wed, Dec 27, 2006 at 11:16:50AM +0100, Geert Hendrickx wrote:
> On Wed, Dec 27, 2006 at 12:04:47AM +0000, Darren Reed wrote:
> > So...the attached script, "ipfadm", I'm curious for feedback on.
> > 
> > The idea is to do "ipfadm enable ipfilter" or "ipfadm disable ipfilter"
> > and it updates the relevant rc.d config file for you.
> > 
> > Ok, not catchy...
> > 
> > What I hope is of more interest is doing "ipfadm ipfilter status",
> > where it will tell you if it is enabled, disabled, enabled but no rules,
> > or disabled but rules loaded.
> > 
> > Feedback welcome.
> 
> Why not generalise this to "rc.dadmin enable/disable/status XXX" to toggle
> arbitrary startup scripts?  You could still add ipfilter-specific hooks (as
> well as for other rc.d scripts) for the "status" command.

So I went ahead and hacked on something to work vaguely in this
fashion... and it does so long as the last line of /etc/rc.d scripts
can be "skipped".

But in doing it, it also raised some questions:
- do all scripts support "start" ?
- do all scripts support "stop" ?
- do all scripts support "restart" ?
(ie. can you have a script that only does "start" or similar)

The requirements for change to support the rcadmin script are:
X_toggle=Y
    where "Y" is the variable in rc.conf/wherever that you need to
    change from "YES" to "NO to enable/disable.  There's a problem
    here if there' every more than one Y for X.
X_rcstart() { ... }
    returns a string to be output, appened to the status message

For /etc/rc.d/ipfilter, these became:
ipfilter_toggle=ipfilter
ipfilter_rcstatus() {   
        running=`ipf -V 2>/dev/null|sed -ne 's/Running: \(.*\)/\1/p'`
        if [ -z "$running" ] ; then
                rules=
                emsg="-not-in-kernel"
                dmsg=
        else
                case $running in
                yes)
                        emsg=
                        dmsg="-rules-loaded"
                        rules=`ipfstat -io 2>/dev/null`
                        if [ -z "$rules" ] ; then
                                rules=`ipfstat -aio 2>/dev/null`
                                if [ -z "$rules" ] ; then
                                        emsg="-no-rules"
                                        dmsg=
                                fi
                        fi
                        ;;
                no)
                        rules=
                        emsg="-not-running"
                        dmsg=
                        ;;
                esac
        fi
        return "${rules}"
}

Note that the _rcstatus() function is careful to not make any
inquiries about the rc.d view of whether or not it is enabled.

Darren

--6c2NcOVqGQ03X4Wi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=rcadmin

#!/bin/sh
#
RCD=/etc/rc.conf.d
prog=$0

if [ $# -lt 1 ] ; then
	echo "$prog <subsystem> <command>"
	exit 1
fi

sub=$1
shift
cmd=$1
while [ $# -gt 0 ] ; do
	shift
done

. /etc/rc.d/${sub}

eval evar=\$`echo ${sub}_toggle`

usage() {
	echo -n "rcadmin ${sub} <enable|disable|status"
	if [ -n "$start_cmd" ] ; then
		echo -n "|start"
	fi
	if [ -n "$stop_cmd" ] ; then
		echo -n "|stop"
	fi
	if [ -n "$restart_cmd" ] ; then
		echo -n "|restart"
	fi
	for i in $extra_commands; do
		if [ "$i" != "status" ] ; then
			echo -n "|$i"
		fi
	done
	echo ">"
	exit 1
}

enable() {
	old=${RCD}/${sub}.old
	new=${RCD}/${sub}
	mkdir ${RCD}/${sub}.d
	if [ $? -eq 0 ] ; then
		if [ -f ${RCD}/${sub} ] ; then
			cp ${RCD}/${sub} ${RCD}/${sub}.old
			sed -e "s/^${evar} *\=.*/${evar}\=YES/" ${old} > ${new}
			/bin/rm ${old}
		else
			echo "${evar}=YES" > ${RCD}/${sub}
			chmod go-wx ${RCD}/${sub}
		fi
		rmdir ${RCD}/${sub}.d
	fi
}

disable() {
	old=${RCD}/${sub}.old
	new=${RCD}/${sub}
	mkdir ${RCD}/${sub}.d
	if [ $? -eq 0 ] ; then
		if [ -f ${RCD}/${sub} ] ; then
			cp ${RCD}/${sub} ${RCD}/${sub}.old
			sed -e "s/^${evar} *\=.*/${evar}\=NO/" ${old} > ${new}
			/bin/rm ${old}
		else
			echo "$evar=NO" > ${RCD}/${sub}
			chmod go-wx ${RCD}/${sub}
		fi
		rmdir ${RCD}/${sub}.d
	fi
}

status() {
	active=`/etc/rc.d/${sub} rcvar|sed -ne "s/^$""${evar}\=\(.*\)$/\1/p"`
	case $active in
	NO)
		return 0
		;;
	YES)
		return 1
		;;
	esac
	return 2
}

rcstatus() {
	dmsg="-but-running"
	emsg="-not-running"
	umsg="-state-running"

	eval x=\$`echo ${sub}_running`
	echo -n "${sub} "
	status ${evar}
	case $? in
	0)
		if [ -n "$x" ] ; then
			echo "disabled${dmsg}"
		else
			echo "disabled"
		fi
		;;
	1)
		if [ -n "$x" ] ; then
			echo "enabled"
		else
			echo "enabled${emsg}"
		fi
		;;
	2)
		if [ -n "$x" ] ; then
			echo "unknown${umsg}"
		else
			echo "unknown-state"
		fi
		;;
	esac
}

case ${cmd} in
status)
	rcstatus
	;;
start)
	if [ -n "$start_cmd" ] ; then
		/etc/rc.d/$1 start
	else
		echo "${prog} ${sub} ${cmd} - not supported"
		exit 1
	fi
	;;
stop)
	if [ -n "$stop_cmd" ] ; then
		/etc/rc.d/$1 stop
	else
		echo "${prog} ${sub} ${cmd} - not supported"
		exit 1
	fi
	;;
enable)
	enable
	;;
disable)
	disable
	;;
reload)
	if [ -n "$reload_cmd" ] ; then
		/etc/rc.d/$1 reload
	else
		echo "${prog} ${sub} ${cmd} - not supported"
		exit 1
	fi
	;;
restart)
	if [ -n "$restart_cmd" ] ; then
		/etc/rc.d/$1 restart
	else
		echo "${prog} ${sub} ${cmd} - not supported"
		exit 1
	fi
	;;
*)
	usage
esac
exit 0

--6c2NcOVqGQ03X4Wi--