#!/bin/sh

# Check kernel configuration options required by AppSupport
#
# Copyright (c) 2023 Jolla Ltd.
#
# License: Jolla Proprietary

# Config options can be defined in the bottom of this script, format is
# CONFIG_NAME [y/m/o] Explanation for the entry
#
# If expected value is 'y' and the config value is not defined as FOO=y,
# NOT OK! is printed and the explanation part of line is printed.
#
# If expected value is 'm' and the config value is not defined as either
# FOO=y or FOO=m, NOT OK! is printed and the explanation part of the line
# is printed.
#
# If expected value is 'o' and the config value is not defined as either
# FOO=y or FOO=m, "optional, not enabled" is printed and the explanation
# part of the line is printed.
#
# Version 2023-05-02

CONFIG_LOCATION=""

find_config_location() {
    # Try to autodetect active kernel config location
    for LOCATION in                 \
        /proc/config.gz             \
        /proc/config                \
        /boot/config                \
        /boot/config-$(uname -r)    \
    ; do
        if [ -f "$LOCATION" ]; then
            CONFIG_LOCATION="$LOCATION"
            break
        fi
    done
}

if [ $# -gt 0 ]; then
    case "$1" in
        -f|--file)
            if [ -z "$2" ]; then
                echo "Argument $1 requires a file location."
                exit 1
            elif [ -f "$2" ]; then
                CONFIG_LOCATION="$2"
            else
                echo "File not found: $2"
                exit 1
            fi
            ;;
        -h|--help)
            echo "$0 - Check Kernel config for AppSupport."
            echo ""
            echo " -h --help    This help."
            echo " -f --file    Specify file for checking instead of autodetecting."
            echo ""
            exit 0
            ;;
        *)
            echo "Unknown argument $1"
            exit 1
        ;;
    esac
else
    find_config_location

    if [ -z "$CONFIG_LOCATION" ] && ! lsmod | grep -qw configs; then
        echo "Trying to load configs module..."
        if modprobe configs; then
            find_config_location
        fi
    fi

    if [ -z "$CONFIG_LOCATION" ]; then
        echo "Could not detect config location for current Kernel (try --file)."
        exit 1
    fi
fi

echo "Using $CONFIG_LOCATION for determining Kernel build options..."
echo ""

LOCATION_SUFFIX="${CONFIG_LOCATION%???}"
LOCATION_SUFFIX="${CONFIG_LOCATION#"$LOCATION_SUFFIX"}"
if [ "$LOCATION_SUFFIX" = ".gz" ]; then
    TMP_CONF="/tmp/appsupport-kernel-config-check.$$.config"
    gunzip -c "$CONFIG_LOCATION" > "$TMP_CONF"
    if [ $? -ne 0 ]; then
        echo "Failed to unpack $CONFIG_LOCATION"
        exit 1
    fi
    CONFIG_LOCATION="$TMP_CONF"
fi

ALL_OK=1

CONFIG_ENTRY_BINDERFS="$(grep "^CONFIG_ANDROID_BINDERFS=" "$CONFIG_LOCATION")"
CONFIG_ENTRY_BINDER_DEVICES="$(grep "^CONFIG_ANDROID_BINDER_DEVICES=" "$CONFIG_LOCATION")"
# Check binderfs or binder_devices list manually as they need more logic
if grep "^CONFIG_ANDROID_BINDERFS=y" "$CONFIG_LOCATION" >/dev/null ||
   grep "^CONFIG_ANDROID_BINDERFS=m" "$CONFIG_LOCATION" >/dev/null; then
    printf "%*s\r%s\n" 50 "[ok]" "$CONFIG_ENTRY_BINDERFS"
elif grep "^CONFIG_ANDROID_BINDER_DEVICES=" "$CONFIG_LOCATION" >/dev/null; then
    if grep -e "^CONFIG_ANDROID_BINDER_DEVICES=.*puddlejumper,vndpuddlejumper,hwpuddlejumper.*" "$CONFIG_LOCATION" >/dev/null; then
        printf "%*s\r%s\n" 50 "[ok]" "CONFIG_ANDROID_BINDER_DEVICES=*"
        printf "    : %s\n" "$CONFIG_ENTRY_BINDER_DEVICES"
    else
        printf "%*s\r%s\n" 55 "[NOT OK!]" "CONFIG_ANDROID_BINDER_DEVICES="
        printf "    : %s\n" "Binder devices is defined but the list doesn't contain puddlejumper,vndpuddlejumper,hwpuddlejumper"
        ALL_OK=0
    fi
