#!/bin/bash
# ============================================================================
# Oracle 11.2 静默安装脚本重构增强版
# 版本: 4.0
# 作者: Oracle自动化脚本重构
# 特点: 完全参数化,支持多种安装模式,带重复配置检查
# ============================================================================

# 设置脚本执行选项
set -o errexit          # 遇到错误时退出脚本
set -o nounset          # 遇到未定义变量时退出脚本
set -o pipefail         # 管道中任意命令失败时退出脚本

# ============================================================================
# 配置参数区 - 可根据需要修改这些变量
# ============================================================================

# 安装基础路径
readonly INSTALL_BASE_DIR="/data/u01"
readonly DATA_BASE_DIR="/data/u02"
readonly SOFTWARE_BASE_DIR="/data/soft/oracle"
readonly LOG_BASE_DIR="/var/log"

# Oracle安装参数
readonly ORACLE_VERSION="11.2.0.4"
# readonly ORACLE_SID="caiwu"
readonly ORACLE_SID="rkhy"
readonly ORACLE_CHARSET="ZHS16GBK"
readonly ORACLE_MEMORY_PERCENTAGE="70"
readonly ORACLE_BASE="${INSTALL_BASE_DIR}/app/oracle"
readonly ORACLE_HOME="${ORACLE_BASE}/product/${ORACLE_VERSION}/db_1"
readonly ORACLE_INVENTORY="${INSTALL_BASE_DIR}/app/oraInventory"
readonly ORACLE_DATA_DIR="${DATA_BASE_DIR}/${ORACLE_SID}"
readonly ORACLE_SOFTWARE_DIR="${SOFTWARE_BASE_DIR}/software"
readonly ORACLE_General_Purpose="${ORACLE_HOME}/assistants/dbca/templates/General_Purpose.dbc"

# 用户和组配置
readonly ORACLE_USER="oracle"
readonly ORACLE_PASSWORD="oracle"
readonly ORACLE_PRIMARY_GROUP="oinstall"
readonly ORACLE_DBA_GROUP="dba"
readonly ORACLE_OPER_GROUP="oper"

# 安装包配置
readonly ORACLE_ZIP_FILES=(
    "/data/dba/oracle/p13390677_112040_Linux-x86-64_1of7.zip"
    "/data/dba/oracle/p13390677_112040_Linux-x86-64_2of7.zip"
)

# 数据库参数
readonly SYS_PASSWORD="oracle"
readonly SYSTEM_PASSWORD="oracle"

# 系统变量
readonly HOSTNAME=$(hostname)
readonly IP_ADDRESS=$(hostname -I | awk '{print $1}')

# 状态文件
readonly STATE_TIME="$(date +%Y%m%d_%H%M%S)"
readonly STATE_DIR="/tmp/oracle_install_state_$STATE_TIME"
readonly LOG_DIR="${LOG_BASE_DIR}/oracle_install_$STATE_TIME"
readonly INSTALL_LOG="${LOG_DIR}/install.log"
readonly ERROR_LOG="${LOG_DIR}/error.log"

# 颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 全局变量
INSTALL_MODE="full"  # 默认安装模式:full, check, software-only, database-only, clean

# oracle 内存参数
# 兼容free命令不同版本的输出格式,精准提取total值
PHYS_MEM=$(free -g | grep -E "^Mem:" | awk '{print $2}')
# 检查内存提取结果是否为数字
if ! [[ "$PHYS_MEM" =~ ^[0-9]+$ ]]; then
    echo -e "${RED}错误:提取服务器物理内存失败,请手动执行free -g检查输出!${NC}"
    exit 1
fi
echo -e "${GREEN}✅ 提取服务器物理总内存:${PHYS_MEM}G${NC}"

# 第四步:按比例计算SGA/PGA(整数取整,Oracle不支持小数)
SGA_SIZE=$(( PHYS_MEM * 70 / 100 )) # SGA=70%物理内存
PGA_SIZE=$(( PHYS_MEM * 10 / 100 )) # PGA=10%物理内存
# 边界检查:避免计算后为0(小内存服务器兜底,你的环境不会触发)
if [ $SGA_SIZE -eq 0 ]; then SGA_SIZE=1; fi
if [ $PGA_SIZE -eq 0 ]; then PGA_SIZE=1; fi
# echo -e "${GREEN}✅ 按比例计算结果:SGA=${SGA_SIZE}G(70%),PGA=${PGA_SIZE}G(10%)${NC}"

# ============================================================================
# 工具函数
# ============================================================================

# 打印信息
print_info() {
    echo -e "${GREEN}[INFO] $1${NC}"
}

print_warn() {
    echo -e "${YELLOW}[WARN] $1${NC}"
}

print_error() {
    echo -e "${RED}[ERROR] $1${NC}"
}

print_step() {
    echo -e "${BLUE}[STEP] $1${NC}"
}

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        print_error "此脚本必须以root用户运行"
        exit 1
    fi
}

# 显示使用方法
show_usage() {
    cat << EOF
用法: $0 [选项]

选项:
  --check          只检查安装环境,不进行安装
  --software-only  只安装Oracle软件,不创建数据库
  --database-only  只创建数据库(假设软件已安装)
  --clean          清理卸载Oracle
  --help           显示此帮助信息

示例:
  $0 --check              # 只检查环境
  $0 --software-only      # 只安装软件
  $0 --database-only      # 只创建数据库
  $0 --clean              # 清理卸载
  $0                      # 完整安装

EOF
    exit 0
}

# 解析命令行参数
parse_arguments() {
    if [[ $# -eq 0 ]]; then
        INSTALL_MODE="full"
        return
    fi
    
    case "$1" in
        --check)
            INSTALL_MODE="check"
            ;;
        --software-only)
            INSTALL_MODE="software-only"
            ;;
        --database-only)
            INSTALL_MODE="database-only"
            ;;
        --clean)
            INSTALL_MODE="clean"
            ;;
        --help|-h)
            show_usage
            ;;
        *)
            print_error "未知参数: $1"
            show_usage
            ;;
    esac
}

# ============================================================================
# 核心函数库
# ============================================================================

