#!/bin/bash

set -e

PATH=/bin:/usr/bin:/sbin:/usr/sbin

PKGDIR="/opt/isu"
RUNDIR="/run/isu"

# Public key will be checked only if below variable is set
#PUBKEY="/path/to/publickey.pem"

if [ "$PUBKEY" -a ! -r "$PUBKEY" ]; then
	echo "Public key specified but not readable: $PUBKEY"
	exit 1
fi

if [ -z "$1" ]; then
	echo "Please specify unitdir(s) as decribed in systemd.generator (1 or 3 arguments)"
	exit 1
fi
UNITDIR="$1"

MY_NAME=$(basename "$0")

if [ "$MY_NAME" = "isu-system-generator" ]; then
	ISU_SERVICES_DIR=system-services
	SERVICES_DIR=/usr/lib/systemd/system
elif [ "$MY_NAME" = "isu-user-generator" ]; then
	ISU_SERVICES_DIR=user-services
	SERVICES_DIR=/usr/lib/systemd/user
else
	echo "This generator must be named isu-system-generator or isu-user-generator"
	exit 1
fi

install_units()
{
	local srv_path="$1"
	local isu_pkg_name="$2"
	local srv_fname=$(basename $srv_path)
	local new_srv_path="$UNITDIR/$srv_fname"

	rm -f "${new_srv_path}" "${new_srv_path}.tmp"

	# 1st step: copy ISU package's .service file to generator dir and original .service under diffeerent name
	# (nonisu-.. -> different name is needed as original .service will be masked by our new service from ISU)
	cat "$srv_path" > "$new_srv_path".tmp || return 1
	cp -a "$SERVICES_DIR/${srv_fname}" "$UNITDIR/nonisu-${srv_fname}" || return 1

	# 2nd step: generate mount unit for ISU image and extend the service file to use it
	local mount_unit="run-isu-${isu_pkg_name}-rootfs.mount"
	cat <<EOF >> "$UNITDIR/$mount_unit" || return 1
# This unit file has been automatically generated by isu-generator.
#
# Do not edit this file as it will be re-created at next generator run.

[Unit]
DefaultDependencies=no

[Mount]
What=${PKGDIR}/${isu_pkg_name}/rootfs.img
Where=${RUNDIR}/${isu_pkg_name}/rootfs
EOF

	cat <<EOF >> "$new_srv_path".tmp || return 1

[Unit]
After=${mount_unit}
BindsTo=${mount_unit}
OnFailure=nonisu-${srv_fname}
Conflicts=nonisu-${srv_fname}
EOF

	# 3rd step: make new unit visible
	mv "${new_srv_path}.tmp" "${new_srv_path}" || return 1

	return 0
}

isu_prepare()
{
	isu_pkg_dir="$1"
	isu_pkg_name=$(basename "$isu_pkg_dir")

	if ! compgen -G "${isu_pkg_dir}/${ISU_SERVICES_DIR}/*.service"; then
		echo "There are no $SYSTEMD_SCOPE services in $isu_pkg_dir"
		return 0
	fi

	# verify signature and checksum before considering ISU package for application on the system
	cksum_sign_path="$isu_pkg_dir/checksum.sha256.sign"
	cksum_path="${cksum_sign_path%.sign}"
	if [ "$PUBKEY" ]; then
		if ! openssl dgst -sha256 -verify "$PUBKEY" -signature "$cksum_sign_path" "$cksum_path"; then
			echo "Public key verification failed for $cksum_path"
			return 1
		fi
		echo "Public key verification succeeded for $isu_pkg_dir"
	fi

	if [  -s "$cksum_path" ]; then
		pushd "$isu_pkg_dir"
		if ! sha256sum -c --status "$cksum_path"; then
			popd
			echo "Checksum verification failed for $isu_pkg_dir - skipping ISU package"
			return 1
		fi
		popd
	else
		echo "Missing or broken checksum file: $cksum_path - skipping ISU package"
		return 1
	fi


	for srv_path in "$isu_pkg_dir"/${ISU_SERVICES_DIR}/*.service; do

		if ! test -r "$srv_path"; then continue; fi

		if ! mkdir -p "$RUNDIR/$isu_pkg_name/rootfs"; then
			echo "Unable to create directory to mount $isu_pkg_dir's rootfs - skipping ISU package"
			continue
		fi
		install_units "$srv_path" "$isu_pkg_name"

	done
}

# assume isu packages are extracted
for i in "$PKGDIR"/*; do
	if ! test -d "$i" -a -r "$i"/rootfs.img -a -r "$i"/isu.cfg; then continue; fi
	#service_file=$(sed -ne 's,service_file=,, p' < "$i"/isu.info)

	isu_prepare "$i"
done
