#!/bin/bash
# -*- mode: sh; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# vim: et sts=4 sw=4

#  SPDX-License-Identifier: LGPL-2.1+
#
#  Copyright © 2020-2021 Collabora Ltd.
#  Copyright © 2020-2021 Valve Corporation.
#
#  This file is part of steamos-customizations.
#
#  steamos-customizations is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation; either version 2.1 of the License,
#  or (at your option) any later version.

set -e
set -u
set -o pipefail

usage() {
    cat <<EOF
Usage: ${0##*/} enable|disable|status|verify

Enable or disable the block level verification on the current running SteamOS.
EOF
}

blockinfo() {
    eval "$(blkid "$1" | sed 's,^\(.*\): ,export DEVNAME="\1" ,')"
    echo "$DEVNAME"
    echo "${UUID:-}"
    echo "${PARTLABEL:-}"
    echo "${PARTUUID:-}"
    echo "${TYPE:-}"
    echo "${LABEL:-}"
    echo "${BLOCK_SIZE:-}"
}

read_write() {
    tune2fs -O ^read-only "$1"
    if grep -q '^/dev/mapper/root / ' /proc/mounts
    then
        echo "Warning: The rootfs is still read-only!" >&2
        echo "         Reboot to complete setup." >&2
        return
    fi

    mount -o remount,rw /
    rm -f /efi/SteamOS/roothash
    sync /
}

read_only() {
    if grep -q '^/dev/mapper/root / ' /proc/mounts
    then
        echo "Warning: The rootfs is already read-only!" >&2
        echo "         Nothing is performed." >&2
        return
    fi

    mapfile -t rootfs < <(blockinfo "$1")

    sync /
    mount -o remount,ro /
    tune2fs -O read-only "${rootfs[0]}"
    veritysetup format --data-block-size "${rootfs[6]}" --hash-block-size "${rootfs[6]}" "$@" | \
        tee /dev/stderr | \
        sed -n 's,^Root hash:[[:blank:]]\+\([[:xdigit:]]\{64\}\)$,\1,p' >/efi/SteamOS/roothash

    echo "Reboot to complete setup." >&2
}

status() {
    local filesystem_is_readonly
    local device_is_readonly
    local roothash

    if grep -q '^/dev/mapper/root / ' /proc/mounts
    then
        device_is_readonly=yes
    fi

    if tune2fs -l "$1" | grep -q '^Filesystem features: .*read-only.*$'
    then
        filesystem_is_readonly=yes
    fi

    if [[ -e /efi/SteamOS/roothash ]]
    then
        roothash="$(cat /efi/SteamOS/roothash)"
    fi

    if [[ "${roothash:-}" ]] && [[ "${device_is_readonly:-}" ]] && [[ "${filesystem_is_readonly:-}" ]]
    then
        echo "enabled"
        return
    fi

    if [[ ! "${roothash:-}" ]] && [[ ! "${filesystem_is_readonly:-}" ]]
    then
        echo "disabled"
        return 1
    elif [[ ! "${roothash:-}" ]] && [[ ! "${filesystem_is_readonly:-}" ]]
    then
        echo "disabled${device_is_readonly:+ (after reboot)}"
        return 1
    fi

    if [[ "${device_is_readonly:-}" ]]
    then
        device_is_readonly=no
    fi

    if [[ "${filesystem_is_readonly:-}" ]]
    then
        filesystem_is_readonly=no
    fi

    echo "unknown (device-is-read-only: $device_is_readonly, filesystem-is-read-only: $filesystem_is_readonly, roothash: ${roothash:-none})"
    return 1
}

verify() {
    if [[ ! -e /efi/SteamOS/roothash ]]
    then
        return 1
    fi

    veritysetup verify "$@" "$(cat /efi/SteamOS/roothash)"
}

case "${1:-}" in
    disable)
        read_write /dev/disk/by-partsets/self/rootfs
        ;;
    enable)
        read_only /dev/disk/by-partsets/self/rootfs /dev/disk/by-partsets/self/verity
        ;;
    status)
        status /dev/disk/by-partsets/self/rootfs
        ;;
    verify)
        verify /dev/disk/by-partsets/self/rootfs /dev/disk/by-partsets/self/verity
        ;;
    *)
        usage
        exit 1
esac
