#!/bin/bash

set -eu

fs=$1
genimg_in=$2

[[ -d "$fs" ]] || exit 0


# Create persistent skeleton - must match part names in genimage.cfg.in
mkdir -p ${fs}/persistent/slots/system_a/var
mkdir -p ${fs}/persistent/slots/system_b/var
mkdir -p ${fs}/persistent/common/etc

install -d -m 1777 ${fs}/persistent/slots/system_a/var/tmp
install -d -m 1777 ${fs}/persistent/slots/system_b/var/tmp


# machine-id(5) needed by sysinit.target
wants_dir="${fs}/etc/systemd/system/sysinit.target.wants"
units=(
  "machine-id-sync.service"
)
install -d -m 0755 "${wants_dir}"
for unit in "${units[@]}"; do
  [ -f "${fs}/etc/systemd/system/${unit}" ] || die "missing ${unit}"
  chmod 0644 "${fs}/etc/systemd/system/${unit}"
  ln -sf "../${unit}" "${wants_dir}/${unit}"
done

# Ship an empty file, add entry for legacy dbus
rm -f "${fs}/etc/machine-id"
rm -f "${fs}/var/lib/dbus/machine-id"
install -m0644 -o root -g root /dev/null "${fs}/etc/machine-id"
install -d -m 0755 "${fs}/var/lib/dbus/"
ln -s /etc/machine-id "${fs}/var/lib/dbus/machine-id"


# persistent-shared-init needed by local-fs.target
wants_dir="${fs}/etc/systemd/system/local-fs.target.wants"
units=(
  "persistent-shared-init.service"
)
install -d -m 0755 "${wants_dir}"
for unit in "${units[@]}"; do
  [ -f "${fs}/etc/systemd/system/${unit}" ] || die "missing ${unit}"
  chmod 0644 "${fs}/etc/systemd/system/${unit}"
  ln -sf "../${unit}" "${wants_dir}/${unit}"
done


# /var is per-slot, so synchronise
rsync -aHAXS --numeric-ids --delete "${fs}/var/" "${fs}/persistent/slots/system_a/var/"
rsync -aHAXS --numeric-ids --delete "${fs}/var/" "${fs}/persistent/slots/system_b/var/"


# Journal is retained across slot rotations
install -d -m 2755 -o root -g systemd-journal "${fs}/persistent/log/journal"
# set preferences
# https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html
install -d -m 0755 ${fs}/etc/systemd/journald.conf.d
cat > ${fs}/etc/systemd/journald.conf.d/persistent.conf <<'EOF'
[Journal]
Storage=persistent

# Reduce space
Compress=yes

# Lower disk budget
SystemMaxUse=512M
SystemMaxFileSize=20M

# No time window retention
MaxRetentionSec=0
MaxFileSec=0

# Endurance profile
RuntimeMaxUse=128M
SyncIntervalSec=2m
RateLimitInterval=30s
RateLimitBurst=2000

# Integrity
Seal=yes
EOF


# /home is bind mounted to /persistent/home and retained across slot rotations
# Mirror it
mkdir -p "${fs}/persistent/home/"
rsync -aHAXS --numeric-ids --delete "${fs}/home/" "${fs}/persistent/home/"

# Reclaim /home
find "${fs}/home" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +


# Reclaim /var but ensure skeleton exists for services that need PrivateTmp
# otherwise namespace setup will fail on the immutable root.
find "${fs}/var" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
install -d -m 1777 ${fs}/var/tmp
install -d -m 0755 ${fs}/var/log
install -d -m 0755 ${fs}/var/cache
install -d -m 0755 ${fs}/var/spool


# For each slot-shared path: seed /persistent/shared and retain a copy in the
# immutable root. Both use the slot-a copy (rsynced above) as the source.
# Retaining in the immutable root lets persistent-shared-init push OTA-delivered
# files into the shared location on each boot, before bind mounts activate.
if ls "${fs}/etc/rpi-image-gen/slot-shared.d/"*.conf >/dev/null 2>&1; then
   for conf in "${fs}/etc/rpi-image-gen/slot-shared.d/"*.conf; do
      [ -f "$conf" ] || continue
      version=""
      paths=""
      while IFS= read -r line || [ -n "$line" ]; do
         case "$line" in ''|\#*) continue ;; esac
           key="${line%%=*}"
           value="${line#*=}"
           case "$key" in
               Version) version="$value" ;;
               Path)    paths="$paths /${value#/}" ;;
           esac
      done < "$conf"

      if [ "$version" != "1" ]; then
         die "preimage: $conf: unsupported slot-shared version '${version:-missing}'"
      fi

      for path in $paths; do
         src="${fs}/persistent/slots/system_a${path}"
         [ -d "$src" ] || continue
         mkdir -p "${fs}/persistent/shared${path}"
         rsync -aHAXS --numeric-ids --delete "${src}/" "${fs}/persistent/shared${path}/"
         mkdir -p "${fs}${path}"
         rsync -aHAXS --numeric-ids --delete "${src}/" "${fs}${path}/"
      done
   done
fi


# Older systemd (eg 252/Bookworm) sets up per‑service mount namespaces by
# bind mounting a read‑only snapshot of / under /run/systemd/unit-root then
# mounting APIVFS and PrivateTmp bits (eg, /dev, /proc, /sys) inside that.
# systemd is not able to create these on an immutable root if they don't
# exist. Even if we create them, namespace init fails (status=226/NAMESPACE).
# New systemd (eg 257/Trixie) does not have this problem. Only workaround is
# to relax the sandboxing for these services. See:
# https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
ver=$(systemd-major "$fs")
[[ "$ver" =~ ^[0-9]+$ ]] || { echo "systemd-major error for $fs" >&2; exit 1; }
if [[ "$ver" -lt 257 ]]; then
  for svc in systemd-resolved systemd-timesyncd; do
    d="${fs}/etc/systemd/system/${svc}.service.d"
    mkdir -p "$d"
    cat > "${d}/immutable-root.conf" <<'EOF'
[Service]
PrivateDevices=no
EOF
  done
fi


# Perms for bind mounts on the immutable root
chmod 755 "${fs}/home"
chmod 755 "${fs}/var"
