#!/bin/sh
# vim:ts=4:sts=4:fdm=marker:cms=\ #\ %s
#
# rlinetd's version of update-inetd.
# Robert Luberda <robert@debian.org>, 2001, 2009, 2011, 2013
#

set -e

PATH=/usr/sbin:$PATH

# global variables
g_version='#VERSION#'
g_rlinconfdir="/etc/rlinetd.d"
g_ucfdir="/var/lib/rlinetd/ucf"

g_debug=0
g_need_reload=0
g_line=""
g_mode=""

# error - prints error message and exits the program  # {{{
error()
{
	msg="$1"
	echo "update-inetd: $msg" >&2
	debug "Program arguments: --$g_mode \"$line\""
	exit 1
} # }}}

# debug - prints debug info # {{{
debug()
{
	[ $g_debug -eq 1 ] || return 0
	msg="$1"
	echo "$msg"
} # }}}

# check_debconf - ugly hack to check if debconf is still running # {{{
check_debconf()
{
  conffile="$1"
  if [ "$DEBIAN_HAS_FRONTEND" ] &&  [ -e /usr/share/debconf/confmodule ] && [ $(id -u) = 0 ]; then
	status=0
	tmseconds=15

	debug "Checking (for up to $tmseconds seconds) if debconf is running"
	timeout -k 1 "$tmseconds" /bin/sh -c '. /usr/share/debconf/confmodule; db_version > /dev/null' \
		|| status="$?"
	debug "debconf check status: $status"

	case "$status" in
		0) # OK, debconf is running
			;;
		124|137) # debconf hung
			error \
"The \"${DPKG_MAINTSCRIPT_PACKAGE:-unknown}\" package stops debconf before calling update-inetd!
 This prevents rlinetd's version of update-inetd from updating file ${conffile}.
 Please report this as a bug in package \"${DPKG_MAINTSCRIPT_PACKAGE:-rlinetd}\".

 Note: update-inetd was called with the following arguments:
 $0 --$g_mode \"$line\"
"
			;;
		*) # something strange has just happend
			error \
"internal error: cannot check debconf, timeout command failed with $status
 Please report this as a bug in package rlinetd.
"
			;;
		esac
	fi
} # }}}

# ucf_ack - asks user a question using ucf # {{{
ucf_ask()
{
	cachedfile="$1"
	conffile="$2"

	if [ ! -e "$conffile" ] || ! cmp -s "$cachedfile" "$conffile"; then
		check_debconf "$conffile"
		debug "Running ucf on $cachedfile and $conffile"
		ucf --three-way --debconf-ok "$cachedfile" "$conffile"
		ucfr "rlinetd" "$conffile"
		g_need_reload=1
	else
		debug "$cachedfile and $conffile identical, skipping ucf"
	fi

} # }}}

# ucf_purge - purges ucf configuration # {{{
ucf_purge()
{
	conffile="$1"

	debug "Removing $conffile from ucf"
	ucf --purge "$conffile"
    ucfr --purge "rlinetd" "$conffile" || true
	g_need_reload=1
} # }}}

# enable_disable_util - enables or disables an entry # {{{
enable_disable_util()
{
	cachedfile="$1"
	conffile="$2"
	enable="$3"

	debug "Setting enable to $3 in $cachedfile"

	sed -e "s/^\([ \t]*enabled[ \t][ \t]*\).*$/\1$enable;/" < "$cachedfile" >  "$cachedfile.tmp"
	mv "$cachedfile.tmp"  "$cachedfile"


	ucf_ask "$cachedfile" "$conffile"

} # }}}

# enable - calls enable_disable_util to enable an entry # {{{
enable()
{
	enable_disable_util "$1" "$2" "yes"
} # }}}

# disable - calls enable_disable_util to disable an entry # {{{
disable()
{
	enable_disable_util "$1" "$2" "no"
} # }}}

# remove - removes an entry # {{{
remove()
{
	cachedfile="$1"
	conffile="$2"

	debug "Removing $cachedfile, $conffile"

	rm -f "$cachedfile" "$conffile"
	ucf_purge "$conffile"

} # }}}

