#!/bin/sh
#
# runit wrapper script which populates runtime services directory before
# invoking runit.
#
set -eu

# This directory contains the static OS provided services.
SV_DIR="${SV_DIR:-/etc/sv}"

# This directory is populated with dynamic services by various software
# components. Creating a new service needs to happen atomically otherwise runit
# gets confused. To avoid this, the dynamic services are fully created in this
# staging area before creating the link in the RUN_SV_DIR structure.
STAGE_SV_DIR="${STAGE_SV_DIR:-/var/run/service}"

# Directory against which we execute runit (contains the reunion of static and
# dynamic services).
RUN_SV_DIR="${RUN_SV_DIR:-/var/service}"

# For testing
RUN_SV_DIR_BIN="${RUN_SV_DIR_BIN:-/usr/bin/runsvdir}"

#
# Creates a symlink structure of existing entries in a directory.
#
# Arguments:
#   1 - The directory in which all files are the target of the symlinks.
#   2 - The directory where the symlinks structure is created.
#
ln_all() {
	_from="$1"
	_to="$2"

	[ -d "$_from" ] || return

	# Creates symlinks to each file because runit maintains a state in each
	# service's directory so linking the service directory would pollute
	# the source directory.
	find "$_from" -mindepth 1 ! -type d | while read -r _target; do
		_linkname="$_to/${_target#$_from/}"
		if [ -L "$_linkname" ] && [ "$(readlink "$_linkname")" = "$(realpath "$_target")" ]; then
			continue # symlink already in place
		fi
		mkdir -p "$(dirname "$_linkname")"
		ln -snf "$_target" "$_linkname"
	done
}

# Initialize RUN_SV_DIR with static OS services from SV_DIR.
ln_all "$SV_DIR" "$RUN_SV_DIR"

# Initialize RUN_SV_DIR with dynamically created services from STAGE_SV_DIR.
ln_all "$STAGE_SV_DIR" "$RUN_SV_DIR"

# Start runit.
mkdir -p "$RUN_SV_DIR" # Just in case there was no service
eval exec "$RUN_SV_DIR_BIN" -P "$RUN_SV_DIR"
