#!/bin/bash

type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh

function getOverlayBaseDirectory {
    # initialize and print overlay base directory below which
    # the overlayfs based mountpoints are managed
    local overlay_base=/run/overlay
    local unit_name
    local overlay_size
    mkdir -p "${overlay_base}"
    if ! mountpoint -q "${overlay_base}";then
        overlay_size=$(getarg rd.root.overlay.size)
        [ -z "${overlay_size}" ] && overlay_size="50%"
        unit_name=$(echo "${overlay_base}" | cut -c 2- | tr / -)
        cat >/run/systemd/system/"${unit_name}".mount <<-EOF
		[Unit]
		Before=initrd-root-fs.target
		DefaultDependencies=no
		[Mount]
		Where=$overlay_base
		What=tmpfs
		Type=tmpfs
		DirectoryMode=0755
		[Install]
		WantedBy=multi-user.target
		EOF
        systemctl start "${unit_name}".mount
    fi
    echo "${overlay_base}"
}

function resize_filesystem {
    local device=$1
    test -n "${device}" || return
    local resize_fs
    local mpoint=/fs-resize
    local fstype
    fstype=$(probe_filesystem "${device}")
    lock="set_device_lock ${device}"
    case ${fstype} in
    ext2|ext3|ext4)
        resize_fs="${lock} resize2fs -f -p ${device}"
    ;;
    btrfs)
        resize_fs="mkdir -p ${mpoint} && mount ${device} ${mpoint} &&"
        resize_fs="${resize_fs} ${lock} btrfs filesystem resize max ${mpoint}"
        resize_fs="${resize_fs};umount ${mpoint} && rmdir ${mpoint}"
    ;;
    xfs)
        resize_fs="mkdir -p ${mpoint} && mount ${device} ${mpoint} &&"
        resize_fs="${resize_fs} ${lock} xfs_growfs ${mpoint}"
        resize_fs="${resize_fs};umount ${mpoint} && rmdir ${mpoint}"
    ;;
    swap)
        resize_fs="${lock} mkswap ${device} --label SWAP"
    ;;
    *)
        # don't know how to resize this filesystem
        warn "Don't know how to resize ${fstype}... skipped"
        return
    ;;
    esac
    if ! _is_ramdisk_device "${device}"; then
        if [ ! "${fstype}" = "btrfs" ];then
            # btrfs reports the free space cache to be outdated/corrupt
            # after kiwi has resized the partition table. This is an
            # expected condition prior resize of the filesystem and
            # should not prevent the following resize. As such the
            # filesystem check is not applied for btrfs prior resize
            check_filesystem "${device}"
        fi
    fi
    info "Resizing ${fstype} filesystem on ${device}..."
    if ! eval "${resize_fs}"; then
        die "Failed to resize filesystem"
    fi
}

function check_filesystem {
    local device=$1
    test -n "${device}" || return
    local check_fs
    local check_fs_return_ok
    local fstype
    fstype=$(probe_filesystem "${device}")
    lock="set_device_lock ${device}"
    case ${fstype} in
    ext2|ext3|ext4)
        # The exit code by e2fsck is the sum of the following conditions:
        # 0    - No errors
        # 1    - File system errors corrected
        # 2    - File system errors corrected, system should be rebooted
        # 4    - File system errors left uncorrected
        # 8    - Operational error
        # 16   - Usage or syntax error
        # 32   - E2fsck canceled by user request
        # 128  - Shared library error
        check_fs="${lock} e2fsck -p -f ${device}"
        check_fs_return_ok="test \$? -le 2"
    ;;
    btrfs)
        # btrfs check returns a zero exit status if it succeeds.
        # Non zero is returned in case of failure.
        check_fs="${lock} btrfsck ${device}"
        check_fs_return_ok="test \$? -eq 0"
    ;;
    xfs)
        # xfs_repair can be used to check the filesystem. However
        # for subsequent xfs_growfs no check is needed. Thus for
        # xfs we skip the checking
        return
    ;;
    *)
        # don't know how to check this filesystem
        warn "Don't know how to check ${fstype}... skipped"
        return
    ;;
    esac
    info "Checking ${fstype} filesystem on ${device}..."
    eval "${check_fs}"
    if ! eval "${check_fs_return_ok}"; then
        die "Failed to check filesystem"
    fi
}

function probe_filesystem {
    local device=$1
    test -n "${device}" || return
    local fstype
    fstype=$(blkid "${device}" -s TYPE -o value)
    if [ -z "${fstype}" ];then
        fstype=unknown
    fi
    if [ "${fstype}" = "crypto_LUKS" ];then
        fstype=luks
    fi
    echo "${fstype}"
}

#======================================
# Methods considered private
#--------------------------------------
function _is_ramdisk_device {
    echo "$1" | grep -qi "/dev/ram"
}
