#!/usr/bin/bash
# Set up btrfs snapshots and container storage on the first boot of an
# installed ZypherOS Kinetic system: separate subvolumes for container and VM
# storage, so rolling back the OS never touches them; a snapper configuration
# for the root filesystem with a baseline snapshot; Docker's socket; and the
# docker and libvirt groups for the administrators the installer created. dnf
# then snapshots before and after every transaction
# (/etc/dnf/libdnf5-plugins/actions.d/snapper.actions).
set -euo pipefail

stamp=/var/lib/kinetic/snapshots-setup.done
install -d /var/lib/kinetic

if [[ "$(findmnt --noheadings --output FSTYPE /)" != btrfs ]]; then
	echo "The root filesystem is not btrfs; snapshots are not available."
	touch "${stamp}"
	exit 0
fi

# Nested subvolumes are left out of snapshots of the root subvolume
# /var/lib/containers/storage, not its parent: containers-common ships files
# in /var/lib/containers
for dir in /var/lib/docker /var/lib/containers/storage /var/lib/libvirt/images; do
	if btrfs subvolume show "${dir}" >/dev/null 2>&1; then
		continue
	fi
	if [[ -d "${dir}" ]]; then
		# Only empty directories (such as ones systemd-tmpfiles created at
		# boot) may be replaced; any file means real data
		if [[ -n "$(find "${dir}" -mindepth 1 ! -type d -print -quit)" ]]; then
			echo "Leaving ${dir} as a directory: it already has data."
			continue
		fi
		mode="$(stat -c %a "${dir}")"
		owner="$(stat -c %u:%g "${dir}")"
		find "${dir}" -depth -type d -delete
	else
		mode=711
		owner=0:0
		install -d "$(dirname "${dir}")"
	fi
	btrfs subvolume create "${dir}"
	chmod "${mode}" "${dir}"
	chown "${owner}" "${dir}"
	restorecon "${dir}"
	echo "Created subvolume ${dir}"
done

# Recreate the standard directories systemd-tmpfiles puts in them
systemd-tmpfiles --create --prefix=/var/lib/docker --prefix=/var/lib/containers --prefix=/var/lib/libvirt

if ! snapper -c root get-config >/dev/null 2>&1; then
	snapper -c root create-config /
	snapper -c root set-config \
		TIMELINE_CREATE=no \
		NUMBER_LIMIT=30 \
		NUMBER_LIMIT_IMPORTANT=10 \
		ALLOW_GROUPS=wheel \
		SYNC_ACL=yes
	restorecon -R /.snapshots
fi
snapper -c root create --description "ZypherOS Kinetic first boot" --userdata important=yes
systemctl enable --now snapper-cleanup.timer

# Docker starts on first use. Live installs keep the image's unit states, and
# docker-ce doesn't apply presets to its socket, so enable it here, once.
# --no-block: this unit is ordered before docker.service, which the socket
# starts.
if systemctl cat docker.socket >/dev/null 2>&1; then
	systemctl enable docker.socket
	systemctl start --no-block docker.socket
fi

# The administrators the installer created run containers and virtual
# machines without sudo. The installer's web interface runs no post-install
# scripts, so this is done here, before anyone logs in.
for user in $(getent group wheel | cut -d: -f4 | tr ',' ' '); do
	for group in docker libvirt; do
		if getent group "${group}" >/dev/null; then
			usermod -aG "${group}" "${user}"
		fi
	done
done

touch "${stamp}"
echo "Snapshots and container storage are set up."
