#!/bin/bash
################################################################################
# OOM和内核异常检测模块
# 功能: 检测OOM Killer事件、Core dump文件、文件系统只读状态等内核异常
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################

# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
    source "$LIB_DIR/lib/config.sh"
else
    echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
    exit 1
fi

if [ -f "$LIB_DIR/lib/common.sh" ]; then
    source "$LIB_DIR/lib/common.sh"
else
    echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
    exit 1
fi

# ==================== 检测函数 ====================

# 检测OOM Killer事件
check_oom_killer() {
    local oom_count=0
    local oom_recent=0
    local oom_output=""

    # 从 dmesg 检查OOM记录
    if command -v dmesg &> /dev/null; then
        # 检查是否有OOM记录
        oom_output=$(dmesg -T 2>/dev/null | grep -i "Out of memory\|Killed process" | tail -5)
        oom_count=$(echo "$oom_output" | wc -l)

        # 检查最近7天的OOM记录
        oom_recent=$(dmesg -T 2>/dev/null | grep -i "Out of memory\|Killed process" | grep -E "$(date +%Y-%m-%d --date='7 days ago')|$(date +%Y-%m-%d --date='6 days ago')|$(date +%Y-%m-%d --date='5 days ago')|$(date +%Y-%m-%d --date='4 days ago')|$(date +%Y-%m-%d --date='3 days ago')|$(date +%Y-%m-%d --date='2 days ago')|$(date +%Y-%m-%d --date='1 days ago')|$(date +%Y-%m-%d)" | wc -l)
    fi

    # 从系统日志检查OOM记录
    if [ -r /var/log/messages ]; then
        local log_oom=$(grep -i "Out of memory\|Killed process" /var/log/messages 2>/dev/null | tail -5)
        if [ -n "$log_oom" ]; then
            oom_output="${oom_output}${log_oom}"
        fi
    elif [ -r /var/log/syslog ]; then
        local log_oom=$(grep -i "Out of memory\|Killed process" /var/log/syslog 2>/dev/null | tail -5)
        if [ -n "$log_oom" ]; then
            oom_output="${oom_output}${log_oom}"
        fi
    fi

    output_result "OOM_COUNT" "$oom_count"
    output_result "OOM_RECENT_DAYS" "$oom_recent"

    if [ "$oom_count" -gt 0 ]; then
        output_result "OOM_STATUS" "严重"
        echo "ERROR:检测到OOM Killer事件，系统可能内存不足"
    else
        output_result "OOM_STATUS" "正常"
    fi
}

# 检测Core dump文件
check_core_dumps() {
    local core_count=0
    local core_files=""

    # 在常见目录查找core文件
    local search_dirs="/data /tmp /root /var/crash"

    for dir in $search_dirs; do
        if [ -d "$dir" ]; then
            local found=$(find "$dir" -name "core.*" -mtime -7 2>/dev/null)
            if [ -n "$found" ]; then
                core_files="${core_files}${found}"$'\n'
            fi
        fi
    done

    core_count=$(echo "$core_files" | grep -c "core" || echo "0")

    if [ "$core_count" -gt 0 ]; then
        output_result "CORE_DUMP_COUNT" "$core_count"
        output_result "CORE_DUMP_STATUS" "警告"
        echo "ERROR:检测到${core_count}个core dump文件，可能有程序崩溃"
    else
        output_result "CORE_DUMP_COUNT" "0"
        output_result "CORE_DUMP_STATUS" "正常"
    fi
}

# 检测只读文件系统
check_readonly_fs() {
    local ro_fs=0

    # 检查 /proc/mounts 中是否有只读挂载的文件系统
    ro_fs=$(cat /proc/mounts 2>/dev/null | grep -c 'ro,' || echo "0")

    # 排除预期的只读文件系统（如squashfs、iso9660等）
    local ro_expected=$(cat /proc/mounts 2>/dev/null | grep -E 'squashfs|iso9660|overlay' | wc -l)
    ro_fs=$((ro_fs - ro_expected))

    if [ "$ro_fs" -gt 0 ]; then
        output_result "READONLY_FS_COUNT" "$ro_fs"
        output_result "READONLY_FS_STATUS" "严重"
        echo "ERROR:检测到只读文件系统，可能磁盘故障"
    else
        output_result "READONLY_FS_COUNT" "0"
        output_result "READONLY_FS_STATUS" "正常"
    fi
}

# 检测内核错误日志
check_kernel_errors() {
    local kernel_errors=0

    if command -v dmesg &> /dev/null; then
        # 检查内核错误
        kernel_errors=$(dmesg -T 2>/dev/null | grep -iE "error|failed|warning" | grep -v "ACPI" | wc -l)
    fi

    output_result "KERNEL_ERRORS" "$kernel_errors"

    if [ "$kernel_errors" -gt 50 ]; then
        output_result "KERNEL_STATUS" "警告"
    else
        output_result "KERNEL_STATUS" "正常"
    fi
}

# 检测软锁定（Soft Lockup）
check_soft_lockup() {
    local lockup_count=0

    if command -v dmesg &> /dev/null; then
        lockup_count=$(dmesg -T 2>/dev/null | grep -i "soft lockup" | wc -l)
    fi

    output_result "SOFT_LOCKUP_COUNT" "$lockup_count"

    if [ "$lockup_count" -gt 0 ]; then
        output_result "SOFT_LOCKUP_STATUS" "严重"
        echo "ERROR:检测到软锁定事件"
    else
        output_result "SOFT_LOCKUP_STATUS" "正常"
    fi
}

# 检测硬件错误（MCE）
check_hardware_errors() {
    local mce_count=0

    if command -v dmesg &> /dev/null; then
        mce_count=$(dmesg -T 2>/dev/null | grep -i "machine check" | wc -l)
    fi

    # 检查 /dev/mcelog 是否存在
    if [ -c /dev/mcelog ]; then
        output_result "MCE_DEVICE" "存在"
    else
        output_result "MCE_DEVICE" "不存在"
    fi

    output_result "HARDWARE_ERRORS" "$mce_count"

    if [ "$mce_count" -gt 0 ]; then
        output_result "HARDWARE_STATUS" "严重"
        echo "ERROR:检测到硬件错误"
    else
        output_result "HARDWARE_STATUS" "正常"
    fi
}

# ==================== 主检测流程 ====================
main() {
    log_info "开始OOM和内核异常检测..."

    # 执行各项检测
    check_oom_killer
    check_core_dumps
    check_readonly_fs
    check_kernel_errors
    check_soft_lockup
    check_hardware_errors

    log_info "OOM和内核异常检测完成"
}

# 执行主函数
main