# 初始化安装环境
init_environment() {
    echo "================================================================"
    echo "开始Oracle 11.2.0.4静默安装"
    echo "================================================================"
    echo "安装模式:           ${INSTALL_MODE}"
    echo "主机名:             ${HOSTNAME}"
    echo "IP地址:             ${IP_ADDRESS}"
    echo "Oracle SID:         ${ORACLE_SID}"
    echo "Oracle基目录:       ${ORACLE_BASE}"
    echo "数据目录:           ${ORACLE_DATA_DIR}"
    echo "安装组件的状态目录:${STATE_DIR}"
    echo "安装日志文件:      ${INSTALL_LOG}"
    echo "安装错误日志文件:  ${ERROR_LOG}"
    echo "================================================================"
    
    # 创建必要的目录
    mkdir -p "${LOG_DIR}"
    mkdir -p "${STATE_DIR}"
    
    # 创建日志文件
    touch "${INSTALL_LOG}" "${ERROR_LOG}"
    
    print_info "初始化完成"
    echo "$(date): 初始化完成" | tee -a "${INSTALL_LOG}"
}

# 记录步骤完成状态
mark_step_completed() {
    local step_name="$1"
    touch "${STATE_DIR}/${step_name}.completed"
    echo "$(date): 步骤 ${step_name} 完成" | tee -a "${INSTALL_LOG}"
}

# 检查步骤是否已完成
check_step_completed() {
    local step_name="$1"
    if [[ -f "${STATE_DIR}/${step_name}.completed" ]]; then
        echo "$(date): 步骤 ${step_name} 已跳过(已完成)" | tee -a "${INSTALL_LOG}"
        return 0
    fi
    return 1
}

# ============================================================================
# 检查函数库
# ============================================================================

# 检查操作系统版本
check_os_version() {
    print_step "检查操作系统版本..."
    
    local os_release="/etc/redhat-release"
    if [[ ! -f "$os_release" ]]; then
        os_release="/etc/os-release"
    fi
    
    if [[ -f "$os_release" ]]; then
        echo "操作系统信息:"
        cat "$os_release" | head -5
    else
        print_warn "无法确定操作系统版本"
    fi
    
    # 检查是否是64位系统
    if [[ $(uname -m) != "x86_64" ]]; then
        print_error "需要64位操作系统"
        exit 1
    fi
    
    print_info "操作系统检查完成"
}

# 检查磁盘空间
check_disk_space() {
    print_step "检查磁盘空间..."
    
    local required_space=10240  # 10GB in MB
    local available_space
    
    # 检查根目录
    available_space=$(df -m / | tail -1 | awk '{print $4}')
    echo "根目录可用空间: ${available_space}MB"
    
    if [[ $available_space -lt $required_space ]]; then
        print_warn "根目录空间不足,建议至少10GB"
    fi
    
    # 检查安装目录
    if [[ -d "$INSTALL_BASE_DIR" ]]; then
        available_space=$(df -m "$INSTALL_BASE_DIR" | tail -1 | awk '{print $4}')
        echo "安装目录可用空间: ${available_space}MB"
    fi
    
    print_info "磁盘空间检查完成"
}

# 检查内存
check_memory() {
    print_step "检查内存..."
    
    local total_mem=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    local mem_gb=$((total_mem / 1024 / 1024))
    
    echo "总内存: ${total_mem}KB (约${mem_gb}GB)"
    
    if [[ $total_mem -lt 2097152 ]]; then  # 小于2GB
        print_warn "内存较小,建议至少2GB"
    fi
    
    print_info "内存检查完成"
}