else
    printf "%*s\r%s\n" 55 "[NOT OK!]" "ANDROID BINDER configuration"
    printf "    : %s\n" "Either CONFIG_ANDROID_BINDERFS=y with Kernels that support it or CONFIG_ANDROID_BINDER_DEVICES= with \"puddlejumper,vndpuddlejumper,hwpuddlejumper\" is required."
    ALL_OK=0
fi

START_ENTRIES=0
while read LINE; do
    if [ $START_ENTRIES -eq 1 ]; then
        if [ "$LINE" = "#-CONFIG ENTRIES END" ]; then
            break
        fi

        # Do the checking
        set -- ${LINE%#*}
        CONFIG_OPT="$1"

        if [ -z "$CONFIG_OPT" ]; then
            continue
        elif [ "$CONFIG_OPT" = "-NOTE" ]; then
            shift
            echo "# $@"
            continue
        fi

        CONFIG_VAL="$2"
        shift
        shift
        CONFIG_NOTE="$@"

        OPTIONAL=0
        if [ "$CONFIG_VAL" = "o" ]; then
            CONFIG_VAL=m
            OPTIONAL=1
        fi

        CONFIG_ENTRY="$(grep "^$CONFIG_OPT=" "$CONFIG_LOCATION")"

        if ( [ "$CONFIG_VAL" = "m" ] && grep "^$CONFIG_OPT=y" "$CONFIG_LOCATION" >/dev/null ) ||
            grep "^$CONFIG_OPT=$CONFIG_VAL" "$CONFIG_LOCATION" >/dev/null; then
            printf "%*s\r%s\n" 50 "[ok]" "$CONFIG_ENTRY"
        else
            if [ $OPTIONAL -eq 1 ]; then
                printf "%*s\r%s\n" 69 "[optional, not enabled]" "$CONFIG_OPT="
            else
                printf "%*s\r%s\n" 55 "[NOT OK!]" "$CONFIG_OPT=$CONFIG_VAL"
            fi
            if [ -n "$CONFIG_NOTE" ]; then
                printf "    : %s\n" "$CONFIG_NOTE"
            fi
            ALL_OK=0
        fi

    elif [ "$LINE" = "#-CONFIG ENTRIES BEGIN" ]; then
        START_ENTRIES=1
    fi
done < $0

if [ $ALL_OK -eq 0 ]; then
    echo ""
    echo "Some Kernel options were not found, please check Kernel config and try again."
    echo ""
    exit 1
fi

exit 0

#-CONFIG ENTRIES BEGIN
CONFIG_ANDROID y
CONFIG_ANDROID_BINDER_IPC y
CONFIG_ASHMEM y
CONFIG_SQUASHFS y
CONFIG_SQUASHFS_LZ4 y
CONFIG_SQUASHFS_XATTR y
CONFIG_STAGING y Needed to enable ashmem
CONFIG_BLK_DEV_LOOP y Needed for mounting system image
CONFIG_PSI y Low memory killer

-NOTE Following are needed by lxc
CONFIG_SECCOMP y
CONFIG_NAMESPACES y
CONFIG_UTS_NS y
CONFIG_IPC_NS y
CONFIG_PID_NS y
CONFIG_NET_NS y

-NOTE Following are needed for networking (Note: =m can be substituted by =y)
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE m
CONFIG_IP_NF_FILTER m
CONFIG_NF_NAT m
CONFIG_NF_CONNTRACK y
CONFIG_IP_NF_NAT m
CONFIG_IP_NF_TARGET_MASQUERADE m
CONFIG_BRIDGE_NF_EBTABLES m
CONFIG_BRIDGE_EBT_T_NAT m
CONFIG_NET_CLS_CGROUP m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM m

CONFIG_INET6_ESP y
CONFIG_INET6_IPCOMP y
CONFIG_INET6_XFRM_MODE_TRANSPORT y
CONFIG_INET6_XFRM_MODE_TUNNEL y
CONFIG_INET y
CONFIG_INET_DIAG_DESTROY y
CONFIG_INET_ESP y
CONFIG_INET_XFRM_MODE_TRANSPORT y
CONFIG_INET_XFRM_MODE_TUNNEL y
CONFIG_IP6_NF_FILTER y
CONFIG_IP6_NF_IPTABLES y
CONFIG_IP6_NF_MANGLE y
CONFIG_IP6_NF_MATCH_RPFILTER y
CONFIG_IP6_NF_RAW y
CONFIG_IP6_NF_TARGET_REJECT y
CONFIG_IPV6 y
CONFIG_IPV6_MIP6 y
CONFIG_IPV6_MULTIPLE_TABLES y
CONFIG_IPV6_OPTIMISTIC_DAD y
CONFIG_IPV6_ROUTER_PREF y
CONFIG_IPV6_ROUTE_INFO y
CONFIG_IPV6_VTI y
CONFIG_IP_ADVANCED_ROUTER y
CONFIG_IP_MULTICAST y
CONFIG_IP_MULTIPLE_TABLES y
CONFIG_IP_NF_ARPFILTER y
CONFIG_IP_NF_ARPTABLES y
CONFIG_IP_NF_ARP_MANGLE y
CONFIG_IP_NF_FILTER y
CONFIG_IP_NF_IPTABLES y
CONFIG_IP_NF_MANGLE y
CONFIG_IP_NF_MATCH_ECN y
CONFIG_IP_NF_MATCH_TTL y
CONFIG_IP_NF_NAT y
CONFIG_IP_NF_RAW y
CONFIG_IP_NF_SECURITY y
CONFIG_IP_NF_TARGET_MASQUERADE y
CONFIG_IP_NF_TARGET_NETMAP y
CONFIG_IP_NF_TARGET_REDIRECT y
CONFIG_IP_NF_TARGET_REJECT y

CONFIG_NET y
CONFIG_NETDEVICES y
CONFIG_NETFILTER y
CONFIG_NETFILTER_XT_MATCH_BPF y
CONFIG_NETFILTER_XT_MATCH_COMMENT y
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT y
CONFIG_NETFILTER_XT_MATCH_CONNMARK y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK y
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT y
CONFIG_NETFILTER_XT_MATCH_HELPER y
CONFIG_NETFILTER_XT_MATCH_IPRANGE y
CONFIG_NETFILTER_XT_MATCH_LENGTH y
CONFIG_NETFILTER_XT_MATCH_LIMIT y
CONFIG_NETFILTER_XT_MATCH_MAC y
CONFIG_NETFILTER_XT_MATCH_MARK y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE y
CONFIG_NETFILTER_XT_MATCH_POLICY y
CONFIG_NETFILTER_XT_MATCH_QUOTA2 y
CONFIG_NETFILTER_XT_MATCH_QUOTA y
CONFIG_NETFILTER_XT_MATCH_SOCKET y
CONFIG_NETFILTER_XT_MATCH_STATE y
CONFIG_NETFILTER_XT_MATCH_STATISTIC y
CONFIG_NETFILTER_XT_MATCH_STRING y
CONFIG_NETFILTER_XT_MATCH_TIME y
CONFIG_NETFILTER_XT_MATCH_U32 y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY y
CONFIG_NETFILTER_XT_TARGET_CONNMARK y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER y
CONFIG_NETFILTER_XT_TARGET_MARK y
CONFIG_NETFILTER_XT_TARGET_NFLOG y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE y
CONFIG_NETFILTER_XT_TARGET_SECMARK y
CONFIG_NETFILTER_XT_TARGET_TCPMSS y
CONFIG_NETFILTER_XT_TARGET_TPROXY y
CONFIG_NETFILTER_XT_TARGET_TRACE y
CONFIG_NET_CLS_ACT y
CONFIG_NET_CLS_U32 y
CONFIG_NET_EMATCH y
CONFIG_NET_EMATCH_U32 y
CONFIG_NET_IPVTI y
CONFIG_NET_KEY y
CONFIG_NET_SCHED y
CONFIG_NET_SCH_HTB y
CONFIG_NF_CONNTRACK y
CONFIG_NF_CONNTRACK_AMANDA y
CONFIG_NF_CONNTRACK_EVENTS y
CONFIG_NF_CONNTRACK_FTP y
CONFIG_NF_CONNTRACK_H323 y
CONFIG_NF_CONNTRACK_IPV4 y
CONFIG_NF_CONNTRACK_IPV6 y
CONFIG_NF_CONNTRACK_IRC y
CONFIG_NF_CONNTRACK_NETBIOS_NS y
CONFIG_NF_CONNTRACK_PPTP y
CONFIG_NF_CONNTRACK_SANE y
CONFIG_NF_CONNTRACK_SECMARK y
CONFIG_NF_CONNTRACK_TFTP y
CONFIG_NF_CT_NETLINK y
CONFIG_NF_CT_PROTO_DCCP y
CONFIG_NF_CT_PROTO_SCTP y
CONFIG_NF_CT_PROTO_UDPLITE y
CONFIG_NF_NAT y
#-CONFIG ENTRIES END
