#!/bin/bash

if [ "$UID" != "0" ]; then
	echo Need to be root.
	exit 1
fi

declare -A results_runlevel
declare -A results_priority

usage() {
cat << EOF
usage: systemd-sysv-convert [-h] [--save] [--show] [--apply]
                            SERVICE [SERVICE ...]
EOF
}

help() {
usage
cat << EOF
Save and Restore SysV Service Runlevel Information

positional arguments:
  SERVICE	Service names

optional arguments:
  -h, --help	show this help message and exit
  --save	Save SysV runlevel information for one or more services
  --show	Show saved SysV runlevel information for one or more services
  --apply 	Apply saved SysV runlevel information for one or more services
  		to systemd counterparts
EOF
}

find_service() {
local service
local runlevel
declare -i priority
service=$1
runlevel=$2
priority=-1
for l in $(ls /etc/rc.d/rc$runlevel.d/) ; do
	initscript=$(basename $l)
	if [ ${initscript:0:1} != "S" -o ${initscript:3} != "$service" ]; then
		continue
	fi
	if [ ${initscript:1:2} -ge 0 -a ${initscript:1:2} -le 99 -a ${initscript:1:2} -ge $priority ]; then
		if [ ${initscript:1:1} == 0 ]; then
			priority=${initscript:2:1}
		else
			priority=${initscript:1:2}
		fi
	fi
done
if [ $priority -ge 0 ]; then
	return $priority
else
	return 255
fi
}

lookup_database() {
local services
local service
local service_file
local runlevel
local priority
local -i k
declare -a parsed
services=$@
k=0
results_runlevel=()
results_priority=()
while read line ; do
		k+=1
		parsed=($line)
		service=${parsed[0]}
		runlevel=${parsed[1]}
		priority=${parsed[2]}
		if [ $runlevel -lt 2 -o $runlevel -gt 5 ]; then
			echo "Runlevel out of bounds in database line $k. Ignoring" >/dev/stderr
			continue
		fi
		if [ $priority -lt 0 -o $priority -gt 99 ]; then
			echo "Priority out of bounds in database line $k. Ignoring" >/dev/stderr
			continue
		fi
			
		declare -i found
		found=0
		for s in $services ; do
			if [ $s == $service ]; then
				found=1
				continue
			fi
		done
		if [ $found -eq 0 ]; then
			continue
		fi
		results_runlevel[$service]+=" $runlevel"
		results_priority[$service]+=" $priority"
done < /var/lib/systemd/sysv-convert/database
}

declare -i fail=0
case "$1" in 
	-h|--help) 
		help
		exit 0
		;;
	--save)
		shift
		for service in $@ ; do
			if [ ! -r "/etc/init.d/$service" ]; then
				echo "SysV service $service does not exist" >/dev/stderr
				let fail++
				continue
			fi
			for runlevel in 2 3 4 5; do
				find_service $service $runlevel
				priority=$?
				if [ $priority -lt 255 ]; then
					echo "$service	$runlevel	$priority"
				fi
			done >>/var/lib/systemd/sysv-convert/database
		done
		;;
	--show)
		shift
		services=$@
		lookup_database $services
		for service in $services; do
  			if [ -z "${results_runlevel[$service]}" ]; then
				echo No information found about service $service found. >/dev/stderr
				let fail++
				continue
			fi
			declare -i count
			count=0
			priority=(${results_priority[$service]})
			for runlevel in ${results_runlevel[$service]}; do
				echo SysV service $service enabled in runlevel $runlevel at priority ${priority[$count]}
				count+=1
			done
		done
		;;
	--apply)
		shift
		services=$@
		for service in $services; do
			if [ ! -f "/lib/systemd/system/$service.service" -a ! -f "/usr/lib/systemd/system/$service.service" ]; then
				echo systemd service $service.service does not exist. >/dev/stderr
				exit 1
			fi
		done
		lookup_database $services
		for service in $services; do
			[ -f "/lib/systemd/system/$service.service" ] && service_file="/lib/systemd/system/$service.service" 
			[ -f "/usr/lib/systemd/system/$service.service" ] && service_file="/usr/lib/systemd/system/$service.service" 

			# If $service is not present in the database,
			# then it simply means that the sysv init
			# service was not enabled at all.
			for runlevel in ${results_runlevel[$service]}; do
				echo ln -sf $service_file /etc/systemd/system/runlevel$runlevel.target.wants/$service.service >/dev/stderr
				mkdir -p "/etc/systemd/system/runlevel$runlevel.target.wants"
				/bin/ln -sf $service_file /etc/systemd/system/runlevel$runlevel.target.wants/$service.service 
			done

		done
		;;
	*) 	usage
		let fail=2
		;;
esac

exit $fail