#!/bin/bash
set -euo pipefail
# https://github.com/coreos/fedora-coreos-tracker/issues/465
# coreos-assembler generates disk images which are installed bit-for-bit
# or booted directly in the cloud.
# Generate new UUID on firstboot; this is general best practice, but in the future
# we may use this for mounting by e.g. adding a boot=<uuid> and root=<uuid> kernel args.

label=$1

# Keep this in sync with https://github.com/coreos/coreos-assembler/blob/e3905fd2e138de04184c1cd86b99b0fd83cbe5cf/src/create_disk.sh#L17
bootfs_uuid="96d15588-3596-4b3c-adca-a2ff7279ea63"
rootfs_uuid="910678ff-f77e-4a7d-8d53-86f2ac47a823"

target=/dev/disk/by-label/${label}
if ! [ -b "${target}" ]; then
  echo "$0: Failed to find block device ${target}" 1>&2
  exit 1
fi

eval $(blkid -o export ${target})
case "${label}" in
  root) orig_uuid="${rootfs_uuid}"; orig_type=xfs ;;
  boot) orig_uuid="${bootfs_uuid}"; orig_type=ext4 ;;
  *) echo "unexpected ${label}"; exit 1 ;;
esac

if [ "${TYPE}" == "${orig_type}" ] && [ "${UUID}" == "${orig_uuid}" ]; then
  case "${TYPE}" in
    ext4)
          # If the filesystem supports metadata_csum_seed then the UUID is stored
          # in the superblock and there is no need to worry with an fsck. For the
          # boot filesystem this FS feature wasn't supported by GRUB until recently.
          # https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00031.html
          # Once grub is updated in all systems we care about we can standardize
          # on the metadata_csum_seed and delete the `else` code block.
          if tune2fs -l ${target} | grep 'metadata_csum_seed'; then
              tune2fs -U random "${target}"
          else
              # Run an fsck since tune2fs -U requires the FS to be clean
              e2fsck -fy "${target}"
              # We just ran an fsck, but there is a bug where tune2fs -U will still
              # complain. It will still error if the last checked timestamp (just
              # set by the e2fsck above) is older than the last mount timestamp (happens
              # on systems with out of date or non-functioning hardware clocks).
              # See https://github.com/coreos/fedora-coreos-tracker/issues/735#issuecomment-859605953
              # Potentially fixed in future by: https://www.spinics.net/lists/linux-ext4/msg78012.html
              tune2fsinfo="$(tune2fs -l ${target})"
              lastmount=$(echo "$tune2fsinfo" | grep '^Last mount time:' | cut -d ':' -f 2,3,4)
              lastfsck=$(echo "$tune2fsinfo" | grep '^Last checked:' | cut -d ':' -f 2,3,4)
              lastmountsse=$(date --date="$lastmount" +%s)
              lastfscksse=$(date --date="$lastfsck" +%s)
              if (( lastfscksse < lastmountsse )); then
                  echo "Detected timestamp of last fsck is older than timestamp of last mount."
                  echo "Setting "${target}" timestamp of last fsck to same time as last mount."
                  tune2fs -T $(date --date="$lastmount" +%Y%m%d%H%M%S) "${target}"
              fi
              # Finally, we can randomize the UUID
              tune2fs -U random "${target}"
          fi ;;
    xfs) xfs_admin -U generate "${target}" ;;
    *) echo "unexpected filesystem type ${TYPE}" 1>&2; exit 1 ;;
  esac
  udevadm settle || :
  echo "Regenerated UUID for ${target}"
else
  echo "No changes required for ${target} TYPE=${TYPE} UUID=${UUID}"
fi
