#! /bin/sh

main() {
    local NFTABLES_SAVE=${2:-'/var/lib/nftables/rules-save'}
    local retval
    case "$1" in
        "clear")
            if ! use_legacy; then
                nft flush ruleset
            else
                clear_legacy
            fi
            retval=$?
        ;;
        "list")
            if ! use_legacy; then
                nft list ruleset
            else
                list_legacy
            fi
            retval=$?
        ;;
        "load")
            nft -f ${NFTABLES_SAVE}
            retval=$?
        ;;
        "store")
            local tmp_save="${NFTABLES_SAVE}.tmp"
            if ! use_legacy; then
                nft ${SAVE_OPTIONS} list ruleset > ${tmp_save}
            else
                save_legacy ${tmp_save}
            fi
            retval=$?
            if [ ${retval} ]; then
                mv ${tmp_save} ${NFTABLES_SAVE}
            fi
        ;;
    esac
    return ${retval}
}

clear_legacy() {
    local l3f line table chain first_line

    first_line=1
    if manualwalk; then
        for l3f in $(getfamilies); do
            nft list tables ${l3f} | while read line; do
                table=$(echo ${line} | sed "s/table[ \t]*//")
                deletetable ${l3f} ${table}
            done
        done
    else
        nft list tables | while read line; do
            l3f=$(echo ${line} | cut -d ' ' -f2)
            table=$(echo ${line} | cut -d ' ' -f3)
            deletetable ${l3f} ${table}
        done
    fi
}

list_legacy() {
    local l3f

    if manualwalk; then
        for l3f in $(getfamilies); do
            nft list tables ${l3f} | while read line; do
                line=$(echo ${line} | sed "s/table/table ${l3f}/")
                echo "$(nft list ${line})"
            done
        done
    else
        nft list tables | while read line; do
            echo "$(nft list ${line})"
        done
    fi
}

save_legacy() {
    tmp_save=$1
    touch "${tmp_save}"
    if manualwalk; then
        for l3f in $(getfamilies); do
            nft list tables ${l3f} | while read line; do
                line=$(echo ${line} | sed "s/table/table ${l3f}/")
                nft ${SAVE_OPTIONS} list ${line} >> ${tmp_save}
            done
        done
    else
        nft list tables | while read line; do
            nft ${SAVE_OPTIONS} list ${line} >> "${tmp_save}"
        done
    fi
}

use_legacy() {
    local major_ver minor_ver

    major_ver=$(uname -r | cut -d '.' -f1)
    minor_ver=$(uname -r | cut -d '.' -f2)

    [ $major_ver -ge 4 -o $major_ver -eq 3 -a $minor_ver -ge 18 ] && return 1
    return 0
}

CHECK_TABLE_NAME="GENTOO_CHECK_TABLE"

getfamilies() {
    local l3f families

    for l3f in ip arp ip6 bridge inet; do
        if nft create table ${l3f} ${CHECK_TABLE_NAME} > /dev/null 2>&1; then
            families="${families}${l3f} "
            nft delete table ${l3f} ${CHECK_TABLE_NAME}
        fi
    done
    echo ${families}
}

manualwalk() {
    local result l3f=`getfamilies | cut -d ' ' -f1`

    nft create table ${l3f} ${CHECK_TABLE_NAME}
    nft list tables | read line
    if [ $(echo $line | wc -w) -lt 3 ]; then
        result=0
    fi
    result=1
    nft delete table ${l3f} ${CHECK_TABLE_NAME}

    return $result
}

deletetable() {
    # family is $1
    # table name is $2
    nft flush table $1 $2
    nft list table $1 $2 | while read l; do
        chain=$(echo $l | grep -o 'chain [^[:space:]]\+' | cut -d ' ' -f2)
        if [ -n "${chain}" ]; then
            nft flush chain $1 $2 ${chain}
            nft delete chain $1 $2 ${chain}
        fi
    done
    nft delete table $1 $2
}

main "$@"
