#!/bin/sh

__snapshot () {
    local _name _snapshot _fulluuid _dataset _date _jid _database_check _answer

    _date=$(date "+%F_%T")

    if [ "$1" = "-r" ] ; then
        shift
        _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
        _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"
        _dataset="$(__find_jail ${_name})" || exit $?
        _fulluuid="$(__check_name ${_name} ${_dataset})"
        _jid=$(jls -j ioc-${_fulluuid} jid 2> /dev/null)
        _database_check="$(ps -axJ ${_jid} 2> /dev/null | \
            grep -qE 'mysqld|postgresql' ; echo $?)"

        if [ -z $_name ] ; then
            __die "missing UUID!"
        fi

        if [ "${_database_check}" -eq 0 ] ; then
            if [ "${_force}" != "1" ] ; then
                echo " "
                echo "  WARNING: A database is running! This may cause issues!"
                echo " "
                echo -n "  Would you like to continue? y[N]: "
                read _answer

                if [ "${_answer}" = "N" -o "${_answer}" = "n" ] ; then
                    exit 0
                fi
            fi
        fi

        if [ ! -z $_snapshot ] ; then
            zfs snapshot -r ${_dataset}@${_snapshot}
        else
            zfs snapshot -r ${_dataset}@ioc-${_date}
        fi
    else
        _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
        _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"
        _dataset="$(__find_jail ${_name})" || exit $?
        _fulluuid="$(__check_name ${_name} ${_dataset})"
        _jid=$(jls -j ioc-${_fulluuid} jid 2> /dev/null)
        _database_check="$(ps -axJ ${_jid} 2> /dev/null | \
            grep -qE 'mysqld|postgresql' ; echo $?)"

        if [ -z $_name ] ; then
            __die "missing UUID!"
        fi

        if [ "${_database_check}" -eq 0 ] ; then
            if [ "${_force}" != "1" ] ; then
                echo " "
                echo "  WARNING: A database is running! This may cause issues!"
                echo " "
                echo -n "  Would you like to continue? y[N]: "
                read _answer

                if [ "${_answer}" = "N" -o "${_answer}" = "n" ] ; then
                    exit 0
                fi
            fi
        fi

        if [ ! -z $_snapshot ] ; then
                zfs snapshot ${_dataset}/root@${_snapshot}
        else
                zfs snapshot ${_dataset}/root@ioc-${_date}
        fi
    fi
}


__snapremove () {
    local _name _snap _snapshot _snapshots _dataset
    _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
    _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"

    if [ -z ${_name} ] || [ -z ${_snapshot} ]; then
        __die "missing UUID or snapshot name!"
    fi

    if [ "$2" ] ; then
        _dataset="$2"
    else
        _dataset="$(__find_jail ${_name})" || exit $?
    fi

    if [ -z ${_dataset} ] ; then
        __die "jail dataset not found"
    fi

    if [ ! -z ${_snapshot} ] && [ "${_snapshot}" != "ALL" ] ; then
        echo "* removing snapshot: ${_snapshot}"
        zfs destroy -r ${_dataset}@${_snapshot}
    elif [ "${_snapshot}" == "ALL" ] ; then
        _snapshots="$(zfs list -d1 -Hrt snapshot -o name ${_dataset})"
        for _snap in $(echo ${_snapshots}) ; do
            zfs destroy -r ${_snap}
        done
    else
        __die "snapshot not found!"
    fi
}

__snaplist () {
    local _name _dataset _fulluuid _snapshots _snapname \
          _creation _used _referenced _snap

    _name="$1"

    if [ -z "${_name}" ] ; then
        __die "missing UUID!"
    fi

    _dataset="$(__find_jail ${_name})" || exit $?

    if [ -z "${_dataset}" ] ; then
        __die "${_name} not found!"
    fi

    _fulluuid="$(__check_name ${_name} ${_dataset})"
    _snapshots="$(zfs list -Hrt snapshot -d3 ${_dataset} | awk '{print $1}')"

    if [ -z "${_snapshots}" ] ; then
        __info "${_name} has no snapshots."
        exit 0
    fi

    printf "%-36s  %-21s  %s   %s\n" "NAME" "CREATED"\
            "RSIZE" "USED"

    for _snap in ${_snapshots} ; do
        _snapname="$(echo ${_snap} | cut -f 2 -d \@)"
        _creation="$(zfs get -H -o value creation ${_snap})"
        _used="$(zfs get -H -o value used ${_snap})"
        _referenced="$(zfs get -H -o value referenced ${_snap})"

        printf "%-36s  %-21s  %s    %s\n" "${_snapname}" "${_creation}"\
                   "${_referenced}" "${_used}"
    done
}

