/*
 * Copyright (c) 2022 Huawei Technologies Co.,Ltd.
 *
 * DMS is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * dms_reform_fault_inject.c
 *
 *
 * IDENTIFICATION
 *    src/rc/dms_reform_fault_inject.c
 *
 * -------------------------------------------------------------------------
 */

#include "dms_reform_fault_inject.h"
#include "dms_reform_proc.h"
#include "cm_num.h"

typedef enum en_rfi_param {
    PARAM_FAULT_INJECT_TYPE = 0,
    PARAM_FAULT_INJECT_STEP = 1,
    PARAM_FAULT_INJECT_SLEEP_TIME = 2,

    PARAM_COUNT
} rfi_param_t;

#define FAULT_INJECT_DEFAULT_SLEEP_TIME 30

static config_item_t g_rfi_params[] = {
    { "FAULT_INJECT_TYPE", CM_TRUE, CM_FALSE, "NONE", NULL, NULL, "-", "-", "STRING", NULL,
        PARAM_FAULT_INJECT_TYPE, EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, FLAG_NONE, "NONE", CM_FALSE, CM_FALSE },
    { "FAULT_INJECT_STEP", CM_TRUE, CM_FALSE, "NONE", NULL, NULL, "-", "-", "STRING", NULL,
        PARAM_FAULT_INJECT_STEP, EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, FLAG_NONE, "NONE", CM_FALSE, CM_FALSE },
    { "FAULT_INJECT_SLEEP_TIME", CM_TRUE, CM_FALSE, "30", NULL, NULL, "-", "-", "INT", NULL,
        PARAM_FAULT_INJECT_SLEEP_TIME, EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, FLAG_NONE, "NONE", CM_FALSE, CM_FALSE },
};

typedef struct st_rfi_context {
    thread_t            thread;
    config_t            config;
    char                fault_step[CM_BUFLEN_64];
    char                fault_type[CM_BUFLEN_64];
    uint32              sleep_time;
} rfi_context_t;

rfi_context_t g_rfi_context;

static void dms_reform_fault_inject_ini_create(char *ini_path)
{
    int32 file_handle = CM_INVALID_HANDLE;
    if (cm_create_file(ini_path, O_CREAT | O_RDWR, &file_handle) != CM_SUCCESS) {
        LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL4, "[DMS FAULT INJECT]fail to create %s", ini_path);
        return;
    }
    cm_close_file(file_handle);
}

static void dms_reform_fault_inject_load_params(char *ini_path)
{
    if (cm_load_config(g_rfi_params, PARAM_COUNT, ini_path, &g_rfi_context.config, CM_FALSE) != CM_SUCCESS) {
        LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL4, "[DMS FAULT INJECT]fail to load parameter");
        return;
    }

    char *value = cm_get_config_value(&g_rfi_context.config, "FAULT_INJECT_TYPE");
    MEMS_RETVOID_IFERR(strcpy_s(g_rfi_context.fault_type, CM_BUFLEN_64, value));

    value = cm_get_config_value(&g_rfi_context.config, "FAULT_INJECT_STEP");
    MEMS_RETVOID_IFERR(strcpy_s(g_rfi_context.fault_step, CM_BUFLEN_64, value));

    value = cm_get_config_value(&g_rfi_context.config, "FAULT_INJECT_SLEEP_TIME");
    if (cm_str2uint32(value, &g_rfi_context.sleep_time) != CM_SUCCESS) {
        g_rfi_context.sleep_time = FAULT_INJECT_DEFAULT_SLEEP_TIME;
    }
}

static void dms_reform_fault_inject_thread(thread_t *thread)
{
#ifdef OPENGAUSS
    g_dms.callback.dms_thread_init(CM_FALSE, (char **)&thread->reg_data);
#endif
    char *gsdb_home = thread->argument;
    char ini_path[CM_FILE_NAME_BUFFER_SIZE];

#ifdef OPENGAUSS
    PRTS_RETVOID_IFERR(sprintf_s(ini_path, CM_MAX_FILE_NAME_LEN, "%s/dms_rfi.ini", gsdb_home));
#else
    PRTS_RETVOID_IFERR(sprintf_s(ini_path, CM_MAX_FILE_NAME_LEN, "%s/cfg/dms_rfi.ini", gsdb_home));
#endif

    cm_set_thread_name(DMS_REFORM_FI_THRD_NAME);
    LOG_RUN_INF("[DMS FAULT INJECT]dms_reform_fault_inject_thread start");
    mes_block_sighup_signal();

    while (!thread->closed) {
        if (!cm_file_exist(ini_path)) {
            dms_reform_fault_inject_ini_create(ini_path);
        }
        dms_reform_fault_inject_load_params(ini_path);
        cm_sleep(DMS_REFORM_SHORT_TIMEOUT);
    }

    LOG_RUN_INF("[DMS FAULT INJECT]dms_reform_fault_inject_thread close");
}

void dms_reform_fault_inject_init(char *gsdb_home)
{
    if (cm_create_thread(dms_reform_fault_inject_thread, 0, gsdb_home, &g_rfi_context.thread) != CM_SUCCESS) {
        LOG_RUN_ERR("[DMS FAULT INJECT]fail to create dms_reform_fault_inject_thread");
    }
}

void dms_reform_fault_inject_deinit(void)
{
    cm_close_thread(&g_rfi_context.thread);
}

void dms_reform_fault_inject_before_step(dms_reform_proc_t *reform_proc)
{
    if (strlen(g_rfi_context.fault_step) == 0 || strlen(g_rfi_context.fault_type) == 0) {
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_step, reform_proc->desc) != 0) {
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_type, "ABORT_BEFORE_STEP") == 0) {
        LOG_RUN_WAR("[DMS FAULT INJECT]before %s, abort", reform_proc->desc);
        cm_exit(0);
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_type, "SLEEP_BEFORE_STEP") == 0) {
        LOG_RUN_WAR("[DMS FAULT INJECT]before %s, sleep %us", reform_proc->desc, g_rfi_context.sleep_time);
        cm_sleep(g_rfi_context.sleep_time * MILLISECS_PER_SECOND);
        return;
    }
}

void dms_reform_fault_inject_after_step(dms_reform_proc_t *reform_proc)
{
    if (strlen(g_rfi_context.fault_step) == 0 || strlen(g_rfi_context.fault_type) == 0) {
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_step, reform_proc->desc) != 0) {
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_type, "ABORT_AFTER_STEP") == 0) {
        LOG_RUN_WAR("[DMS FAULT INJECT]after %s, abort", reform_proc->desc);
        cm_exit(0);
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_type, "SLEEP_AFTER_STEP") == 0) {
        LOG_RUN_WAR("[DMS FAULT INJECT]after %s, sleep %us", reform_proc->desc, g_rfi_context.sleep_time);
        cm_sleep(g_rfi_context.sleep_time * MILLISECS_PER_SECOND);
        return;
    }

    if (cm_strcmpi(g_rfi_context.fault_type, "FAIL_AFTER_STEP") == 0) {
        LOG_RUN_WAR("[DMS FAULT INJECT]after %s, set reform fail", reform_proc->desc);
        reform_info_t *reform_info = DMS_REFORM_INFO;
        reform_info->reform_fail = CM_TRUE;
        return;
    }
}