#!/bin/bash
if [ $$ != 1 ]; then
	exec -a "/sbin/init" /sbin/init.debian "$@"
fi
## Ok, we are PID 1 here
: > /var/run/utmp	## reset runlevel, that's what init.c:init_main() does
#
# Univention Docker Container Mode
#  wrapper script for PID 1 (i.e. /sbin/init)
#
# Copyright 2015-2020 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

if [ ! -e /var/univention-join/joined ]; then

	## Set nameservers in UCR first, so DNS resolution still works
	## when something causes an ucr commit on /etc/resolv.conf
	if [ -z "$nameserver1" ] && [ -z "$nameserver2" ] && [ -z "$nameserver3" ]; then
		read -d'\n' nameserver1 nameserver2 nameserver3 \
			< <(sed -rn 's/^nameserver[\t ]+([^\t ]+)/\1/p' /etc/resolv.conf)
	fi

	declare -a ucrchanges
	[ -n "$nameserver1" ] && ucrchanges+=( "nameserver1=$nameserver1" )
	[ -n "$nameserver2" ] && ucrchanges+=( "nameserver2=$nameserver2" )
	[ -n "$nameserver3" ] && ucrchanges+=( "nameserver3=$nameserver3" )
	if [ -n "$ucrchanges" ]; then
		univention-config-registry set "${ucrchanges[@]}"
		unset ucrchanges
	fi

	## Next pass hostname and domainname to UCR and create a host certificate

	# set hostname, required for:
	# 1) apache requires a valid /etc/hosts entry
	# 2) SSL certificate
	# 3) ...

	test -n "$domainname" \
		|| domainname="$(hostname | sed -re 's/^[^.]+.//')"

	test -n "$domainname" \
		|| domainname="$(sed -rn 's/^domain[\t ]+([^\t ]+)/\1/p' /etc/resolv.conf)"

	hostname="$(hostname | sed -re 's/[.].*//')"

	univention-config-registry set \
		hostname="$hostname" \
		domainname="$domainname"

	# create new certificate - otherwise apache will not start
	univention-certificate new -name "$hostname.$domainname"
fi

## docker restart "$container" overwrites resolv.conf
univention-config-registry commit /etc/resolv.conf

eval "$(ucr shell hostname domainname)"

# purge fstab (unused for docker)
: > /etc/fstab

declare -a ucrchanges

# force hostname for univention system setup
ucrchanges+=( "system/setup/boot/force/fqdn=$hostname.$domainname" )

gateway=$(LANG=C ip route show | sed -rn 's/^default via ([^\t ]+).*$/\1/p')
if [ "$gateway" != "$(univention-config-registry get gateway)" ]; then
	ucrchanges+=( "gateway=$gateway" )
fi

# set DNS forwarders
[ -n "$dns_forwarder1" ] && ucrchanges+=( "dns/forwarder1=$dns_forwarder1" )
[ -n "$dns_forwarder2" ] && ucrchanges+=( "dns/forwarder2=$dns_forwarder2" )
[ -n "$dns_forwarder3" ] && ucrchanges+=( "dns/forwarder3=$dns_forwarder3" )

# Update updater identification string (VMware ==> Docker)
eval "$(ucr shell updater/identify)"
if echo "${updater_identify}" | grep -q "VMware" ; then
	ucrchanges+=( "updater/identify=${updater_identify/VMware/Docker}" )
fi

#
# Convert an IP address in dot quad format to an integer
#
decodeaddr() {
	local x
	local temp=0
	local ifs=$IFS

	IFS=.

	for x in $1; do
		temp=$(( $(( $temp << 8 )) | $x ))
	done

	echo $temp

	IFS=$ifs
}

#
# convert an integer to dot quad format
#
encodeaddr() {
	addr=$1
	local x
	local y=$(($addr & 255))

	for x in 1 2 3 ; do
		addr=$(($addr >> 8))
		y=$(($addr & 255)).$y
	done

	echo $y
}