# 检查Oracle安装文件
check_oracle_software() {
    print_step "检查Oracle安装文件..."
    
    local missing_files=()
    for zip_file in "${ORACLE_ZIP_FILES[@]}"; do
        if [[ ! -f "$zip_file" ]]; then
            missing_files+=("$zip_file")
            print_error "找不到安装文件: $zip_file"
        else
            print_info "找到安装文件: $zip_file"
            local file_size=$(du -h "$zip_file" | awk '{print $1}')
            echo "  文件大小: $file_size"
        fi
    done
    
    if [[ ${#missing_files[@]} -gt 0 ]]; then
        print_error "请将以下文件放置到指定位置:"
        for file in "${missing_files[@]}"; do
            echo "  $file"
        done
        return 1
    fi
    
    print_info "Oracle安装文件检查完成"
    return 0
}

# 检查端口占用
check_ports() {
    print_step "检查端口占用..."
    
    local ports=(1521 5500)
    
    for port in "${ports[@]}"; do
        if netstat -tlnp 2>/dev/null | grep ":$port " > /dev/null; then
            print_warn "端口 $port 已被占用"
            netstat -tlnp | grep ":$port "
        else
            print_info "端口 $port 可用"
        fi
    done
}

# 检查依赖包
check_dependencies() {
    print_step "检查依赖包..."
    
    local required_packages=(
        "binutils" "compat-libcap1" "compat-libstdc++-33"
        "gcc" "gcc-c++" "glibc" "glibc-devel" "ksh"
        "libgcc" "libstdc++" "libstdc++-devel" "libaio"
        "libaio-devel" "libXext" "libXtst" "libX11"
        "libXau" "libxcb" "libXi" "make" "sysstat"
        "unzip" "unixODBC" "unixODBC-devel"
    )
    
    local missing_packages=()
    
    for pkg in "${required_packages[@]}"; do
        if ! rpm -q "$pkg" &>/dev/null; then
            missing_packages+=("$pkg")
            print_warn "缺少包: $pkg"
        else
            print_info "已安装: $pkg"
        fi
    done
    
    if [[ ${#missing_packages[@]} -gt 0 ]]; then
        echo "缺少的依赖包:"
        for pkg in "${missing_packages[@]}"; do
            echo "  $pkg"
        done
        print_warn "可以通过运行完整安装自动安装这些包"
    else
        print_info "所有依赖包已安装"
    fi
}

# 综合环境检查
check_environment() {
    print_step "开始环境检查..."
    
    check_root
    check_os_version
    check_disk_space
    check_memory
    check_oracle_software
    check_ports
    check_dependencies
    
    print_step "环境检查完成"
    echo ""
    echo "检查结果摘要:"
    echo "  操作系统: 通过"
    echo "  磁盘空间: 通过"
    echo "  内存: 通过"
    echo "  安装文件: 通过"
    echo "  端口: 通过"
    echo "  依赖包: 部分可能需要安装"
    echo ""
    echo "可以运行完整安装或使用 '--software-only' 开始安装软件"
}

# ============================================================================
# 安装函数库
# ============================================================================

# 安装并检查依赖包
install_dependencies() {
    if check_step_completed "install_dependencies"; then
        return 0
    fi
    
    print_step "开始安装依赖包..."
    
    # 基本依赖包
    local base_packages=(
        "binutils" "compat-libcap1" "compat-libstdc++-33"
        "gcc" "gcc-c++" "glibc" "glibc-devel" "ksh"
        "libgcc" "libstdc++" "libstdc++-devel" "libaio"
        "libaio-devel" "libXext" "libXtst" "libX11"
        "libXau" "libxcb" "libXi" "make" "sysstat"
        "unzip" "unixODBC" "unixODBC-devel"
    )
    
    # 检查并安装缺失的包
    for pkg in "${base_packages[@]}"; do
        if ! rpm -q "$pkg" &>/dev/null; then
            echo "$(date): 安装包: $pkg" | tee -a "${INSTALL_LOG}"
            yum -y install "$pkg" >> "${INSTALL_LOG}" 2>&1 || {
                echo "$(date): 警告: 包 $pkg 安装失败" | tee -a "${INSTALL_LOG}"
            }
        else
            echo "$(date): 包 $pkg 已安装" | tee -a "${INSTALL_LOG}"
        fi
    done
    
    mark_step_completed "install_dependencies"
    print_info "依赖包安装完成"
}

# 清理共享内存和信号量
clean_oracle_ipc() {
    print_step "清理Oracle共享内存和信号量..."
    
    # 1. 清理共享内存
    echo "检查Oracle共享内存段..."
    local shm_segments=$(ipcs -m | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$shm_segments" ]]; then
        print_info "找到Oracle共享内存段,正在清理..."
        for shm_id in $shm_segments; do
            print_info "删除共享内存段: $shm_id"
            ipcrm -m "$shm_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle共享内存段"
    fi
    
    # 2. 清理信号量
    echo "检查Oracle信号量..."
    local sem_ids=$(ipcs -s | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$sem_ids" ]]; then
        print_info "找到Oracle信号量,正在清理..."
        for sem_id in $sem_ids; do
            print_info "删除信号量: $sem_id"
            ipcrm -s "$sem_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle信号量"
    fi
    
    # 3. 清理消息队列
    echo "检查Oracle消息队列..."
    local msg_ids=$(ipcs -q | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$msg_ids" ]]; then
        print_info "找到Oracle消息队列,正在清理..."
        for msg_id in $msg_ids; do
            print_info "删除消息队列: $msg_id"
            ipcrm -q "$msg_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle消息队列"
    fi
    
    # 4. 清理/dev/shm中的Oracle文件
    echo "检查/dev/shm中的Oracle文件..."
    if [[ -d "/dev/shm" ]]; then
        local shm_files=$(ls -la /dev/shm | grep -E "(ora_|.ora_|sem\.)" | awk '{print $9}')
        if [[ -n "$shm_files" ]]; then
            print_info "清理/dev/shm中的Oracle文件..."
            for file in $shm_files; do
                if [[ -f "/dev/shm/$file" ]]; then
                    print_info "删除: /dev/shm/$file"
                    rm -f "/dev/shm/$file"
                fi
            done
        fi
    fi
    
    print_info "IPC资源清理完成"
}


# 安全杀死进程的函数
# 参数1:进程PID
# 参数2:要发送的信号(如15=SIGTERM 正常终止,9=SIGKILL 强制终止)
safe_kill_process() {
    local pid="$1"
    local signal="$2"
    
    # 校验参数:PID和信号不能为空,且PID为数字
    if [[ -z "$pid" || -z "$signal" || ! "$pid" =~ ^[0-9]+$ ]]; then
        print_info "无效的进程PID或信号值:PID=$pid, 信号=$signal"
        return 1
    fi

    # 检查进程是否存在
    if ps -p "$pid" >/dev/null 2>&1; then
        print_info "向进程$pid发送信号$signal..."
        # 发送信号,重定向错误输出避免无权限时的冗余报错
        kill -"$signal" "$pid" >/dev/null 2>&1
        # 检查信号是否发送成功
        if [[ $? -eq 0 ]]; then
            print_info "进程$pid已发送信号$signal"
        else
            print_info "向进程$pid发送信号$signal失败(可能无权限)"
        fi
    else
        print_info "进程$pid不存在,无需发送信号"
    fi
    
    return 0
}

# 检查并清理所有Oracle进程
force_kill_oracle() {
    print_step "强制清理所有Oracle相关进程..."
    
    # 1. 停止监听器
    if [[ -f "${ORACLE_HOME}/bin/lsnrctl" ]]; then
        print_info "停止监听器..."
        su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            ${ORACLE_HOME}/bin/lsnrctl stop 2>/dev/null || true
        " 2>/dev/null || true
    fi
    
    # 2. 停止数据库
    if [[ -f "${ORACLE_HOME}/bin/sqlplus" ]]; then
        print_info "停止数据库..."
        su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            export ORACLE_SID=${ORACLE_SID}
            echo 'shutdown abort;' | ${ORACLE_HOME}/bin/sqlplus -S / as sysdba 2>/dev/null || true
        " 2>/dev/null || true
    fi
    
    # 3. 安全的杀死Oracle进程
    print_info "安全地清理Oracle进程..."
    
    # 查找Oracle后台进程
    ps -ef | while read -r line; do
        # 跳过标题行
        if [[ "$line" == *"PID"* ]]; then
            continue
        fi
        
        local pid=$(echo "$line" | awk '{print $2}')
        local user=$(echo "$line" | awk '{print $1}')
        local command=$(echo "$line" | awk '{$1=$2=$3=$4=$5=$6=$7=""; print $0}')
        
        # 只处理oracle用户的进程
        if [[ "$user" == "$ORACLE_USER" ]] || [[ "$user" == "oracle" ]]; then
            # 检查是否是Oracle相关进程
            if echo "$command" | grep -qE "(ora_|asm_|ocssd|diskmon|tnslsnr)"; then
                safe_kill_process "$pid" 15  # 先尝试正常终止
                sleep 0.5
                safe_kill_process "$pid" 9   # 再强制终止
            fi
        fi
    done
    
    # 4. 额外清理:确保没有残留的Oracle进程
    print_info "检查是否有残留的Oracle进程..."
    
    # 等待一会儿让进程完全终止
    sleep 2
    
    # 再次检查并强制清理
    local remaining_processes=$(ps -u "$ORACLE_USER" -o pid= 2>/dev/null | grep -v "^$$\$")
    if [[ -n "$remaining_processes" ]]; then
        print_info "仍有进程残留,强制清理..."
        for pid in $remaining_processes; do
            safe_kill_process "$pid" 9
        done
    fi
    
    # 等待进程完全结束
    sleep 1
    
    print_info "进程清理完成"
}

# 停止Oracle用户的所有进程
stop_oracle_processes() {
    print_step "检查Oracle用户进程..."
    
    # 先强制清理所有Oracle进程
    force_kill_oracle
    
    # 检查是否有oracle用户的进程
    if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
        print_info "找到Oracle用户进程,正在停止..."
        
        # 尝试优雅停止
        pkill -u "$ORACLE_USER"
        sleep 2
        
        # 如果仍有进程,强制停止
        if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
            print_warn "仍有进程运行,强制停止..."
            pkill -9 -u "$ORACLE_USER"
            sleep 1
        fi
        
        # 最终检查
        if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
            print_error "无法停止所有Oracle进程,请手动检查"
            echo "运行以下命令查看进程:ps -ef | grep $ORACLE_USER"
            return 1
        else
            print_info "所有Oracle进程已停止"
        fi
    else
        print_info "未找到Oracle用户进程"
    fi
    
    # 清理IPC资源
    clean_oracle_ipc
    
    return 0
}

# 删除Oracle用户
delete_oracle_user() {
    print_step "检查用户 $ORACLE_USER 是否存在..."
    
    if id "$ORACLE_USER" >/dev/null 2>&1; then
        print_info "删除用户 $ORACLE_USER..."
        
        # 先删除用户的主目录
        if [[ -d "/home/$ORACLE_USER" ]]; then
            rm -rf "/home/$ORACLE_USER"
            print_info "已删除目录 /home/$ORACLE_USER"
        fi
        
        # 删除用户
        userdel "$ORACLE_USER"
        
        if [[ $? -eq 0 ]]; then
            print_info "用户 $ORACLE_USER 已删除"
        else
            print_warn "删除用户 $ORACLE_USER 失败"
        fi
    else
        print_info "用户 $ORACLE_USER 不存在"
    fi
}

# 删除Oracle相关组
delete_oracle_groups() {
    local groups=("$ORACLE_DBA_GROUP" "$ORACLE_OPER_GROUP" "$ORACLE_PRIMARY_GROUP")
    
    for group in "${groups[@]}"; do
        print_step "检查组 $group 是否存在..."
        
        if getent group "$group" >/dev/null 2>&1; then
            print_info "删除组 $group..."
            groupdel "$group"
            
            if [[ $? -eq 0 ]]; then
                print_info "组 $group 已删除"
            else
                print_warn "删除组 $group 失败"
            fi
        else
            print_info "组 $group 不存在"
        fi
    done
}

# 清理安装软件、数据目录、/tmp目录下的Oracle临时文件
clean_tmp_directories() {
    print_step "清理/tmp目录下的Oracle临时文件..."
    
    local tmp_dirs=(
        "/tmp/CVU_11.2.0.4.0_oracle"
        "/tmp/dbca"
        "/tmp/hsperfdata_oracle"
        "/tmp/.oracle"
        "/tmp/CVU*"
        "/etc/oratab"
        "/etc/oraInst.loc"
        "$INSTALL_BASE_DIR"
        "$SOFTWARE_BASE_DIR/software"
        "$DATA_BASE_DIR"
    )
    
    for dir in "${tmp_dirs[@]}"; do
        # 使用find处理通配符
        if [[ "$dir" == *"*"* ]]; then
            for expanded_dir in $dir; do
                if [[ -d "$expanded_dir" || -f "$expanded_dir" ]]; then
                    print_info "删除 $expanded_dir..."
                    rm -rf "$expanded_dir"
                fi
            done
        elif [[ -d "$dir" || -f "$dir" ]]; then
            print_info "删除 $dir..."
            rm -rf "$dir"
        fi
    done
    
    print_info "装软件、数据目录、/tmp目录清理完成"
}

# 清理安装
clean_installation() {
    print_step "开始清理Oracle安装..."
    
    # 确认操作
    read -p "确认要清理卸载Oracle吗?(yes/no): " confirm
    if [[ "${confirm}" != "yes" ]]; then
        print_info "用户取消清理操作"
        return 0
    fi
    
    # 停止进程
    stop_oracle_processes
    
    # 删除用户和组
    delete_oracle_user
    delete_oracle_groups
    
    # 清理目录
    clean_tmp_directories
    
    # 清理环境变量
    local bash_profile="/home/${ORACLE_USER}/.bash_profile"
    if [[ -f "$bash_profile" ]]; then
        print_step "清理环境变量..."
        sed -i '/# Oracle环境变量/,/^[^#]/d' "$bash_profile" 2>/dev/null
        sed -i '/export ORACLE_/d' "$bash_profile" 2>/dev/null
    fi
    
    print_info "Oracle清理完成"
}

# 创建Oracle用户和组
create_oracle_user() {
    if check_step_completed "create_oracle_user"; then
        return 0
    fi
    
    print_step "创建Oracle用户和组..."
    
    # 检查并创建组
    if ! getent group "${ORACLE_PRIMARY_GROUP}" >/dev/null; then
        groupadd "${ORACLE_PRIMARY_GROUP}"
        print_info "创建组: ${ORACLE_PRIMARY_GROUP}"
    fi
    
    if ! getent group "${ORACLE_DBA_GROUP}" >/dev/null; then
        groupadd "${ORACLE_DBA_GROUP}"
        print_info "创建组: ${ORACLE_DBA_GROUP}"
    fi
    
    if ! getent group "${ORACLE_OPER_GROUP}" >/dev/null; then
        groupadd "${ORACLE_OPER_GROUP}"
        print_info "创建组: ${ORACLE_OPER_GROUP}"
    fi
    
    # 检查并创建用户
    if ! id "${ORACLE_USER}" >/dev/null 2>&1; then
        useradd -g "${ORACLE_PRIMARY_GROUP}" \
                -G "${ORACLE_DBA_GROUP},${ORACLE_OPER_GROUP}" \
                "${ORACLE_USER}"
        echo "${ORACLE_USER}:${ORACLE_PASSWORD}" | chpasswd
        print_info "创建用户: ${ORACLE_USER}"
    else
        print_info "用户 ${ORACLE_USER} 已存在"
    fi
    
    mark_step_completed "create_oracle_user"
}

# 配置内核参数
configure_kernel_parameters() {
    if check_step_completed "configure_kernel_parameters"; then
        return 0
    fi
    
    print_step "配置内核参数..."
    
    # 检查是否已配置
    local kernel_params_configured=false
    if grep -q "Oracle内核参数配置" /etc/sysctl.conf; then
        print_info "内核参数已配置,跳过"
        kernel_params_configured=true
    fi
    
    if [[ "$kernel_params_configured" == "false" ]]; then
        # 计算共享内存大小
        local total_mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
        local shmmax=$((total_mem_kb * 1024 * 80 / 100))  # 80% of total memory
        local shmall=$((shmmax / 4096))
        
        cat >> /etc/sysctl.conf << EOF

# Oracle内核参数配置
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.shmall = ${shmall}
kernel.shmmax = ${shmmax}
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
EOF
        
        print_info "内核参数配置已写入 /etc/sysctl.conf"
    fi
    
    # 应用内核参数
    sysctl -p >> "${INSTALL_LOG}" 2>&1
    print_info "内核参数已应用"
    
    mark_step_completed "configure_kernel_parameters"
}

# 配置用户资源限制
configure_user_limits() {
    if check_step_completed "configure_user_limits"; then
        return 0
    fi
    
    print_step "配置用户资源限制..."
    
    # 检查是否已配置
    if ! grep -q "Oracle用户资源限制" /etc/security/limits.conf; then
        cat >> /etc/security/limits.conf << EOF

# Oracle用户资源限制
${ORACLE_USER} soft nproc 2047
${ORACLE_USER} hard nproc 16384
${ORACLE_USER} soft nofile 1024
${ORACLE_USER} hard nofile 65536
${ORACLE_USER} soft stack 10240
EOF
        print_info "用户资源限制已配置"
    else
        print_info "用户资源限制已存在,跳过"
    fi
    
    # 配置pam.d
    if ! grep -q "pam_limits.so" /etc/pam.d/login; then
        echo "session required pam_limits.so" >> /etc/pam.d/login
    fi
    
    mark_step_completed "configure_user_limits"
}

# 创建Oracle目录结构
create_oracle_directories() {
    if check_step_completed "create_oracle_directories"; then
        return 0
    fi
    
    print_step "创建Oracle目录结构..."
    
    # 创建主目录
    local dirs=(
        "${INSTALL_BASE_DIR}"
        "${DATA_BASE_DIR}"
        "${SOFTWARE_BASE_DIR}"
        "${ORACLE_BASE}"
        "${ORACLE_HOME}"
        "${ORACLE_INVENTORY}"
        "${ORACLE_DATA_DIR}"
        "${ORACLE_SOFTWARE_DIR}"
    )
    
    for dir in "${dirs[@]}"; do
        if [[ ! -d "$dir" ]]; then
            mkdir -p "$dir"
            print_info "创建目录: $dir"
        fi
    done
    
    # 创建数据子目录
    local data_subdirs=(
        "oradata"
        "archivelog"
        "redo"
        "standby"
        "backup/dump"
        "backup/rman"
        "flash_recovery_area"
    )
    
    for subdir in "${data_subdirs[@]}"; do
        local full_dir="${ORACLE_DATA_DIR}/${subdir}"
        if [[ ! -d "$full_dir" ]]; then
            mkdir -p "$full_dir"
            print_info "创建数据目录: $full_dir"
        fi
    done
    
    # 设置权限
    chown -R "${ORACLE_USER}:${ORACLE_PRIMARY_GROUP}" "${INSTALL_BASE_DIR}" "${DATA_BASE_DIR}" "${SOFTWARE_BASE_DIR}"
    chmod -R 775 "${INSTALL_BASE_DIR}" "${DATA_BASE_DIR}" "${SOFTWARE_BASE_DIR}"
    
    print_info "目录权限已设置"
    
    mark_step_completed "create_oracle_directories"
}

# 配置Oracle环境变量
configure_oracle_env() {
    if check_step_completed "configure_oracle_env"; then
        return 0
    fi
    
    print_step "配置Oracle环境变量..."
    
    local bash_profile="/home/${ORACLE_USER}/.bash_profile"
    
    # 备份现有配置
    if [[ -f "$bash_profile" ]]; then
        cp "$bash_profile" "${bash_profile}.backup.$(date +%Y%m%d)"
    fi
    
    # 添加Oracle环境变量
    cat >> "$bash_profile" << EOF

# Oracle环境变量
export ORACLE_BASE=${ORACLE_BASE}
export ORACLE_HOME=${ORACLE_HOME}
export ORACLE_SID=${ORACLE_SID}
export ORACLE_UNQNAME=${ORACLE_SID}
export PATH=\$ORACLE_HOME/bin:\$PATH
export LD_LIBRARY_PATH=\$ORACLE_HOME/lib:/lib:/usr/lib
export CLASSPATH=\$ORACLE_HOME/jlib:\$ORACLE_HOME/rdbms/jlib
export NLS_LANG=AMERICAN_AMERICA.${ORACLE_CHARSET}
export TMP=/tmp
export TMPDIR=\$TMP
umask 022
EOF
    
    # 应用环境变量
    chown "${ORACLE_USER}:${ORACLE_PRIMARY_GROUP}" "$bash_profile"
    
    print_info "Oracle环境变量已配置"
    
    mark_step_completed "configure_oracle_env"
}

# 解压Oracle软件
extract_oracle_software() {
    if check_step_completed "extract_oracle_software"; then
        return 0
    fi
    
    print_step "解压Oracle软件..."
    
    # 检查是否已解压
    if [[ -d "${ORACLE_SOFTWARE_DIR}/database" ]]; then
        print_info "Oracle软件已解压,跳过此步骤"
        mark_step_completed "extract_oracle_software"
        return 0
    fi
    
    # 解压安装包
    for zip_file in "${ORACLE_ZIP_FILES[@]}"; do
        print_info "解压文件: $(basename "$zip_file")"
        unzip -q -d "${ORACLE_SOFTWARE_DIR}" "$zip_file" >> "${INSTALL_LOG}" 2>&1
        if [[ $? -ne 0 ]]; then
            print_error "解压失败: $zip_file"
            exit 1
        fi
    done
    
    # 验证解压结果
    if [[ ! -f "${ORACLE_SOFTWARE_DIR}/database/runInstaller" ]]; then
        print_error "解压后找不到runInstaller"
        exit 1
    fi
    
    print_info "Oracle软件解压完成"
    
    mark_step_completed "extract_oracle_software"
}

# 准备响应文件
prepare_response_files() {
    if check_step_completed "prepare_response_files"; then
        return 0
    fi
    
    print_step "准备响应文件..."
    
    local db_install_rsp="${ORACLE_SOFTWARE_DIR}/database/response/db_install.rsp"
    local dbca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/dbca.rsp"
    local netca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/netca.rsp"
    
    # 复制响应文件模板
    if [[ ! -f "${db_install_rsp}.template" ]]; then
        cp "$db_install_rsp" "${db_install_rsp}.template"
    fi
    
    if [[ ! -f "${dbca_rsp}.template" ]]; then
        cp "$dbca_rsp" "${dbca_rsp}.template"
    fi
    
    # 修改db_install.rsp
    sed -i \
        -e "s|^oracle.install.option=$|oracle.install.option=INSTALL_DB_SWONLY|" \
        -e "s|^UNIX_GROUP_NAME=$|UNIX_GROUP_NAME=${ORACLE_PRIMARY_GROUP}|" \
        -e "s|^INVENTORY_LOCATION=$|INVENTORY_LOCATION=${ORACLE_INVENTORY}|" \
        -e "s|^ORACLE_HOME=$|ORACLE_HOME=${ORACLE_HOME}|" \
        -e "s|^ORACLE_BASE=$|ORACLE_BASE=${ORACLE_BASE}|" \
        -e "s|^oracle.install.db.InstallEdition=$|oracle.install.db.InstallEdition=EE|" \
        -e "s|^oracle.install.db.DBA_GROUP=$|oracle.install.db.DBA_GROUP=${ORACLE_DBA_GROUP}|" \
        -e "s|^oracle.install.db.OPER_GROUP=$|oracle.install.db.OPER_GROUP=${ORACLE_OPER_GROUP}|" \
        -e "s|^DECLINE_SECURITY_UPDATES=$|DECLINE_SECURITY_UPDATES=true|" \
        -e "s|^SECURITY_UPDATES_VIA_MYORACLESUPPORT=$|SECURITY_UPDATES_VIA_MYORACLESUPPORT=false|" \
        "$db_install_rsp" 
    local setp_status=$?
    
    if [[ $setp_status -eq 0 ]];then
        print_info "响应文件准备完成:$db_install_rsp"
    else
        print_error "响应文件:$db_install_rsp 配置失败,退出"
        exit 1
    fi 

    # 修改dbca.rsp
    sed -i \
       -e "s|^GDBNAME = \"orcl11g.us.oracle.com\"|GDBNAME = \"${ORACLE_SID}\"|"  \
       -e "s|^SID = \"orcl11g\"|SID = \"${ORACLE_SID}\"|"  \
       -e "s|#SYSPASSWORD = \"password\"|SYSPASSWORD = \"oracle\"|"  \
       -e "s|#SYSTEMPASSWORD = \"password\"|SYSTEMPASSWORD = \"oracle\"|"  \
       -e "s|#EMCONFIGURATION = \"NONE\"|EMCONFIGURATION = \"NONE\"|"  \
       -e "s|#SYSMANPASSWORD = \"password\"|SYSMANPASSWORD = \"oracle\"|"  \
       -e "s|#DBSNMPPASSWORD = \"password\"|DBSNMPPASSWORD = \"oracle\"|"  \
       -e "s|#CHARACTERSET = \"US7ASCII\"|CHARACTERSET = \"ZHS16GBK\"|"  \
       -e "s|#MEMORYPERCENTAGE = \"40\"|MEMORYPERCENTAGE = \"70\"|"  \
       "$dbca_rsp"
    setp_status=$?
    
    if [[ $setp_status -eq 0 ]];then
        print_info "响应文件准备完成:$dbca_rsp"
    else
        print_error "响应文件:$dbca_rsp 配置失败,退出"
        exit 1
    fi
    
    mark_step_completed "prepare_response_files"
}

# 安装Oracle软件
install_oracle_software() {
    if check_step_completed "install_oracle_software"; then
        return 0
    fi
    
    print_step "开始安装Oracle软件..."
    
    local db_install_rsp="${ORACLE_SOFTWARE_DIR}/database/response/db_install.rsp"
    
    # 检查是否已安装
    if [[ -f "${ORACLE_HOME}/bin/oracle" ]]; then
        print_info "Oracle软件已安装,跳过此步骤"
        mark_step_completed "install_oracle_software"
        return 0
    fi
    
    # 以oracle用户身份安装
    print_info "执行安装命令..."
    su - "${ORACLE_USER}" -c "
        cd '${ORACLE_SOFTWARE_DIR}/database'
        ./runInstaller -silent -waitforcompletion -ignoreSysPrereqs \
        -responseFile '${db_install_rsp}' \
        -ignorePrereq -showProgress
    " >> "${INSTALL_LOG}" 2>&1
    
    local install_result=$?
    
    if [[ $install_result -eq 0 ]]; then
        print_info "Oracle软件安装成功"
        
        # 执行root脚本
        if [[ -f "${ORACLE_INVENTORY}/orainstRoot.sh" ]]; then
            print_info "执行orainstRoot.sh"
            "${ORACLE_INVENTORY}/orainstRoot.sh" >> "${INSTALL_LOG}" 2>&1
        fi
        
        if [[ -f "${ORACLE_HOME}/root.sh" ]]; then
            print_info "执行root.sh"
            "${ORACLE_HOME}/root.sh" >> "${INSTALL_LOG}" 2>&1
        fi
    else
        print_error "Oracle软件安装失败,退出码: $install_result"
        print_error "请检查日志文件: ${INSTALL_LOG}"
        exit 1
    fi
    
    mark_step_completed "install_oracle_software"
}

# 配置监听器
configure_listener() {
    if check_step_completed "configure_listener"; then
        return 0
    fi
    
    print_step "配置监听器..."
    
    # 创建listener.ora
    cat > "${ORACLE_HOME}/network/admin/listener.ora" << EOF
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = ${HOSTNAME})(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = ${ORACLE_SID})
      (ORACLE_HOME = ${ORACLE_HOME})
      (SID_NAME = ${ORACLE_SID})
    )
  )
EOF
    
    # 创建tnsnames.ora
    cat > "${ORACLE_HOME}/network/admin/tnsnames.ora" << EOF
${ORACLE_SID} =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = ${HOSTNAME})(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ${ORACLE_SID})
    )
  )
EOF
    
    # 设置权限
    chown -R "${ORACLE_USER}:${ORACLE_DBA_GROUP}" "${ORACLE_HOME}/network/admin"
    
    # 启动监听器
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl stop >> /dev/null 2>&1
        lsnrctl start
    " >> "${INSTALL_LOG}" 2>&1
    
    print_info "监听器配置完成"
    
    mark_step_completed "configure_listener"
}

# 检查数据库是否已存在
check_database_existence() {
    print_step "检查数据库实例是否存在..."
    
    local db_status="NOT_EXIST"
    
    # 方法1: 检查参数文件
    local param_files=(
        "${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora"
        "${ORACLE_HOME}/dbs/init${ORACLE_SID}.ora"
    )
    
    # 方法2: 检查进程
    local pmon_process=$(ps -ef | grep -v grep | grep ora_pmon_${ORACLE_SID} 2>/dev/null)
    
    for param_file in "${param_files[@]}"; do
        if [[ -f "$param_file" ]]; then
            print_warn "找到参数文件: $param_file"
            db_status="PARAM_EXISTS"
            break
        fi
    done
    
    if [[ -n "$pmon_process" ]]; then
        print_warn "找到数据库进程 ora_pmon_${ORACLE_SID}"
        db_status="RUNNING"
    fi
    
    if [[ "$db_status" != "NOT_EXIST" ]]; then
        echo "================================================"
        print_warn "数据库实例 ${ORACLE_SID} 可能已存在!"
        echo "当前状态: $db_status"
        echo ""
        echo "如果要重新安装,请执行以下操作:"
        echo "1. 备份现有数据"
        echo "2. 停止数据库: sqlplus / as sysdba <<< 'shutdown immediate'"
        echo "3. 删除相关文件"
        echo "================================================"
        
        read -p "是否继续创建数据库?(yes/no): " -t 30 confirm_db
        if [[ "${confirm_db}" != "yes" ]]; then
            print_info "用户取消数据库创建"
            return 1
        fi
    fi
    
    return 0
}

# 创建数据库
create_database() {
    if check_step_completed "create_database"; then
        return 0
    fi
    
    print_step "开始创建数据库..."
    
    # 检查数据库是否已存在
    if ! check_database_existence; then
        return 1
    fi
    
    local dbca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/dbca.rsp"
    
    # 修改数据库安装模板
    if [[ -f "$ORACLE_General_Purpose" ]]; then
        sed -i "s#{ORACLE_BASE}/oradata/{DB_UNIQUE_NAME}#$ORACLE_DATA_DIR/oradata#g" "$ORACLE_General_Purpose"
        print_info "$ORACLE_General_Purpose 已经修改完成"
    fi

    # 创建数据库
    print_info "使用dbca创建数据库实例..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        dbca -silent -responseFile '${dbca_rsp}'
    " >> "${INSTALL_LOG}" 2>&1
    
    local dbca_result=$?
    
    if [[ $dbca_result -eq 0 ]]; then
        print_info "数据库创建成功"
        
        # 等待数据库完全启动
        sleep 30
        
        # 验证数据库状态
        if su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            export ORACLE_SID=${ORACLE_SID}
            export PATH=\${ORACLE_HOME}/bin:\${PATH}
            sqlplus -S / as sysdba << 'SQL'
            SELECT 'DATABASE_STATUS:' || status FROM v\\\$instance;
            exit;
SQL
        " | grep -q "DATABASE_STATUS:OPEN"; then
            print_info "数据库已成功打开"
        else
            print_warn "数据库可能未完全启动"
        fi
    else
        print_error "数据库创建失败,退出码: $dbca_result"
        exit 1
    fi
    
    mark_step_completed "create_database"
}

# 配置数据库参数
configure_database_parameters() {
    if check_step_completed "configure_database_parameters"; then
        return 0
    fi
    
    print_step "配置数据库参数..."
    
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus / as sysdba << 'SQL'
        -- 启用归档模式
        SHUTDOWN IMMEDIATE;
        STARTUP MOUNT;
        ALTER DATABASE ARCHIVELOG;
        ALTER DATABASE OPEN;
        
        -- 设置归档目录
        ALTER SYSTEM SET log_archive_dest_1='location=${ORACLE_DATA_DIR}/archivelog' SCOPE=SPFILE;
        
        -- 调整内存参数
        ALTER SYSTEM SET sga_target=${SGA_SIZE}G SCOPE=SPFILE;
        ALTER SYSTEM SET pga_aggregate_target=${PGA_SIZE}G SCOPE=SPFILE;
        
        -- 调整其他参数
        ALTER SYSTEM SET processes=1000 SCOPE=SPFILE;
        ALTER SYSTEM SET open_cursors=300 SCOPE=SPFILE;
        ALTER SYSTEM SET session_cached_cursors=100 SCOPE=SPFILE;
        ALTER SYSTEM SET db_files=2000 SCOPE=SPFILE;
        -- 重启使参数生效
        SHUTDOWN IMMEDIATE;
        STARTUP;
        
        -- 创建pfile备份
        CREATE PFILE='${ORACLE_HOME}/dbs/init${ORACLE_SID}.ora' FROM SPFILE;
        
        exit;
SQL
    " >> "${INSTALL_LOG}" 2>&1
    
    print_info "数据库参数配置完成"
    
    mark_step_completed "configure_database_parameters"
}

# ============================================================================
# 验证函数库
# ============================================================================

# 增强验证安装
enhanced_validate_installation() {
    print_step "增强验证Oracle安装..."
    
    # 检查关键文件
    local critical_files=(
        "${ORACLE_HOME}/bin/oracle"
        "${ORACLE_HOME}/bin/sqlplus"
        "${ORACLE_HOME}/network/admin/listener.ora"
        "${ORACLE_HOME}/network/admin/tnsnames.ora"
        "${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora"
    )
    
    print_info "检查关键文件..."
    for file in "${critical_files[@]}"; do
        if [[ -f "$file" ]]; then
            print_info "✓ $file 存在"
        else
            print_warn "✗ $file 不存在"
        fi
    done
    
    # 检查Oracle用户环境
    print_info "检查Oracle用户环境..."
    su - "${ORACLE_USER}" -c "
        echo 'ORACLE_HOME: \$ORACLE_HOME'
        echo 'ORACLE_SID: \$ORACLE_SID'
        echo 'PATH包含ORACLE_HOME: \$(echo \$PATH | grep \$ORACLE_HOME)'
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 检查监听器状态
    print_info "检查监听器状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl status 2>&1 | grep -A 5 -B 2 \"STATUS\"
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 检查数据库状态
    print_info "检查数据库状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << EOF
        set pagesize 0 linesize 100 feedback off
        select 'DB_NAME: '||name from v\\\$database;
        select 'DB_STATUS: '||status from v\\\$instance;
        select 'OPEN_MODE: '||open_mode from v\\\$database;
        select 'CONTROLFILE: '||name from v\\\$controlfile;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 测试监听器连接
    print_info "测试监听器连接..."
    tnsping_result=$(su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        tnsping ${ORACLE_SID} 2>&1
    " | grep "OK")
    
    if [[ -n "$tnsping_result" ]]; then
        print_info "✓ 监听器连接正常"
    else
        print_warn "✗ 监听器连接失败"
    fi
    
    print_info "增强验证完成"
}

# 验证安装
validate_installation() {
    print_step "验证Oracle安装..."
    
    # 1. 检查监听器
    print_info "检查监听器状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl status 2>&1 | grep -A 5 -B 2 \"STATUS\"
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 2. 检查数据库状态
    print_info "检查数据库状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << EOF
        set pagesize 0 linesize 100 feedback off
        select 'DB_NAME: '||name from v\\\$database;
        select 'DB_STATUS: '||status from v\\\$instance;
        select 'OPEN_MODE: '||open_mode from v\\\$database;
        select 'CONTROLFILE: '||name from v\\\$controlfile;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 3. 检查表空间
    print_info "检查表空间..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << 'EOF'
        set pagesize 0 linesize 100 feedback off
        col \"Tablespace\" format a20
        col \"Used %\" format a10
        select tablespace_name \"Tablespace\",
               round(used_percent,2)||'%' \"Used %\"
        from dba_tablespace_usage_metrics
        order by tablespace_name;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 4. 检查数据文件
    print_info "检查数据文件..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << 'EOF'
        set pagesize 0 linesize 150 feedback off
        col \"Datafile\" format a60
        col \"Size(MB)\" format 999999
        select file_name \"Datafile\", 
               round(bytes/1024/1024) \"Size(MB)\"
        from dba_data_files
        order by tablespace_name, file_id;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    print_info "Oracle安装验证完成"
}

# ============================================================================
# 显示函数库
# ============================================================================

# 显示安装摘要
show_summary() {
    cat << EOF

===============================================================
Oracle 11.2.0.4 安装完成!
===============================================================
安装模式: ${INSTALL_MODE}
安装信息:
  主机名: ${HOSTNAME}
  Oracle SID: ${ORACLE_SID}
  字符集: ${ORACLE_CHARSET}
  数据库内存:按比例计算结果:SGA=${SGA_SIZE}G(70%),PGA=${PGA_SIZE}G(10%)

连接信息:
  监听端口: 1521
  系统用户: sys/${SYS_PASSWORD}
  系统用户: system/${SYSTEM_PASSWORD}

目录结构:
  ORACLE_BASE: ${ORACLE_BASE}
  ORACLE_HOME: ${ORACLE_HOME}
  数据文件: ${ORACLE_DATA_DIR}/oradata
  归档日志: ${ORACLE_DATA_DIR}/archivelog
  备份目录: ${ORACLE_DATA_DIR}/backup

验证步骤:
  1. 检查监听器: lsnrctl status
  2. 连接数据库: sqlplus system/${SYSTEM_PASSWORD}@${ORACLE_SID}
  3. 查看状态: SELECT name, open_mode FROM v\\\$database;

日志文件:
  安装日志: ${INSTALL_LOG}
  错误日志: ${ERROR_LOG}
===============================================================
EOF
}

# ============================================================================
# 安装流程函数
# ============================================================================

# 完整安装流程
install_full() {
    print_step "开始完整安装Oracle..."
    
    local install_steps=(
        "stop_oracle_processes"
        "install_dependencies"
        "create_oracle_user"
        "configure_kernel_parameters"
        "configure_user_limits"
        "create_oracle_directories"
        "configure_oracle_env"
        "extract_oracle_software"
        "prepare_response_files"
        "install_oracle_software"
        "configure_listener"
        "create_database"
        "configure_database_parameters"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    # 验证安装
    enhanced_validate_installation
    
    # 显示摘要
    show_summary
    
    print_info "Oracle完整安装完成"
}

# 只安装软件
install_software_only() {
    print_step "开始只安装Oracle软件..."
    
    local install_steps=(
        "stop_oracle_processes"
        "install_dependencies"
        "create_oracle_user"
        "configure_kernel_parameters"
        "configure_user_limits"
        "create_oracle_directories"
        "configure_oracle_env"
        "extract_oracle_software"
        "prepare_response_files"
        "install_oracle_software"
        "configure_listener"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    print_info "Oracle软件安装完成"
    echo ""
    echo "软件安装完成,可以运行以下命令创建数据库:"
    echo "  1. 切换到oracle用户: su - oracle"
    echo "  2. 创建数据库: dbca -silent -createDatabase -templateName General_Purpose.dbc ..."
    echo "  或运行完整安装: $0 --database-only"
}

# 只创建数据库
install_database_only() {
    print_step "开始只创建数据库..."
    
    # 验证软件是否已安装
    if [[ ! -f "${ORACLE_HOME}/bin/oracle" ]]; then
        print_error "Oracle软件未安装,请先安装软件"
        echo "运行: $0 --software-only"
        exit 1
    fi
    
    local install_steps=(
        "configure_listener"
        "create_database"
        "configure_database_parameters"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    # 验证安装
    validate_installation
    
    print_info "数据库创建完成"
}

# ============================================================================
# 主控制函数
# ============================================================================

main() {
    # 解析命令行参数
    parse_arguments "$@"
    
    # 检查root权限
    check_root
    
    # 初始化环境
    init_environment
    
    # 根据模式执行不同操作
    case "$INSTALL_MODE" in
        "check")
            check_environment
            ;;
        "software-only")
            # 确认继续
            read -p "是否继续安装Oracle软件? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_software_only
            ;;
        "database-only")
            # 确认继续
            read -p "是否继续创建数据库? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_database_only
            ;;
        "clean")
            clean_installation
            ;;
        "full")
            # 检查Oracle软件
            if ! check_oracle_software; then
                exit 1
            fi
            
            # 确认继续
            read -p "是否继续完整安装? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_full
            ;;
        *)
            print_error "未知的安装模式: $INSTALL_MODE"
            show_usage
            ;;
    esac
    
    echo "$(date): 操作完成" | tee -a "${INSTALL_LOG}"
}

# ============================================================================
# 脚本入口
# ============================================================================

# 捕获中断信号
trap 'print_info "安装被用户中断"; exit 1' INT TERM

# 执行主函数
main "$@"

exit 0

 

 posted on 2026-01-29 17:20  xibuhaohao  阅读(1)  评论(0)    收藏  举报