#!/bin/sh
# Set the current hostname if empty, and create /etc/hostname if missing.
set -e

. /usr/share/debconf/confmodule

db_capb backup

hostnamefile=/etc/hostname

currname=`uname -n`
defaultname=ubuntu

log() {
    echo "base-config: $@" >&2
}

info() {
    log "info: $@"
}

set_default_from_dns() {
	# The interface testing work best if the loopback device is skipped.
	# Sorted order to test eth1 before eth0, so that the setting in eth0
	# is the one that take effect
	interfaces=`netstat -i | tail -n +3 | awk '{print $1}' | grep -v '^lo$' | sort -r`
	for interface in $interfaces; do
		ip=`/sbin/ifconfig $interface 2>&1 | grep 'inet addr:' | tr a-zA-Z: " " | awk '{print $1}'`
		if [ "$ip" ]; then
		    dnsname=`getent hosts $ip | awk '{ print $2 }'`
		    if [ "$dnsname" ]; then
				db_set base-config/get-hostname "$dnsname"
				priority=medium
		    else
				info "Unable to find IP address '$ip' in DNS."
		    fi
		else
			info "Unable to find IP address on if '$interface'"
		fi
	done
}

# Check the hostname for RFC 1123 compliance.  2 < length of each part
# < 63, only characters 'a-z.-', and no dash at the start or at the
# end.
is_hostname_bad() {
	filtered=`echo -n "$1" | sed 's/[^A-Za-z0-9.-]//'`
	if [ "$1" != "$filtered" ]; then
	    return 0;
	fi
	for part in `echo -n "$1" | tr . " "`; do
	    length=`echo -n "$part" |wc -c`
	    if [ 2 -gt "$length" ] || [ "$length" -ge 63 ]; then
		return 0
	    fi
	    if echo -n "$part" | grep -E -q "^-|-$"; then
		return 0
	    fi
	done
	return 1
}

if [ -z "$currname" ] || [ "$currname" = localhost ]; then
	# Check IP addresses of interfaces, try to look up
	# using DNS, use that name as default hostname, and
	# ask medium priority question if there is a
	# default, and high priority question if the default
	# is empty.
	priority=high

	# Make sure there is some good default.  Only change
	# the default value, to make it possible to override
	# this using the debconf database.
	db_set base-config/get-hostname $defaultname
	set_default_from_dns
else
	# Ask at medium priority so the menu item does something if
	# manaully selected.
	priority=medium
	db_set base-config/get-hostname $currname
fi

# Prompt for the hostname, using the current name, if any, as the default.
hostname=
LOOPCOUNT=2
while [ -z "$hostname" ]; do
	db_input "$priority" base-config/get-hostname || break
	if ! db_go; then
		db_fset base-config/get-hostname seen false
		exit 30 # back to menu
	fi
	db_fset base-config/get-hostname seen false
	db_get base-config/get-hostname
	hostname="$RET"

	if is_hostname_bad "$hostname"; then
		db_subst base-config/invalid-hostname HOSTNAME "$hostname"
		db_input critical base-config/invalid-hostname || [ $? -eq 30 ]
		if ! db_go; then
			db_fset base-config/invalid-hostname seen false
			exit 30 # back to menu TODO should use state machine
		fi
		db_fset base-config/invalid-hostname seen false
		hostname=
	fi

	# Only loop LOOPCOUNT times.
	LOOPCOUNT=`expr $LOOPCOUNT - 1 || true`
	if [ "0" -ge "$LOOPCOUNT" ]; then
		if [ -z "$hostname" ]; then
			hostname="$defaultname"
			info "Terminating loop, setting hostname to '$hostname'"
		fi
	fi
done

# If the user failed to enter a hostname, then use the current name.
if [ -z "$hostname" ]; then
	if [ -z "$currname" ]; then
		hostname=$defaultname
	else
		hostname=$currname
	fi
fi

# Set hostname.
if [ "$hostname" != "$currname" ]; then
	echo "$hostname" > "$hostnamefile"
	hostname "$hostname"
fi