#
# Netmask from CIDR
#
ip_netmask() {
	local vlsm=${1#*/}

	[ $vlsm -eq 0 ] && echo 0 || echo $(( -1 << $(( 32 - $vlsm )) ))
}

#
# Network address from CIDR
#
ip_network() {
	local decodedaddr=$(decodeaddr ${1%/*})
	local netmask=$(ip_netmask $1)

	echo $(encodeaddr $(($decodedaddr & $netmask)))
}

# FIXME: this only works for IPv4 subnets!

_ifconfig_eth0=$(LANG=C ifconfig eth0)
_ifconfig_eth0_ipv4=$(grep "^ *inet " <<<"$_ifconfig_eth0")
_ip_inet_addr_show_eth0=$(LANG=C ip -f inet addr show eth0)

interfaces_eth0_address=$(grep -Po '^ *inet \K\d+\.\d+\.\d+\.\d+' <<<"$_ip_inet_addr_show_eth0")
echo "interfaces/eth0/address: $interfaces_eth0_address" 

_ip_network_CIDR=$(grep -Po '^ *inet \K\d+\.\d+\.\d+\.\d+/\d+' <<<"$_ip_inet_addr_show_eth0")

interfaces_eth0_broadcast=$(grep -Po " broadcast \K\d+\.\d+\.\d+.\d+" <<<"$_ifconfig_eth0_ipv4")
echo "interfaces/eth0/broadcast: $interfaces_eth0_broadcast" 

# interfaces_eth0_netmask=$(ip_netmask "$_ip_network_CIDR")
interfaces_eth0_netmask=$(grep -Po " netmask \K\d+\.\d+\.\d+.\d+" <<<"$_ifconfig_eth0_ipv4")
echo "interfaces/eth0/netmask: $interfaces_eth0_netmask" 

interfaces_eth0_network=$(ip_network "$_ip_network_CIDR")
echo "interfaces/eth0/network: $interfaces_eth0_network" 

ucrchanges+=(
    "interfaces/eth0/address=$interfaces_eth0_address" \
    "interfaces/eth0/broadcast=$interfaces_eth0_broadcast" \
    "interfaces/eth0/netmask=$interfaces_eth0_netmask" \
    "interfaces/eth0/network=$interfaces_eth0_network" \
    "interfaces/eth0/type=static"
)

## Container ID heuristic: as generic as possible, may vary with docker versions
## Look for lines with "docker" and pick the 64-character [a-z0-9] string after that prefix
container_uuid=$(grep -oe "docker.*" /proc/self/cgroup | head -1 | sed -r 's|docker.*([a-z0-9]{64}).*|\1|')
if [ -n "$container_uuid" ]; then
	ucrchanges+=( "docker/container/uuid=$container_uuid" )
else
	echo "ERROR: Container UUID detection failed" >&2
	previous_container_uuid=$(univention-config-registry get docker/container/uuid)
	if [ -n "$previous_container_uuid" ]; then
		## No clue what this might be good for, but let's backup
		## And unset the "we are in this container" flag
		echo "WARNING: Found UCR docker/container/uuid=$previous_container_uuid" >&2
		echo "WARNING: Saving as docker/container/previousuuid and unsetting it" >&2
		ucrchanges+=( "docker/container/previousuuid=$previous_container_uuid" )
		univention-config-registry unset docker/container/uuid 
	fi
fi

# commit UCR changes
[ -n "$ucrchanges" ] && univention-config-registry set "${ucrchanges[@]}"

# extract root password from environment variable, store it to a file and remove it from environment
if [ -n "$rootpwd" ]; then
	touch /var/lib/univention-ldap/root.secret
	chown root:root /var/lib/univention-ldap/root.secret
	chmod 600 /var/lib/univention-ldap/root.secret
	echo -n "$rootpwd" > /var/lib/univention-ldap/root.secret
	echo "root:$rootpwd" | chpasswd
	unset rootpwd
fi

## cleanup the environment
unset ucrchanges hostname domainname gateway \
	nameserver1 nameserver2 nameserver3 \
	dns_forwarder1 dns_forwarder2 dns_forwarder3 \
	updater_identify container_uuid previous_container_uuid \
	_ifconfig_eth0 _ifconfig_eth0_ipv4 _ip_inet_addr_show_eth0 \
	_ip_network_CIDR decodeaddr encodeaddr ip_netmask ip_network

run-parts --verbose /etc/univention/docker/preinit.d

## Allow the container to override what is called as PID 1 via UCR
declare -a docker_container_pid1
docker_container_pid1=($(univention-config-registry get docker/container/pid1))
if [ -n "$docker_container_pid1" ]; then
	echo "INFO: Found docker/container/pid1 in UCR"
	pid1_process="${docker_container_pid1[0]}"
	## Save the original pid1 argv specified at creation of container
	## Pass this in process environment as docker_cmd_pid1
	docker_cmd_pid1=("$0" "$@")
	## Replace argv as specified by the container
	set -- "${docker_container_pid1[@]}"
	unset docker_container_pid1
	shift	## shift away $1, gets passed as new $0
	## And pass control
	echo "INFO: Switching to container defined $pid1_process $@"
	exec "$pid1_process" "$@"
	exit $?	## never reached
fi

## Default is to continue booting the app
pid1_process="/sbin/init.debian"
## But if the caller specifies any other executable as $1 then run that instead 
if [ "$#" -gt 0 ]; then
	if [ "$1" = "/sbin/init" ]; then
		## In this case we would recurse, so ignore.
		shift
	elif [ -x "$1" ]; then
		pid1_process="$1"
		shift
		echo "INFO: Switching to custom $pid1_process $@"
		exec "$pid1_process" "$@"
	fi
fi

## Pass arguments, e.g. the caller may specify runlevel 1
echo "INFO: Switching to standard $pid1_process $@"
exec -a "/sbin/init" "$pid1_process" "$@"