__rollback () {
    local _name _snapshot _fs _fulluuid _dataset _jail_type

    _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
    _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"
    _dataset="$(__find_jail ${_name})" || exit $?
    _fulluuid="$(__check_name ${_name} ${_dataset})"
    _jail_type="$(__get_jail_prop type ${_fulluuid} ${_dataset})"
    _fs_list=$(zfs list -rH -o name ${_dataset})

    if [ ! -z "${_snapshot}" ] ; then
        for _fs in ${_fs_list} ; do
            if [ "${_jail_type}" = "basejail" -a "${_fs}" = "${_dataset}/root" ] ; then
                continue
            fi
            echo "* Rolling back to ${_fs}@${_snapshot}"
            zfs rollback -r ${_fs}@${_snapshot}
        done
    fi
}

__promote () {
    local _name _dataset _fs_list _origin

    _name="$1"

    if [ -z $_name ] ; then
        __die "missing UUID!"
    fi

    _dataset=$(__find_jail $_name) || exit $?

    if [ -z $_dataset ] ; then
        __die "$_name not found!"
    fi

    _fs_list=$(zfs list -rH -o name $_dataset)

    for _fs in $_fs_list ; do
        _origin="$(zfs get -H -o value origin $_fs)"

        if [ "$_origin" != "-" ] ; then
            echo "* promoting filesystem: $_fs"
            zfs promote $_fs
            continue
        else
            echo "  INFO: filesystem $_fs is not a clone"
        fi
    done
}

__mount_snapshot () {
    local _name _snapshot _destination _fulluuid _dataset _snapcheck

    _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
    _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"
    _destination="$2"
    _dataset="$(__find_jail ${_name})" || exit $?
    _fulluuid="$(__check_name ${_name} ${_dataset})"

    if [ -z "${_snapshot}" ] ; then
        __die "missing snapshot!"
    elif [ -z "${_destination}" ] ; then
        __die "missing destination!"
    elif [ ! -d "${_destination}" ] ; then
        __die "destination does not exist!"
    fi

    # Quick way for us to see if we should use UUID or UUID/root.
    _snapcheck="$(zfs list -Hrt snapshot -d2 ${_dataset})"

    for _snap in $_snapcheck ; do
        if [ "$(echo ${_snap} | grep -w ${_dataset}@${_snapshot})" ] ; then
            mount -t zfs ${_dataset}@${_snapshot} ${_destination}
            mount -t zfs ${_dataset}/root@${_snapshot} ${_destination}/root
            break
        elif [ "$(echo ${_snap} | grep -w ${_dataset}/root@${_snapshot})" ] ; then
            mount -t zfs ${_dataset}/root@${_snapshot} ${_destination}
            break
        fi
    done
}

# This has an annoying quirk of not handling a shared mount. It will work
# If you umount in the reverse order you mounted, otherwise it's all random.
# TODO : Improve some day.
__umount_snapshot () {
    local _name _snapshot _fulluuid _dataset _mountcheck _fullsnap

    _name="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $1 }')"
    _snapshot="$(echo $1 |  awk 'BEGIN { FS = "@" } ; { print $2 }')"
    _dataset="$(__find_jail ${_name})" || exit $?
    _fulluuid="$(__check_name ${_name} ${_dataset})"
    _fullsnap="${_dataset}@${_snapshot}"

    if [ -z "${_snapshot}" ] ; then
        __die "missing snapshot!"
    fi

    # Quick way for us to see if we should use UUID or UUID/root.
    _mountcheck=$(mount -t zfs | \
        awk -v awk_snap="${_fullsnap}" '$1==awk_snap {print $3}')

    if [ ! -z "${_mountcheck}" ] ; then
        umount -ft zfs "${_mountcheck}/root" > /dev/null 2>&1
        umount -ft zfs "${_mountcheck}" > /dev/null 2>&1
    elif [ -z "${_mountcheck}" ] ; then
        _fullsnap="${_dataset}/root@${_snapshot}"
        _mountcheck=$(mount -t zfs | \
            awk -v awk_snap="${_fullsnap}" '$1==awk_snap {print $3}')
        umount -ft zfs "${_mountcheck}" > /dev/null 2>&1
    fi

    if [ -z "${_mountcheck}" ] ; then
        __die "that snapshot isn't mounted!"
    fi
}
