#!/bin/sh
# SPDX-License-Identifier: LGPL-2.1+

export LC_ALL=C.UTF-8
export LANGUAGE=en

# Allow environment variables to override config
: "${CONFIG:=/proc/config.gz}"
: "${MODNAME:=configs}"

GREP="grep"

if [ -t 1 ]; then
    SETCOLOR_SUCCESS="printf \\033[1;32m"
    SETCOLOR_FAILURE="printf \\033[1;31m"
    SETCOLOR_WARNING="printf \\033[1;33m"
    SETCOLOR_NORMAL="printf \\033[0;39m"
else
    SETCOLOR_SUCCESS=":"
    SETCOLOR_FAILURE=":"
    SETCOLOR_WARNING=":"
    SETCOLOR_NORMAL=":"
fi

is_set() {
    $GREP -wm1 "^${1}=[y|m]" "${CONFIG}" > /dev/null
    return $?
}

show_enabled() {
    RES=$1
    RET=1
    if [ "$RES" -eq 0 ]; then
        $SETCOLOR_SUCCESS && printf "enabled" && $SETCOLOR_NORMAL
        RET=0
    else
        if [ -n "$mandatory" ] && [ "$mandatory" = yes ]; then
            $SETCOLOR_FAILURE && printf "required" && $SETCOLOR_NORMAL
        else
            $SETCOLOR_WARNING && printf "missing" && $SETCOLOR_NORMAL
        fi
    fi
    return $RET
}

is_enabled() {
    mandatory=$2

    is_set "$1"
    show_enabled $?
}

has_cgroup_ns() {
    mandatory=no

    if [ -f "/proc/self/ns/cgroup" ]; then
        show_enabled 0
    else
        show_enabled 1
    fi
}

is_probed() {
    if [ ! -f /proc/modules ]; then
        return
    fi
    if lsmod | grep -wm1 "^${1}" > /dev/null; then
        printf ", loaded"
    else
        printf ", not loaded"
    fi
}

if command -v lxc-start >/dev/null; then
    echo "LXC version $(lxc-start --version)"
fi

if [ ! -f "${CONFIG}" ]; then
    echo "Kernel configuration not found at $CONFIG; searching..."
    KVER="$(uname -r)"
    HEADERS_CONFIG="/lib/modules/$KVER/build/.config"
    BOOT_CONFIG="/boot/config-$KVER"
    [ -f "${HEADERS_CONFIG}" ] && CONFIG=${HEADERS_CONFIG}
    [ -f "${BOOT_CONFIG}" ] && CONFIG=${BOOT_CONFIG}
    if [ ! -f "$CONFIG" ]; then
        MODULEFILE="$(modinfo -k "$KVER" -n "$MODNAME" 2> /dev/null)"
        # don't want to modprobe, so give user a hint
        # although scripts/extract-ikconfig could be used to extract contents without loading kernel module
        # http://svn.pld-linux.org/trac/svn/browser/geninitrd/trunk/geninitrd?rev=12696#L327
    fi
    if [ ! -f "$CONFIG" ]; then
        echo "$(basename "$0"): unable to retrieve kernel configuration" >&2
        echo >&2
        if [ -f "$MODULEFILE" ]; then
            echo "Try modprobe $MODNAME module, or" >&2
        fi
        echo "Try recompiling with IKCONFIG_PROC, installing the kernel headers," >&2
        echo "or specifying the kernel configuration path with:" >&2
        echo "  CONFIG=<path> $(basename "$0")" >&2
        exit 1
    else
        echo "Kernel configuration found at $CONFIG"
    fi
fi

if gunzip -t < "$CONFIG" >/dev/null 2>&1; then
    GREP="zgrep"
fi

KVER_MAJOR="$($GREP -m1 '^# Linux.*Kernel Configuration' "${CONFIG}" | \
    sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')"
if [ "$KVER_MAJOR" = "2" ]; then
  KVER_MINOR="$($GREP -m1 '^# Linux.*Kernel Configuration' "${CONFIG}" | \
    sed -r 's/.* 2.6.([0-9]{2}).*/\1/')"
else
  KVER_MINOR="$($GREP -m1 '^# Linux.*Kernel Configuration' "${CONFIG}" | \
    sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')"
fi

if [ -z "${KVER_MAJOR}" ]; then
    echo "WARNING: Unable to detect version from configuration, assuming latest"
    echo
    KVER_MAJOR="100"
    KVER_MINOR="0"
fi

echo "
--- Namespaces ---"
printf "Namespaces: " && is_enabled CONFIG_NAMESPACES yes
echo
printf "Utsname namespace: " && is_enabled CONFIG_UTS_NS
echo
printf "Ipc namespace: " && is_enabled CONFIG_IPC_NS yes
echo
printf "Pid namespace: " && is_enabled CONFIG_PID_NS yes
echo
printf "User namespace: " && is_enabled CONFIG_USER_NS
echo
if is_set CONFIG_USER_NS; then
    if command -v newuidmap >/dev/null 2>&1; then
        f=$(command -v newuidmap)
        if [ ! -u "${f}" ]; then
            echo "Warning: newuidmap is not setuid-root"
        fi
    else
        echo "newuidmap is not installed"
    fi
    if command -v newgidmap >/dev/null 2>&1; then
        f=$(command -v newgidmap)
        if [ ! -u "${f}" ]; then
            echo "Warning: newgidmap is not setuid-root"
        fi
    else
        echo "newgidmap is not installed"
    fi
fi
printf "Network namespace: " && is_enabled CONFIG_NET_NS
echo
if [ "${KVER_MAJOR}" -lt 4 ] || { [ "${KVER_MAJOR}" -eq 4 ] && [ "${KVER_MINOR}" -lt 7 ]; }; then
    printf "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES
    echo