# remove_regexp - removes an entry based on regexp # {{{
remove_regexp()
{
	regexp="$1"
	regexp="^# Generated from: ${regexp#^}"
	debug "Searching for files matching \"$regexp\""
	files=`cd $g_ucfdir && egrep -l "$regexp" -- *`
	[ "$files" ] || { debug "None found"; return 1; }
	debug "Found: $files"
	for basefile in $files; do
		remove "$g_ucfdir/$basefile" "$g_rlinconfdir/$basefile"
	done
	return 0

} # }}}

# add - adds a new entry # {{{
add()
{
	line="$1"
	files=`inetd2rlinetd --force-overwrite --print-file-names --add-from-comment -l "$line" "$g_ucfdir"`
	debug "Converted $line saved in $files"
	[ -z "$file" ] || return 0

	for file in $files; do
		file="${file##*/}"
		case "$file" in
			*_udp)
				basename="${file%_*}"
				if [ ! -e "$g_rlinconfdir/$file" ] &&
					[ ! -e "$g_ucfdir/$basename" ]  &&
					[ -f "$g_rlinconfdir/$basename" ]; then
					# rename previous versions of file
					debug "Renaming $g_rlinconfdir/$basename to $g_rlinconfdir/$file"
					mv -f "$g_rlinconfdir/$basename" "$g_rlinconfdir/$file"
				fi
				;;
		esac

		ucf_ask "$g_ucfdir/$file" "$g_rlinconfdir/$file"
	done
} # }}}

# operation  - calls add, remove, enable or disable # {{{
operation()
{
	operation="$1"
	line="$2"

	[ -n "$line" ] || error "--$operation requires argument"

	debug "Running $operation for $line"

	# add
	if [ "$operation" = "add" ]; then
		add "$line"
		return 0
	fi

	# disable, enable: line can be comma separated list of values
	# remove: treat line as is.
	service=""
	found=0
	while [ "$line" != "$service" ] ; do
		if [ "$operation" = "remove" ] ; then
			service="$line"
		else
			service="${line%,*}"
			line="${line#*,}"
		fi

		for proto in "" _udp; do
			basefile="${service}${proto}"
			file="$g_ucfdir/$basefile"
			debug "Checking for file $file"
			if [ -e "$file" ]; then
				found=1
				"$operation" "$file" "$g_rlinconfdir/$basefile"
			fi
		done

		if [ $found -eq 0 ] && [ "$operation" = "remove" ]; then
			! remove_regexp "$line" || found=1
		fi

		if [ $found -eq 0 ]; then
			echo "Cannot find cached rlinetd's config files for service $service, ignoring $operation request" >&2;
		fi
	done
} # }}}

# reload_rlinetd - reloads rlinetd daemon # {{{
reload_rlinetd()
{
	if [ "$g_need_reload" -eq 0 ]; then
		debug "Configuration not changed, not reloading rlinetd"
		return 0
	fi

	debug "Reloading rlinetd config files"

    killall -HUP rlinetd || true
} # }}}


# MAIN FUNCTION # {{{

# parse arguments # {{{
ignore_next=0
for i in "$@" ; do
    # note: the original update-inetd allows things  like "--add --comment-chars XX LINE_TO_ADD"
    if [ "$ignore_next" -eq 1 ] ; then
		ignore_next=0
		continue
	fi

	case "$i" in
		"--add"|"--remove"|"--disable"|"--enable")
			[ -z "$mode" ] || error "$i conflicts with --$mode"
			g_mode="$i"
			g_mode="${g_mode#--}"
			;;
		"--debug")
			g_debug=1
			;;
		"--version")
			echo "rlinetd's version of update-inetd"
			echo "version: $g_version"
			exit 0
			;;
		"--multi"|"--verbose")
			# ignore
			;;
		"--file"|"--group"|"--comment-chars")
			ignore_next=1
			;;
		"--*")
			echo "Unknown option \`$i\' passed to $0, ignoring" >&2;
			;;
		*)	if [ -n "$g_mode" ] ; then
				[ -z "$g_line" ] || error "--$g_mode requires only one argument"
				g_line="$i"
			fi
			;;
	esac
done # }}}

# do our job
[ -z "$g_mode" ] || operation "$g_mode" "$g_line"

# reload configuration
reload_rlinetd

# execute real update-inetd
real_upd=`dpkg-divert --truename /usr/sbin/update-inetd`
real_conf='/etc/inetd.conf'
[ -x "$real_upd" ] && [ -f "$real_conf" ] && exec "$real_upd" "$@"

exit 0
 # }}}
