#!/bin/sh

set -eu

# Mount Puavo partitions from local hard drive and use files created by
# puavo-register script.  Checks if LVM partitions /dev/mapper/puavo-home,
# /dev/mapper/puavo-state and /dev/mapper/puavo-tmp and mounts those as
# /home, /state or /tmp correspondingly.

btrfs_root=0
rootdev=''
if mountpoint -q /.puavo || mountpoint -q /.puavoinstaller; then
  btrfs_root=1
  # Attempt to read root device from /run/puavo/root-device
  if [ -r /run/puavo/root-device ]; then
    rootdev=$(cat /run/puavo/root-device)
  fi
  # If not found, fall back to parsing kernel parameters
  if [ -z "$rootdev" ]; then
    for parameter in $(cat /proc/cmdline); do
      case "$parameter" in
        root=*)
          rootdev=${parameter#root=}
          ;;
      esac
    done
  fi
  if [ -z "$rootdev" ]; then
    echo 'can not determine the root device for mounting local partitions' >&2
    exit 1
  fi
fi

puavo_mount_partition_on_btrfs() {
  local btrfs_label btrfs_subvol extra_mount_args puavo_mntpoint

  btrfs_label=$1        # not checked or used here
  btrfs_subvol=$2
  extra_mount_args=${3:-}

  puavo_mntpoint="/${btrfs_subvol}"

  # presume, if $puavo_mntpoint is already mounted, there is nothing to do
  if mountpoint -q "$puavo_mntpoint"; then
    return 0
  fi

  mkdir -p "$puavo_mntpoint"
  mount -o "subvol=${btrfs_subvol}" $extra_mount_args "$rootdev" \
           "$puavo_mntpoint"
}

puavo_mount_partition_on_lvm() {
  local extra_mount_args mount_opts partition puavo_mntpoint puavo_partition

  vgname=$1
  partition=$2
  extra_mount_args=${3:-}

  puavo_partition="${vgname}-${partition}"
  puavo_mntpoint="/${partition}"

  if ! [ -b "/dev/mapper/${puavo_partition}" ]; then
    echo "failed to find /dev/mapper/${puavo_partition}" >&2
    return 1
  fi

  # presume, if $puavo_mntpoint is already mounted, there is nothing to do
  if mountpoint -q "$puavo_mntpoint"; then
    return 0
  fi

  mkdir -p "$puavo_mntpoint"

  rotational_value=$(cat /sys/block/sda/queue/rotational 2>/dev/null || true)
  if [ "$rotational_value" = '0' ]; then
    mount_opts='-o discard,noatime'
  else
    mount_opts='-o noatime'
  fi

  if [ -e /images/forcefsck ]; then
    # FORCE fsck if /images/forcefsck exists
    if ! fsck -fpv "/dev/mapper/${puavo_partition}"; then
      fsck -fvy "/dev/mapper/${puavo_partition}" || true
    fi
  fi

  if mount $mount_opts $extra_mount_args "/dev/mapper/${puavo_partition}" \
           "$puavo_mntpoint"; then
    return 0
  fi

  # fsck if mount failed (first try automatic, then -y)
  if ! fsck -pv "/dev/mapper/${puavo_partition}"; then
    fsck -vy "/dev/mapper/${puavo_partition}" || true
  fi

  if mount $mount_opts $extra_mount_args "/dev/mapper/${puavo_partition}" \
           "$puavo_mntpoint"; then
    return 0
  fi

  # FORCE fsck if mount failed again (first try automatic, then -y)
  if ! fsck -fpv "/dev/mapper/${puavo_partition}"; then
    fsck -fvy "/dev/mapper/${puavo_partition}" || true
  fi

  mount $mount_opts $extra_mount_args "/dev/mapper/${puavo_partition}" \
        "$puavo_mntpoint"
}

puavo_mount_partition() {
  if [ "$btrfs_root" = 1 ]; then
    puavo_mount_partition_on_btrfs "$@"
  else
    puavo_mount_partition_on_lvm "$@"
  fi
}

read puavo_hosttype < /etc/puavo/hosttype

# activate puavo VG in case we are using LVM
if [ "$btrfs_root" = 0 ]; then
  case "$puavo_hosttype" in
    diskinstaller)
      vgchange -a y puavoinstaller
      ;;
    fatclient)
      # fatclients normally do not have a "puavo" volume group,
      # so failing this is not an error and there is nothing more to do.
      vgchange -a y puavo 2>/dev/null || exit 0
      ;;
    unregistered)
      # Do not attach puavo VG when installing a new system.
      ;;
    *)
      vgchange -a y puavo
      ;;
  esac
fi

status=0

if [ "$puavo_hosttype" = 'diskinstaller' ]; then
  puavo_mount_partition puavoinstaller installimages || status=1
fi

case "$puavo_hosttype" in
  bootserver|laptop)
    puavo_mount_partition puavo home || status=1
    ;;
esac

# In the preinstalled case "images" and "state" should be mounted for
# system updates in case of a network boot.
case "$puavo_hosttype" in
  bootserver|laptop|preinstalled|wirelessaccesspoint)
    puavo_mount_partition puavo images || status=1
    puavo_mount_partition puavo state  || status=1
    ;;
esac

# With the "exam" hosttype we want to lookup some configurations from "/state"
# but need only a read-only mount.  It is unmounted later at boot.
if [ "$puavo_hosttype" = 'exam' ]; then
  puavo_mount_partition puavo state --read-only || status=1
fi

case "$puavo_hosttype" in
  diskinstaller|exam|unregistered)
    # do not mount from /dev/mapper/puavo-tmp when installing
    # (or on the exam hosttype)
    ;;
  *)
    if [ -b /dev/mapper/puavo-tmp ]; then
      { puavo_mount_partition puavo tmp && chmod 1777 /tmp; } || status=1
    fi
    ;;
esac

if [ "$btrfs_root" = 1 ]; then
  additional_subvolumes='images/puavo-pkg state/var/lib/docker state/var/log'
  case "$puavo_hosttype" in
    bootserver|laptop|preinstalled)
      for subvol in $additional_subvolumes; do
        puavo_mount_partition_on_btrfs puavo "$subvol" || status=1
      done
      ;;
  esac
fi

rm -f /images/forcefsck

exit $status