fi
echo "Namespace limits:"
for file in /proc/sys/user/max_*_namespaces; do
    [ -r "${file}" ] || continue

    ns_name="$(basename "${file}" | sed -e "s/^max_//g" -e "s/_namespaces$//g")"
    printf "  %s: %s" "${ns_name}" "$(cat "${file}")"
    echo
done

echo "
--- Control groups ---"
printf "Cgroups: " && is_enabled CONFIG_CGROUPS
echo
printf "Cgroup namespace: " && has_cgroup_ns
echo

print_cgroups() {
  # print all mountpoints for cgroup filesystems
  awk '$1 !~ /#/ && $3 == mp { print $2; } ; END { exit(0); } '  "mp=$1" "$2" ;
}
CGROUP_V1_MNTS=$(print_cgroups cgroup /proc/self/mounts)
CGROUP_V2_MNTS=$(print_cgroups cgroup2 /proc/self/mounts)

echo "Cgroup v1 mount points: "
for mnt in ${CGROUP_V1_MNTS}; do
    echo " - ${mnt}"
done

echo "Cgroup v2 mount points: "
for mnt in ${CGROUP_V2_MNTS}; do
    echo " - ${mnt}"
done

if [ "${CGROUP_V2_MNTS}" != "/sys/fs/cgroup" ]; then
    CGROUP_SYSTEMD_MNTPT=$(echo "$CGROUP_V1_MNTS" | grep -F "/systemd")
    if [ -z "$CGROUP_SYSTEMD_MNTPT" ]; then
        printf "Cgroup v1 systemd controller: "
        $SETCOLOR_FAILURE && echo "missing" && $SETCOLOR_NORMAL
    fi

    CGROUP_FREEZER_MNTPT=$(echo "$CGROUP_V1_MNTS" | grep -F "/freezer")
    if [ -z "$CGROUP_FREEZER_MNTPT" ]; then
        printf "Cgroup v1 freezer controller: "
        $SETCOLOR_FAILURE && echo "missing" && $SETCOLOR_NORMAL
    fi

    CGROUP_MNT_PATH=$(echo "$CGROUP_V1_MNTS" | head -n 1)
    if [ -f "$CGROUP_MNT_PATH/cgroup.clone_children" ]; then
        printf "Cgroup v1 clone_children flag: " &&
        $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
    fi
fi

printf "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
echo

printf "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
echo

printf "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
echo

printf "Cgroup memory controller: "
if { [ "${KVER_MAJOR}" -ge 3 ] && [ "${KVER_MINOR}" -ge 6 ]; } || [ "${KVER_MAJOR}" -gt 3 ]; then
    is_enabled CONFIG_MEMCG
else
    is_enabled CONFIG_CGROUP_MEM_RES_CTLR
fi
echo

is_set CONFIG_SMP && printf "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS && echo

echo "
--- Misc ---"
printf "Veth pair device: " && is_enabled CONFIG_VETH && is_probed veth
echo
printf "Macvlan: " && is_enabled CONFIG_MACVLAN && is_probed macvlan
echo
printf "Vlan: " && is_enabled CONFIG_VLAN_8021Q && is_probed 8021q
echo
printf "Bridges: " && is_enabled CONFIG_BRIDGE && is_probed bridge
echo
printf "Advanced netfilter: " && is_enabled CONFIG_NETFILTER_ADVANCED && is_probed nf_tables
if { [ "${KVER_MAJOR}" -gt 3 ] && [ "${KVER_MINOR}" -gt 6 ]; } && [ "${KVER_MAJOR}" -lt 5 ]; then
    echo
    printf "CONFIG_NF_NAT_IPV4: " && is_enabled CONFIG_NF_NAT_IPV4 && is_probed nf_nat_ipv4
    echo
    printf "CONFIG_NF_NAT_IPV6: " && is_enabled CONFIG_NF_NAT_IPV6 && is_probed nf_nat_ipv6
fi
echo
printf "CONFIG_IP_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP_NF_TARGET_MASQUERADE && is_probed nf_nat_masquerade_ipv4
echo
printf "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE && is_probed nf_nat_masquerade_ipv6
echo
printf "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM && is_probed xt_CHECKSUM
echo
printf "CONFIG_NETFILTER_XT_MATCH_COMMENT: " && is_enabled CONFIG_NETFILTER_XT_MATCH_COMMENT && is_probed xt_comment
echo
printf "FUSE (for use with lxcfs): " && is_enabled CONFIG_FUSE_FS && is_probed fuse
echo

echo "
--- Checkpoint/Restore ---"
printf "checkpoint restore: " && is_enabled CONFIG_CHECKPOINT_RESTORE
echo
printf "CONFIG_FHANDLE: " && is_enabled CONFIG_FHANDLE
echo
printf "CONFIG_EVENTFD: " && is_enabled CONFIG_EVENTFD
echo
printf "CONFIG_EPOLL: " && is_enabled CONFIG_EPOLL
echo
printf "CONFIG_UNIX_DIAG: " && is_enabled CONFIG_UNIX_DIAG
echo
printf "CONFIG_INET_DIAG: " && is_enabled CONFIG_INET_DIAG
echo
printf "CONFIG_PACKET_DIAG: " && is_enabled CONFIG_PACKET_DIAG
echo
printf "CONFIG_NETLINK_DIAG: " && is_enabled CONFIG_NETLINK_DIAG
echo
printf "File capabilities: "
if [ "${KVER_MAJOR}" = 2 ] && [ "${KVER_MINOR}" -lt 33 ]; then
    is_enabled CONFIG_SECURITY_FILE_CAPABILITIES
    echo
else
    $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
fi

echo "
Note: Before booting a new kernel, you can check its configuration with:

  CONFIG=/path/to/config $0

"
