#!/bin/sh
# Called from /etc/fstab to ensure we have something writable mounted
# at /cfg, /etc, /home, /root, and /var.
#
# /mnt/cfg is used to store device modifications made to /etc, /home,
# /root.
#
# /mnt/var is used as the backing store for /var.  If /mnt/var isn't
# available, /mnt/cfg will still be be used to persist /var/lib.
#
# If a disk partiion with the corresponding label ("cfg"/"var") is
# available, that is used to persist changes to the aforementioned
# directories. Otherwise fall back to a tmpfs based RAM disk. This
# effectively brings up the system with the default configuration, but
# obviously any subsequent configuration is ephemeral.
. /etc/os-release

set -e

nm=$(basename $0)
err=0
opt="-k"

mount_rw()
{
    # If something is already setup, leave it be.
    mountpoint -q "/$1" && return 0

    # TODO: Also look for UBI partitions
    mount LABEL="$1" 2>/dev/null && return 0

    return 1
}

# Bind mount /var or /var/lib to ensure applications like podman can set
# up overlay mounts for containers.  Overlays cannot sit on top of other
# overlays.  We always copy the contents of /var or /var/lib from the
# rootfs to get updates, e.g., new packages added in an upgrade.
mount_bind()
{
    src="$1"
    dst="$2"

    mkdir -p "$src"
    cp -af "$dst/." "$src/" ||:

    mount -o bind "$src" "$dst"
}

# mkdir -p -m 0755 only applies to the deepest directory
# shellcheck disable=SC2174
mount_overlay()
{
    tag="$1"
    src="$2"
    dst="$3"
    u="$src/infix/$tag.u"
    w="$src/infix/$tag.w"

    mkdir -p -m 0755 "$u"
    mkdir -p -m 0755 "$w"

    mount -t overlay "$tag-overlay" "$dst" \
	  -o lowerdir="$dst",upperdir="$u",workdir="$w"
}

# Fall back to console logging if sysklogd is too old
if ! logger -? |grep -q "Log to kernel"; then
    opt="-c"
fi

if ! mount_rw aux >/dev/null 2>&1; then
    logger $opt -p user.warn -t "$nm" \
	   "No auxiliary partition found, software updates not supported."
fi

varsrc=/mnt/var
if ! mount_rw var >/dev/null 2>&1; then
    logger $opt -p user.warn -t "$nm" \
	   "No persistent storage found for /var, only /var/lib is persisted."
    varsrc=/mnt/tmp
    vlibsrc=/mnt/cfg/vlib
else
    mount_bind "$varsrc" /var
    varsrc=
    vlibsrc=
fi

cfgsrc=/mnt/cfg
etcsrc=/mnt/tmp
if ! mount_rw cfg >/dev/null 2>&1; then
    err=1

    logger $opt -p user.crit -t "$nm" \
	   "No persistent storage found for /cfg, falling back to tmpfs."

    cfgsrc=/mnt/tmp

    # Even if /mnt/var isn't available, if /mnt/cfg isn't either, then
    # there's no point in overlaying one ramdisk on top of another.
    vlibsrc=
else
    # Check for factory reset
    if [ -f /mnt/cfg/infix/.reset ]; then
	logger $opt -p user.crit -t "$nm" "Resetting to factory defaults."
	rm -rf /mnt/cfg/infix /mnt/var/infix
	sync
    fi

    # Check build: NETCONF or Classic
    if [ "$VARIANT_ID" != "netconf" ]; then
	etcsrc=/mnt/cfg
    fi

    # Ensure that all users in wheel can create the .reset file
    mkdir -p /mnt/cfg/infix
    chgrp wheel /mnt/cfg/infix
fi

mount_overlay cfg  $cfgsrc /cfg
mount_overlay etc  $etcsrc /etc
mount_overlay home $cfgsrc /home
mount_overlay root $cfgsrc /root

[ "$varsrc" ]  && mount_overlay var "$varsrc"  /var
[ "$vlibsrc" ] && mount_bind        "$vlibsrc" /var/lib

# Keep transient configs in a ramdisk and symlink out to /cfg for
# startup.
mkdir -p /mnt/tmp/infix/db
ln -s /cfg/startup_db /mnt/tmp/infix/db/startup_db

for tag in $(ls /sys/bus/virtio/devices/*/mount_tag 2>/dev/null); do
    if [ "$(cat $tag | tr -d '\0')" = hostfs ]; then
	mount hostfs
	break
    fi
done

exit $err
