#!/bin/bash
# Need bash because of "${FOO/bar}" and "for (( ))"

MYNAME="${0##*/}"

DEFAULT_TIMEOUT_SECONDS=300

report_err() { echo "ifupdown: ${MYNAME}${MODE:+ $MODE}: Error: $*" >&2 ; }

is_whitespace_free()
{
	local EXPANDED="$(echo $1)"
	[ "$1" = "${EXPANDED/ }" ]
}

is_numeral()
{
	[ "$1" ] || return 1
	[ "$1" = "${1/[^0-9]}" ]
}

[ "$MODE" ] || { report_err "MODE missing from env" ; exit 1 ; }

[ "$IFACE" ] || { report_err "IFACE missing from env" ; exit 1 ; }
is_whitespace_free "$IFACE" || { report_err "Interface name contains whitespace" ; exit 1 ; }

TIMEOUT_SECONDS="$DEFAULT_TIMEOUT_SECONDS"
if [ "$IF_UP_TIMEOUT" ] ; then
	is_whitespace_free "$IF_UP_TIMEOUT" || { report_err "Timeout argument contains whitespace" ; exit 1 ; }
	case "$IF_UP_TIMEOUT" in
	none|infinity)
		:
		;;
	*)
		is_numeral "$IF_UP_TIMEOUT" || { report_err "Timeout argument is not a legal value" ; exit 1 ; }
		TIMEOUT_SECONDS="$(( $IF_UP_TIMEOUT ))"
		[ "$TIMEOUT_SECONDS" -gt 0 ] || { report_err "Timeout of zero not allowed" ; exit 1 ; }
		;;
	esac
fi

DHCP_CLIENT=""
if [ "$IF_DHCP_CLIENT" ] ; then
	is_whitespace_free "$IF_DHCP_CLIENT" || { report_err "DHCP client argument contains whitespace" ; exit 1 ; }
	DHCP_CLIENT="$IF_DHCP_CLIENT"
	[ -x "/sbin/$DHCP_CLIENT" ] || { report_err "No executable DHCP client /sbin/$DHCP_CLIENT" ; exit 1 ; }
else
	for CLNT in dhclient3 dhclient pump udhcpc dhcpcd ; do
		[ -x "/sbin/$CLNT" ] || continue
		DHCP_CLIENT="$CLNT"
		break
	done
fi
[ "$DHCP_CLIENT" ] || { report_err "No DHCP client found" ; exit 1 ; }

stop_dhcp_client()
{
	case "$DHCP_CLIENT" in
		dhclient3) [ -s  /var/run/dhclient."$IFACE".pid ] && dhclient3 -r -pf /var/run/dhclient."$IFACE".pid -lf /var/run/dhclient."$IFACE".leases "$IFACE" ;;
		dhclient) [ -s  /var/run/dhclient."$IFACE".pid ] && kill -TERM "$(cat /var/run/dhclient."$IFACE".pid)" ;;
		pump) pump -i "$IFACE" -r ;;
		udhcpc) [ -s  /var/run/udhcpc."$IFACE".pid ] && kill -TERM "$(cat /var/run/udhcpc."$IFACE".pid)" ;;
		dhcpcd) dhcpcd -k "$IFACE" ;;
		*) report_err "Unknown DHCP client" ; exit 1 ;;
	esac
}

case "$MODE" in
start)
	start_dhcp_client() {
		case "$DHCP_CLIENT" in
			dhclient3) /sbin/dhclient3 -pf /var/run/dhclient."$IFACE".pid -lf /var/run/dhclient."$IFACE".leases "$IFACE" ;;
			dhclient) /sbin/dhclient -pf /var/run/dhclient."$IFACE".pid -lf /var/run/dhclient."$IFACE".leases "$IFACE" ;;
			pump) /sbin/pump -i "$IFACE" ${IF_HOSTNAME:+-h "$IF_HOSTNAME"} ${IF_LEASEHOURS:+-l "$IF_LEASEHOURS"} ;;
			udhcpc) /sbin/udhcpc -n -p /var/run/udhcpc."$IFACE".pid -i "$IFACE" ${IF_HOSTNAME:+-H "$IF_HOSTNAME"} ${IF_CLIENTID:+-c "$IF_CLIENTID"} ;;
			dhcpcd) /sbin/dhcpcd ${IF_HOSTNAME:+-h "$IF_HOSTNAME"} ${IF_VENDOR:+-i "$IF_VENDOR"} ${IF_CLIENTID:+-I "$IF_CLIENTID"} ${IF_LEASETIME:+-l "$IF_LEASETIME"} "$IFACE" ;;
			*) report_err "Unknown DHCP client" ; exit 1 ;;
		esac
	}
	case "$IF_UP_TIMEOUT" in
	none)
		start_dhcp_client &
		exit 0
		;;
	infinity)
		start_dhcp_client
		exit
		;;
	*)
		stop_child_and_exit()
		{
			[ "$!" ] && kill -TERM "-$!"  # Kill child's process group
			stop_dhcp_client
			exit 1
		}
		trap stop_child_and_exit INT
		set -m   # Run children in own process group
		start_dhcp_client &
		[ "$!" ] || { report_err "Failed to start DHCP client" ; exit 1 ; }
		ps --no-headers "$!" > /dev/null || exit 0
		for (( T=$TIMEOUT_SECONDS ; T > 0 ; T-- )) ; do
			sleep 1
			ps --no-headers "$!" > /dev/null || exit 0
		done
		report_err "Timed out"
		stop_child_and_exit
		;;
	esac
	;;
stop)
	stop_dhcp_client
	ifconfig "$IFACE" down
	exit 0
	;;
*)
	report_err "Mode not recognized"
	exit 1
	;;
esac
