1784 lines
49 KiB
C++
1784 lines
49 KiB
C++
/**
|
|
* @file cm_elog.cpp
|
|
* @brief error logging and reporting
|
|
* @author xxx
|
|
* @version 1.0
|
|
* @date 2020-08-06
|
|
*
|
|
* @copyright Copyright (c) Huawei Technologies Co., Ltd. 2011-2020. All rights reserved.
|
|
*
|
|
*/
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <syslog.h>
|
|
#include <limits.h>
|
|
#include "cm/path.h"
|
|
|
|
#include "cm/cm_c.h"
|
|
#include "cm/stringinfo.h"
|
|
#include "cm/elog.h"
|
|
#include "alarm/alarm.h"
|
|
#include "cm/cm_misc.h"
|
|
#include "cm/be_module.h"
|
|
|
|
#include <sys/time.h>
|
|
#if !defined(WIN32)
|
|
#include <sys/syscall.h>
|
|
#define gettid() syscall(__NR_gettid)
|
|
#else
|
|
/* windows. */
|
|
#endif
|
|
#include <sys/stat.h>
|
|
|
|
#undef _
|
|
#define _(x) x
|
|
|
|
/*
|
|
* We really want line-buffered mode for logfile output, but Windows does
|
|
* not have it, and interprets _IOLBF as _IOFBF (bozos). So use _IONBF
|
|
* instead on Windows.
|
|
*/
|
|
#ifdef WIN32
|
|
#define LBF_MODE _IONBF
|
|
#else
|
|
#define LBF_MODE _IOLBF
|
|
#endif
|
|
|
|
int log_destion_choice = LOG_DESTION_FILE;
|
|
|
|
/* declare the global variable of alarm module. */
|
|
int g_alarmReportInterval;
|
|
char g_alarmComponentPath[MAXPGPATH];
|
|
int g_alarmReportMaxCount;
|
|
|
|
char sys_log_path[MAX_PATH_LEN] = {0}; /* defalut cmData/cm_server or cmData/cm_agent. */
|
|
char cm_krb_server_keyfile[MAX_PATH_LEN] = {0};
|
|
int Log_RotationSize = 16 * 1024 * 1024L;
|
|
pthread_rwlock_t syslog_write_lock;
|
|
pthread_rwlock_t dotCount_lock;
|
|
static bool dotCountNotZero = false;
|
|
|
|
FILE* syslogFile = NULL;
|
|
const char* prefix_name = NULL;
|
|
|
|
char curLogFileName[MAXPGPATH] = {0};
|
|
volatile int log_min_messages = WARNING;
|
|
volatile bool incremental_build = true;
|
|
volatile bool security_mode = false;
|
|
volatile int maxLogFileSize = 16 * 1024 * 1024;
|
|
volatile bool logInitFlag = false;
|
|
/* undocumentedVersion:
|
|
* It's for inplace upgrading. This variable means which version we are
|
|
* upgrading from. Zero means we are not upgrading.
|
|
*/
|
|
volatile uint32 undocumentedVersion = 0;
|
|
bool log_file_set = false;
|
|
/* unify log style */
|
|
THR_LOCAL const char* thread_name = NULL;
|
|
|
|
FILE* logfile_open(const char* filename, const char* mode);
|
|
static void get_alarm_report_interval(const char* conf);
|
|
static void TrimPathDoubleEndQuotes(char* path);
|
|
|
|
#define BUF_LEN 1024
|
|
#define COUNTSTR_LEN 128
|
|
#define MSBUF_LENGTH 8
|
|
#define FORMATTED_TS_LEN 128
|
|
|
|
static THR_LOCAL char errbuf_errdetail[EREPORT_BUF_LEN];
|
|
static THR_LOCAL char errbuf_errcode[EREPORT_BUF_LEN];
|
|
static THR_LOCAL char errbuf_errmodule[EREPORT_BUF_LEN];
|
|
static THR_LOCAL char errbuf_errmsg[EREPORT_BUF_LEN];
|
|
static THR_LOCAL char errbuf_errcause[EREPORT_BUF_LEN];
|
|
static THR_LOCAL char errbuf_erraction[EREPORT_BUF_LEN];
|
|
|
|
static THR_LOCAL char formatted_log_time[FORMATTED_TS_LEN];
|
|
|
|
/**
|
|
* @brief When a parent process opens a file, the child processes will inherit the
|
|
* file handle of the parent process. If the file is deleted and the child processes
|
|
* are still running, the file handle will not be freed and take up disk space.
|
|
* We set the FD_CLOEXEC flag to the file, so that the child processes don't inherit
|
|
* the file handle of the parent process, and do not cause handle leak.
|
|
*
|
|
* @param fp open file object
|
|
* @return int 0 means successfully set the flag.
|
|
*/
|
|
int SetFdCloseExecFlag(FILE* fp)
|
|
{
|
|
int fd = fileno(fp);
|
|
int flags = fcntl(fd, F_GETFD);
|
|
if (flags < 0) {
|
|
(void)printf("fcntl get flags failed.\n");
|
|
return flags;
|
|
}
|
|
flags |= FD_CLOEXEC;
|
|
int ret = fcntl(fd, F_SETFD, flags);
|
|
if (ret == -1) {
|
|
(void)printf("fcntl set flags failed.\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void AlarmLogImplementation(int level, const char* prefix, const char* logtext)
|
|
{
|
|
switch (level) {
|
|
case ALM_DEBUG:
|
|
write_runlog(LOG, "%s%s\n", prefix, logtext);
|
|
break;
|
|
case ALM_LOG:
|
|
write_runlog(LOG, "%s%s\n", prefix, logtext);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* setup formatted_log_time, for consistent times between CSV and regular logs
|
|
*/
|
|
static void setup_formatted_log_time(void)
|
|
{
|
|
struct timeval tv = {0};
|
|
time_t stamp_time;
|
|
char msbuf[MSBUF_LENGTH];
|
|
struct tm timeinfo = {0};
|
|
int rc;
|
|
errno_t rcs;
|
|
|
|
(void)gettimeofday(&tv, NULL);
|
|
stamp_time = (time_t)tv.tv_sec;
|
|
(void)localtime_r(&stamp_time, &timeinfo);
|
|
|
|
(void)strftime(formatted_log_time,
|
|
FORMATTED_TS_LEN,
|
|
/* leave room for milliseconds... */
|
|
"%Y-%m-%d %H:%M:%S %Z",
|
|
&timeinfo);
|
|
|
|
/* 'paste' milliseconds into place... */
|
|
rc = sprintf_s(msbuf, MSBUF_LENGTH, ".%03d", (int)(tv.tv_usec / 1000));
|
|
securec_check_ss_c(rc, "\0", "\0");
|
|
rcs = strncpy_s(formatted_log_time + 19, FORMATTED_TS_LEN - 19, msbuf, 4);
|
|
securec_check_c(rcs, "\0", "\0");
|
|
}
|
|
|
|
void add_log_prefix(int elevel, char* str)
|
|
{
|
|
char errbuf_tmp[BUF_LEN * 3] = {0};
|
|
errno_t rc;
|
|
int rcs;
|
|
|
|
setup_formatted_log_time();
|
|
|
|
/* unify log style */
|
|
if (thread_name == NULL) {
|
|
thread_name = "";
|
|
}
|
|
rcs = snprintf_s(errbuf_tmp,
|
|
sizeof(errbuf_tmp),
|
|
sizeof(errbuf_tmp) - 1,
|
|
"%s tid=%ld %s %s: ",
|
|
formatted_log_time,
|
|
gettid(),
|
|
thread_name,
|
|
log_level_int_to_string(elevel));
|
|
securec_check_intval(rcs, );
|
|
/* max message length less than 2048. */
|
|
rc = strncat_s(errbuf_tmp, BUF_LEN * 3, str, BUF_LEN * 3 - strlen(errbuf_tmp));
|
|
|
|
securec_check_c(rc, "\0", "\0");
|
|
rc = memcpy_s(str, BUF_LEN * 2, errbuf_tmp, BUF_LEN * 2 - 1);
|
|
securec_check_c(rc, "\0", "\0");
|
|
str[BUF_LEN * 2 - 1] = '\0';
|
|
}
|
|
|
|
/*
|
|
* is_log_level_output -- is elevel logically >= log_min_level?
|
|
*
|
|
* We use this for tests that should consider LOG to sort out-of-order,
|
|
* between ERROR and FATAL. Generally this is the right thing for testing
|
|
* whether a message should go to the postmaster log, whereas a simple >=
|
|
* test is correct for testing whether the message should go to the client.
|
|
*/
|
|
static bool is_log_level_output(int elevel, int log_min_level)
|
|
{
|
|
if (elevel == LOG) {
|
|
if (log_min_level == LOG || log_min_level <= ERROR) {
|
|
return true;
|
|
}
|
|
} else if (log_min_level == LOG) {
|
|
/* elevel not equal to LOG */
|
|
if (elevel >= FATAL)
|
|
return true;
|
|
} else if (elevel >= log_min_level) {
|
|
/* Neither is LOG */
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Write errors to stderr (or by equal means when stderr is
|
|
* not available).
|
|
*/
|
|
void write_runlog(int elevel, const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_list bp;
|
|
char errbuf[2048] = {0};
|
|
char fmtBuffer[2048] = {0};
|
|
int count = 0;
|
|
int ret = 0;
|
|
bool output_to_server = false;
|
|
|
|
/* Get whether the record will be logged into the file. */
|
|
output_to_server = is_log_level_output(elevel, log_min_messages);
|
|
if (!output_to_server) {
|
|
return;
|
|
}
|
|
|
|
/* Obtaining international texts. */
|
|
fmt = _(fmt);
|
|
|
|
va_start(ap, fmt);
|
|
|
|
if (prefix_name != NULL && strcmp(prefix_name, "cm_ctl") == 0) {
|
|
/* Skip the wait dot log and the line break log. */
|
|
if (strcmp(fmt, ".") == 0) {
|
|
(void)pthread_rwlock_wrlock(&dotCount_lock);
|
|
dotCountNotZero = true;
|
|
(void)pthread_rwlock_unlock(&dotCount_lock);
|
|
(void)vfprintf(stdout, fmt, ap);
|
|
(void)fflush(stdout);
|
|
va_end(ap);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Log the record to std error.
|
|
* 1. The log level is greater than the level "LOG", and the process name is "cm_ctl".
|
|
* 2. The log file path was not initialized.
|
|
*/
|
|
if (elevel >= LOG || sys_log_path[0] == '\0') {
|
|
if (dotCountNotZero == true) {
|
|
fprintf(stdout, "\n");
|
|
(void)pthread_rwlock_wrlock(&dotCount_lock);
|
|
dotCountNotZero = false;
|
|
(void)pthread_rwlock_unlock(&dotCount_lock);
|
|
}
|
|
|
|
/* Get the print out format. */
|
|
ret = snprintf_s(fmtBuffer, sizeof(fmtBuffer), sizeof(fmtBuffer) - 1, "%s: %s", prefix_name, fmt);
|
|
securec_check_ss_c(ret, "\0", "\0");
|
|
va_copy(bp, ap);
|
|
(void)vfprintf(stdout, fmtBuffer, bp);
|
|
(void)fflush(stdout);
|
|
va_end(bp);
|
|
}
|
|
}
|
|
|
|
/* Format the log record. */
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
va_end(ap);
|
|
|
|
switch (log_destion_choice) {
|
|
case LOG_DESTION_FILE:
|
|
add_log_prefix(elevel, errbuf);
|
|
write_log_file(errbuf, count);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int add_message_string(char* errmsg_tmp, char* errdetail_tmp, char* errmodule_tmp, char* errcode_tmp, const char* fmt)
|
|
{
|
|
int rcs = 0;
|
|
char *p = NULL;
|
|
char errbuf_tmp[BUF_LEN] = {0};
|
|
|
|
rcs = snprintf_s(errbuf_tmp, sizeof(errbuf_tmp), sizeof(errbuf_tmp) - 1, "%s", fmt);
|
|
securec_check_intval(rcs, );
|
|
if ((p = strstr(errbuf_tmp, "[ERRMSG]:")) != NULL) {
|
|
rcs = snprintf_s(errmsg_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRMSG]:"));
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRDETAIL]:")) != NULL) {
|
|
rcs = snprintf_s(errdetail_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt);
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRMODULE]:")) != NULL) {
|
|
rcs = snprintf_s(errmodule_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRMODULE]:"));
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRCODE]:")) != NULL) {
|
|
rcs = snprintf_s(errcode_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRCODE]:"));
|
|
}
|
|
securec_check_intval(rcs, );
|
|
return 0;
|
|
}
|
|
|
|
int add_message_string(char* errmsg_tmp, char* errdetail_tmp, char* errmodule_tmp, char* errcode_tmp,
|
|
char* errcause_tmp, char* erraction_tmp, const char* fmt)
|
|
{
|
|
int rcs = 0;
|
|
char *p = NULL;
|
|
char errbuf_tmp[BUF_LEN] = {0};
|
|
|
|
rcs = snprintf_s(errbuf_tmp, sizeof(errbuf_tmp), sizeof(errbuf_tmp) - 1, "%s", fmt);
|
|
securec_check_intval(rcs, );
|
|
if ((p = strstr(errbuf_tmp, "[ERRMSG]:")) != NULL) {
|
|
rcs = snprintf_s(errmsg_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRMSG]:"));
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRDETAIL]:")) != NULL) {
|
|
rcs = snprintf_s(errdetail_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt);
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRMODULE]:")) != NULL) {
|
|
rcs = snprintf_s(errmodule_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRMODULE]:"));
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRCODE]:")) != NULL) {
|
|
rcs = snprintf_s(errcode_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt + strlen("[ERRCODE]:"));
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRCAUSE]:")) != NULL) {
|
|
rcs = snprintf_s(errcause_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt);
|
|
} else if ((p = strstr(errbuf_tmp, "[ERRACTION]:")) != NULL) {
|
|
rcs = snprintf_s(erraction_tmp, BUF_LEN, BUF_LEN - 1, "%s", fmt);
|
|
}
|
|
securec_check_intval(rcs, );
|
|
return 0;
|
|
}
|
|
|
|
|
|
void add_log_prefix2(int elevel, const char* errmodule_tmp, const char* errcode_tmp, char* str)
|
|
{
|
|
char errbuf_tmp[BUF_LEN * 3] = {0};
|
|
errno_t rc;
|
|
int rcs;
|
|
|
|
setup_formatted_log_time();
|
|
|
|
/* unify log style */
|
|
if (thread_name == NULL) {
|
|
thread_name = "";
|
|
}
|
|
if (errmodule_tmp[0] && errcode_tmp[0]) {
|
|
rcs = snprintf_s(errbuf_tmp,
|
|
sizeof(errbuf_tmp),
|
|
sizeof(errbuf_tmp) - 1,
|
|
"%s tid=%ld %s [%s] %s %s: ",
|
|
formatted_log_time,
|
|
gettid(),
|
|
thread_name,
|
|
errmodule_tmp,
|
|
errcode_tmp,
|
|
log_level_int_to_string(elevel));
|
|
} else {
|
|
rcs = snprintf_s(errbuf_tmp,
|
|
sizeof(errbuf_tmp),
|
|
sizeof(errbuf_tmp) - 1,
|
|
"%s tid=%ld %s %s: ",
|
|
formatted_log_time,
|
|
gettid(),
|
|
thread_name,
|
|
log_level_int_to_string(elevel));
|
|
}
|
|
securec_check_intval(rcs, );
|
|
/* max message length less than 2048. */
|
|
rc = strncat_s(errbuf_tmp, BUF_LEN * 3, str, BUF_LEN * 3 - strlen(errbuf_tmp));
|
|
|
|
securec_check_c(rc, "\0", "\0");
|
|
rc = memcpy_s(str, BUF_LEN * 2, errbuf_tmp, BUF_LEN * 2 - 1);
|
|
securec_check_c(rc, "\0", "\0");
|
|
str[BUF_LEN * 2 - 1] = '\0';
|
|
}
|
|
|
|
/*
|
|
* Write errors to stderr (or by equal means when stderr is
|
|
* not available).
|
|
*/
|
|
void write_runlog3(int elevel, const char* errmodule_tmp, const char* errcode_tmp, const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_list bp;
|
|
char errbuf[2048] = {0};
|
|
char fmtBuffer[2048] = {0};
|
|
int count = 0;
|
|
int ret = 0;
|
|
bool output_to_server = false;
|
|
|
|
/* Get whether the record will be logged into the file. */
|
|
output_to_server = is_log_level_output(elevel, log_min_messages);
|
|
if (!output_to_server) {
|
|
return;
|
|
}
|
|
|
|
/* Obtaining international texts. */
|
|
fmt = _(fmt);
|
|
|
|
va_start(ap, fmt);
|
|
|
|
if (prefix_name != NULL && strcmp(prefix_name, "cm_ctl") == 0) {
|
|
/* Skip the wait dot log and the line break log. */
|
|
if (strcmp(fmt, ".") == 0) {
|
|
(void)pthread_rwlock_wrlock(&dotCount_lock);
|
|
dotCountNotZero = true;
|
|
(void)pthread_rwlock_unlock(&dotCount_lock);
|
|
(void)vfprintf(stdout, fmt, ap);
|
|
(void)fflush(stdout);
|
|
va_end(ap);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Log the record to std error.
|
|
* 1. The log level is greater than the level "LOG", and the process name is "cm_ctl".
|
|
* 2. The log file path was not initialized.
|
|
*/
|
|
if (elevel >= LOG || sys_log_path[0] == '\0') {
|
|
if (dotCountNotZero == true) {
|
|
fprintf(stdout, "\n");
|
|
(void)pthread_rwlock_wrlock(&dotCount_lock);
|
|
dotCountNotZero = false;
|
|
(void)pthread_rwlock_unlock(&dotCount_lock);
|
|
}
|
|
|
|
/* Get the print out format. */
|
|
ret = snprintf_s(fmtBuffer, sizeof(fmtBuffer), sizeof(fmtBuffer) - 1, "%s: %s", prefix_name, fmt);
|
|
securec_check_intval(ret, );
|
|
va_copy(bp, ap);
|
|
(void)vfprintf(stdout, fmtBuffer, bp);
|
|
(void)fflush(stdout);
|
|
va_end(bp);
|
|
}
|
|
}
|
|
|
|
/* Format the log record. */
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
securec_check_intval(count, );
|
|
va_end(ap);
|
|
|
|
switch (log_destion_choice) {
|
|
case LOG_DESTION_FILE:
|
|
add_log_prefix2(elevel, errmodule_tmp, errcode_tmp, errbuf);
|
|
write_log_file(errbuf, count);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Open a new logfile with proper permissions and buffering options.
|
|
*
|
|
* If allow_errors is true, we just log any open failure and return NULL
|
|
* (with errno still correct for the fopen failure).
|
|
* Otherwise, errors are treated as fatal.
|
|
*/
|
|
FILE* logfile_open(const char* log_path, const char* mode)
|
|
{
|
|
FILE* fh = NULL;
|
|
mode_t oumask;
|
|
char log_file_name[MAXPGPATH] = {0};
|
|
char log_temp_name[MAXPGPATH] = {0};
|
|
char log_create_time[LOG_MAX_TIMELEN] = {0};
|
|
DIR* dir = NULL;
|
|
struct dirent* de = NULL;
|
|
bool is_exist = false;
|
|
pg_time_t current_time;
|
|
struct tm* systm = NULL;
|
|
/* check validity of current log file name */
|
|
char* name_ptr = NULL;
|
|
errno_t rc = 0;
|
|
int ret = 0;
|
|
|
|
if (log_path == NULL) {
|
|
(void)printf("logfile_open,log file path is null.\n");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Note we do not let Log_file_mode disable IWUSR,
|
|
* since we certainly want to be able to write the files ourselves.
|
|
*/
|
|
oumask = umask((mode_t)((~(mode_t)(S_IRUSR | S_IWUSR | S_IXUSR)) & (S_IRWXU | S_IRWXG | S_IRWXO)));
|
|
|
|
/* find current log file. */
|
|
if ((dir = opendir(log_path)) == NULL) {
|
|
printf(_("%s: opendir %s failed! \n"), prefix_name, log_path);
|
|
return NULL;
|
|
}
|
|
while ((de = readdir(dir)) != NULL) {
|
|
/* exist current log file. */
|
|
if (strstr(de->d_name, prefix_name) != NULL) {
|
|
name_ptr = strstr(de->d_name, "-current.log");
|
|
if (name_ptr != NULL) {
|
|
name_ptr += strlen("-current.log");
|
|
if ((*name_ptr) == '\0') {
|
|
is_exist = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = memset_s(log_file_name, MAXPGPATH, 0, MAXPGPATH);
|
|
securec_check_errno(rc, );
|
|
if (!is_exist) {
|
|
/* create current log file name. */
|
|
current_time = time(NULL);
|
|
systm = localtime(¤t_time);
|
|
if (systm != NULL) {
|
|
(void)strftime(log_create_time, LOG_MAX_TIMELEN, "-%Y-%m-%d_%H%M%S", systm);
|
|
}
|
|
ret =
|
|
snprintf_s(log_temp_name, MAXPGPATH, MAXPGPATH - 1, "%s%s%s", prefix_name, log_create_time, curLogFileMark);
|
|
securec_check_intval(ret, );
|
|
ret = snprintf_s(log_file_name, MAXPGPATH, MAXPGPATH - 1, "%s/%s", log_path, log_temp_name);
|
|
securec_check_intval(ret, );
|
|
} else {
|
|
/* if log file exist, get its file name. */
|
|
ret = snprintf_s(log_file_name, MAXPGPATH, MAXPGPATH - 1, "%s/%s", log_path, de->d_name);
|
|
securec_check_intval(ret, );
|
|
}
|
|
(void)closedir(dir);
|
|
fh = fopen(log_file_name, mode);
|
|
|
|
(void)umask(oumask);
|
|
|
|
if (fh != NULL) {
|
|
(void)setvbuf(fh, NULL, LBF_MODE, 0);
|
|
|
|
#ifdef WIN32
|
|
/* use CRLF line endings on Windows */
|
|
_setmode(_fileno(fh), _O_TEXT);
|
|
#endif
|
|
/*
|
|
* when parent process(cm_agent) open the cm_agent_xxx.log, the child processes(cn\dn\gtm\cm_server)
|
|
* inherit the file handle of the parent process. If the file is deleted and the child processes
|
|
* are still running, the file handle will not be freed, it will take up disk space, so we set
|
|
* the FD_CLOEXEC flag to the file, so that the child processes don't inherit the file handle of the
|
|
* parent process.
|
|
*/
|
|
if (SetFdCloseExecFlag(fh) == -1) {
|
|
(void)printf("set file flag failed, filename:%s, errmsg: %s.\n", log_file_name, strerror(errno));
|
|
}
|
|
} else {
|
|
int save_errno = errno;
|
|
|
|
(void)printf("logfile_open could not open log file:%s %s.\n", log_file_name, strerror(errno));
|
|
errno = save_errno;
|
|
}
|
|
|
|
/* store current log file name */
|
|
rc = memset_s(curLogFileName, MAXPGPATH, 0, MAXPGPATH);
|
|
securec_check_errno(rc, );
|
|
rc = strncpy_s(curLogFileName, MAXPGPATH, log_file_name, strlen(log_file_name));
|
|
securec_check_errno(rc, );
|
|
|
|
return fh;
|
|
}
|
|
|
|
int logfile_init()
|
|
{
|
|
int rc;
|
|
errno_t rcs;
|
|
|
|
rc = pthread_rwlock_init(&syslog_write_lock, NULL);
|
|
if (rc != 0) {
|
|
fprintf(stderr, "logfile_init lock failed.exit\n");
|
|
exit(1);
|
|
}
|
|
rc = pthread_rwlock_init(&dotCount_lock, NULL);
|
|
if (rc != 0) {
|
|
fprintf(stderr, "logfile_init dot_count_lock failed.exit\n");
|
|
exit(1);
|
|
}
|
|
rcs = memset_s(sys_log_path, MAX_PATH_LEN, 0, MAX_PATH_LEN);
|
|
securec_check_c(rcs, "\0", "\0");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int is_comment_line(const char* str)
|
|
{
|
|
size_t ii = 0;
|
|
|
|
if (str == NULL) {
|
|
printf("bad config file line\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* skip blank */
|
|
for (;;) {
|
|
if (*(str + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*(str + ii) == '#') {
|
|
return 1; /* comment line */
|
|
}
|
|
|
|
return 0; /* not comment line */
|
|
}
|
|
|
|
int get_authentication_type(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
int type = CM_AUTH_TRUST;
|
|
|
|
if (config_file == NULL) {
|
|
return CM_AUTH_TRUST; /* default level */
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
char errBuffer[ERROR_LIMIT_LEN];
|
|
printf("can not open config file: %s %s\n", config_file, pqStrerror(errno, errBuffer, ERROR_LIMIT_LEN));
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
errno_t rc;
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
if (strstr(buf, "cm_auth_method") != NULL) {
|
|
/* check all lines */
|
|
if (strstr(buf, "trust") != NULL) {
|
|
type = CM_AUTH_TRUST;
|
|
}
|
|
|
|
if (strstr(buf, "gss") != NULL) {
|
|
type = CM_AUTH_GSS;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
return type;
|
|
}
|
|
|
|
/* trim successive characters on both ends */
|
|
static char* TrimToken(char* src, const char& delim)
|
|
{
|
|
char* s = 0;
|
|
char* e = 0;
|
|
char* c = 0;
|
|
|
|
for (c = src; (c != NULL) && *c; ++c) {
|
|
if (*c == delim) {
|
|
if (e == NULL) {
|
|
e = c;
|
|
}
|
|
} else {
|
|
if (s == NULL) {
|
|
s = c;
|
|
}
|
|
e = NULL;
|
|
}
|
|
}
|
|
|
|
if (s == NULL) {
|
|
s = src;
|
|
}
|
|
|
|
if (e != NULL) {
|
|
*e = 0;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static void TrimPathDoubleEndQuotes(char* path)
|
|
{
|
|
int pathLen = strlen(path);
|
|
|
|
/* make sure buf[MAXPGPATH] can copy the whole path, last '\0' included */
|
|
if (pathLen > MAXPGPATH - 1) {
|
|
return;
|
|
}
|
|
|
|
char* pathTrimed = NULL;
|
|
pathTrimed = TrimToken(path, '\'');
|
|
pathTrimed = TrimToken(pathTrimed, '\"');
|
|
|
|
char buf[MAXPGPATH] = {0};
|
|
errno_t rc = 0;
|
|
|
|
rc = strncpy_s(buf, MAXPGPATH, pathTrimed, strlen(pathTrimed));
|
|
securec_check_errno(rc, );
|
|
|
|
rc = strncpy_s(path, pathLen + 1, buf, strlen(buf));
|
|
securec_check_errno(rc, );
|
|
}
|
|
|
|
void get_krb_server_keyfile(const char* config_file)
|
|
{
|
|
char buf[MAXPGPATH];
|
|
FILE* fd = NULL;
|
|
|
|
int ii = 0;
|
|
|
|
char* subStr = NULL;
|
|
char* subStr1 = NULL;
|
|
char* subStr2 = NULL;
|
|
char* subStr3 = NULL;
|
|
|
|
char* saveptr1 = NULL;
|
|
char* saveptr2 = NULL;
|
|
char* saveptr3 = NULL;
|
|
errno_t rc = 0;
|
|
|
|
if (config_file == NULL) {
|
|
return;
|
|
} else {
|
|
logInitFlag = true;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
printf("get_krb_server_keyfile confDir error\n");
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, MAXPGPATH, 0, MAXPGPATH);
|
|
securec_check_errno(rc, );
|
|
|
|
(void)fgets(buf, MAXPGPATH, fd);
|
|
buf[MAXPGPATH - 1] = 0;
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
subStr = strstr(buf, "cm_krb_server_keyfile");
|
|
if (subStr == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr = strstr(subStr + 7, "=");
|
|
if (subStr == NULL) {
|
|
continue;
|
|
}
|
|
|
|
/* = is last char */
|
|
if (subStr + 1 == 0) {
|
|
continue;
|
|
}
|
|
|
|
/* skip blank */
|
|
ii = 1;
|
|
for (;;) {
|
|
if (*(subStr + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
subStr = subStr + ii;
|
|
|
|
/* beging check blank */
|
|
subStr1 = strtok_r(subStr, " ", &saveptr1);
|
|
if (subStr1 == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr2 = strtok_r(subStr1, "\n", &saveptr2);
|
|
if (subStr2 == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr3 = strtok_r(subStr2, "\r", &saveptr3);
|
|
if (subStr3 == NULL) {
|
|
continue;
|
|
}
|
|
if (subStr3[0] == '\'') {
|
|
subStr3 = subStr3 + 1;
|
|
}
|
|
if (subStr3[strlen(subStr3) - 1] == '\'') {
|
|
subStr3[strlen(subStr3) - 1] = '\0';
|
|
}
|
|
if (strlen(subStr3) > 0) {
|
|
rc = memcpy_s(cm_krb_server_keyfile, sizeof(sys_log_path), subStr3, strlen(subStr3) + 1);
|
|
securec_check_errno(rc, );
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
TrimPathDoubleEndQuotes(cm_krb_server_keyfile);
|
|
|
|
return; /* default value warning */
|
|
}
|
|
|
|
void GetStringFromConf(const char* configFile, char* itemValue, size_t itemValueLenth, const char* itemName)
|
|
{
|
|
char buf[MAXPGPATH];
|
|
FILE* fd = NULL;
|
|
|
|
int ii = 0;
|
|
|
|
char* subStr = NULL;
|
|
char* subStr1 = NULL;
|
|
char* subStr2 = NULL;
|
|
char* subStr3 = NULL;
|
|
|
|
char* saveptr1 = NULL;
|
|
char* saveptr2 = NULL;
|
|
char* saveptr3 = NULL;
|
|
errno_t rc = 0;
|
|
|
|
if (configFile == NULL) {
|
|
return;
|
|
} else {
|
|
logInitFlag = true;
|
|
}
|
|
|
|
fd = fopen(configFile, "r");
|
|
if (fd == NULL) {
|
|
printf("%s confDir error\n", itemName);
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, MAXPGPATH, 0, MAXPGPATH);
|
|
securec_check_errno(rc, );
|
|
|
|
(void)fgets(buf, MAXPGPATH, fd);
|
|
buf[MAXPGPATH - 1] = 0;
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
subStr = strstr(buf, itemName);
|
|
if (subStr == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr = strstr(subStr + strlen(itemName), "=");
|
|
if (subStr == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (subStr + 1 == 0) {
|
|
continue; /* = is last char */
|
|
}
|
|
|
|
/* skip blank */
|
|
ii = 1;
|
|
for (;;) {
|
|
if (*(subStr + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
subStr = subStr + ii;
|
|
|
|
/* beging check blank */
|
|
subStr1 = strtok_r(subStr, " ", &saveptr1);
|
|
if (subStr1 == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr2 = strtok_r(subStr1, "\n", &saveptr2);
|
|
if (subStr2 == NULL) {
|
|
continue;
|
|
}
|
|
|
|
subStr3 = strtok_r(subStr2, "\r", &saveptr3);
|
|
if (subStr3 == NULL) {
|
|
continue;
|
|
}
|
|
if (subStr3[0] == '\'') {
|
|
subStr3 = subStr3 + 1;
|
|
}
|
|
if (subStr3[strlen(subStr3) - 1] == '\'') {
|
|
subStr3[strlen(subStr3) - 1] = '\0';
|
|
}
|
|
if (strlen(subStr3) > 0) {
|
|
rc = memcpy_s(itemValue, itemValueLenth, subStr3, strlen(subStr3) + 1);
|
|
securec_check_errno(rc, );
|
|
} else {
|
|
write_runlog(ERROR, "invalid value for parameter \" %s \" in %s.\n", itemName, configFile);
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
return; /* default value warning */
|
|
}
|
|
|
|
/* used for cm_agent and cm_server */
|
|
/* g_currentNode->cmDataPath --> confDir */
|
|
void get_log_level(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
|
|
if (config_file == NULL) {
|
|
return;
|
|
} else {
|
|
logInitFlag = true;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
char errBuffer[ERROR_LIMIT_LEN];
|
|
printf("can not open config file: %s %s\n", config_file, pqStrerror(errno, errBuffer, ERROR_LIMIT_LEN));
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
errno_t rc;
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
if (strstr(buf, "log_min_messages") != NULL) {
|
|
/* check all lines */
|
|
if (strcasestr(buf, "DEBUG5") != NULL) {
|
|
log_min_messages = DEBUG5;
|
|
break;
|
|
}
|
|
|
|
if (strcasestr(buf, "DEBUG1") != NULL) {
|
|
log_min_messages = DEBUG1;
|
|
break;
|
|
}
|
|
|
|
if (strcasestr(buf, "WARNING") != NULL) {
|
|
log_min_messages = WARNING;
|
|
break;
|
|
}
|
|
|
|
if (strcasestr(buf, "ERROR") != NULL) {
|
|
log_min_messages = ERROR;
|
|
break;
|
|
}
|
|
|
|
if (strcasestr(buf, "FATAL") != NULL) {
|
|
log_min_messages = FATAL;
|
|
break;
|
|
}
|
|
|
|
if (strcasestr(buf, "LOG") != NULL) {
|
|
log_min_messages = LOG;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
return; /* default value warning */
|
|
}
|
|
|
|
/* used for cm_agent */
|
|
void get_build_mode(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
|
|
if (config_file == NULL) {
|
|
return;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
char errBuffer[ERROR_LIMIT_LEN];
|
|
printf("can not open config file: %s %s\n", config_file, pqStrerror(errno, errBuffer, ERROR_LIMIT_LEN));
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
errno_t rc;
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
/* skip # comment */
|
|
if (is_comment_line(buf) == 1) {
|
|
continue;
|
|
}
|
|
|
|
/* check all lines */
|
|
if (strstr(buf, "incremental_build") != NULL) {
|
|
if (strstr(buf, "on") != NULL) {
|
|
incremental_build = true;
|
|
} else if (strstr(buf, "off") != NULL) {
|
|
incremental_build = false;
|
|
} else {
|
|
incremental_build = true;
|
|
write_runlog(FATAL, "invalid value for parameter \"incremental_build\" in %s.\n", config_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fd);
|
|
return;
|
|
}
|
|
|
|
/* used for cm_agent and cm_server */
|
|
void get_log_file_size(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
|
|
if (config_file == NULL) {
|
|
return; /* default size */
|
|
} else {
|
|
logInitFlag = true;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
printf("get_log_file_size error\n");
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
errno_t rc;
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
if (strstr(buf, "log_file_size") != NULL) {
|
|
/* only check the first line */
|
|
char* subStr = NULL;
|
|
char countStr[COUNTSTR_LEN] = {0};
|
|
int ii = 0;
|
|
int jj = 0;
|
|
|
|
subStr = strchr(buf, '=');
|
|
if (subStr != NULL) {
|
|
/* find = */
|
|
ii = 1; /* 1 is = */
|
|
|
|
/* skip blank */
|
|
for (;;) {
|
|
if (*(subStr + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else if (*(subStr + ii) >= '0' && *(subStr + ii) <= '9') {
|
|
break; /* number find.break */
|
|
} else {
|
|
/* invalid character. */
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
while (*(subStr + ii) >= '0' && *(subStr + ii) <= '9') {
|
|
/* end when no more number. */
|
|
if (jj > (int)sizeof(countStr) - 2) {
|
|
printf("too large log file size.\n");
|
|
exit(1);
|
|
} else {
|
|
countStr[jj] = *(subStr + ii);
|
|
}
|
|
|
|
ii++;
|
|
jj++;
|
|
}
|
|
countStr[jj] = 0; /* jj maybe have added itself.terminate string. */
|
|
|
|
if (countStr[0] != 0) {
|
|
maxLogFileSize = atoi(countStr) * 1024 * 1024; /* byte */
|
|
} else {
|
|
write_runlog(ERROR, "invalid value for parameter \"log_file_size\" in %s.\n", config_file);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
fclose(fd);
|
|
return; /* default value is warning */
|
|
}
|
|
|
|
int get_cm_thread_count(const char* config_file)
|
|
{
|
|
#define DEFAULT_THREAD_NUM 5
|
|
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
int thread_count = DEFAULT_THREAD_NUM;
|
|
errno_t rc = 0;
|
|
|
|
if (config_file == NULL) {
|
|
printf("no cmserver config file! exit.\n");
|
|
exit(1);
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
printf("open cmserver config file :%s ,error:%m\n", config_file);
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, sizeof(buf), 0, sizeof(buf));
|
|
securec_check_errno(rc, );
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
if (strstr(buf, "thread_count") != NULL) {
|
|
/* only check the first line */
|
|
char* subStr = NULL;
|
|
char countStr[COUNTSTR_LEN] = {0};
|
|
int ii = 0;
|
|
int jj = 0;
|
|
|
|
subStr = strchr(buf, '=');
|
|
/* find = */
|
|
if (subStr != NULL) {
|
|
ii = 1;
|
|
|
|
/* skip blank */
|
|
for (;;) {
|
|
if (*(subStr + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else if (*(subStr + ii) >= '0' && *(subStr + ii) <= '9') {
|
|
/* number find.break */
|
|
break;
|
|
} else {
|
|
/* invalid character. */
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* end when no number */
|
|
while (*(subStr + ii) >= '0' && *(subStr + ii) <= '9') {
|
|
if (jj > (int)sizeof(countStr) - 2) {
|
|
printf("too large thread count.\n");
|
|
exit(1);
|
|
} else {
|
|
countStr[jj] = *(subStr + ii);
|
|
}
|
|
|
|
ii++;
|
|
jj++;
|
|
}
|
|
countStr[jj] = 0; /* jj maybe have added itself.terminate string. */
|
|
|
|
if (countStr[0] != 0) {
|
|
thread_count = atoi(countStr);
|
|
|
|
if (thread_count < 2 || thread_count > 1000) {
|
|
printf("invalid thread count %d, range [2 - 1000].\n", thread_count);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
thread_count = DEFAULT_THREAD_NUM;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
fclose(fd);
|
|
return thread_count;
|
|
}
|
|
|
|
/*
|
|
* @Description: get value of paramater from configuration file
|
|
*
|
|
* @in config_file: configuration file path
|
|
* @in key: name of paramater
|
|
* @in defaultValue: default value of parameter
|
|
*
|
|
* @out: value of parameter
|
|
*/
|
|
int get_int_value_from_config(const char* config_file, const char* key, int defaultValue)
|
|
{
|
|
int64 i64 = get_int64_value_from_config(config_file, key, defaultValue);
|
|
if (i64 > INT_MAX) {
|
|
return defaultValue;
|
|
} else if (i64 < INT_MIN) {
|
|
return defaultValue;
|
|
}
|
|
|
|
return (int)i64;
|
|
}
|
|
|
|
/*
|
|
* @Description: get value of paramater from configuration file
|
|
*
|
|
* @in config_file: configuration file path
|
|
* @in key: name of paramater
|
|
* @in defaultValue: default value of parameter
|
|
*
|
|
* @out: value of parameter
|
|
*/
|
|
uint32 get_uint32_value_from_config(const char* config_file, const char* key, uint32 defaultValue)
|
|
{
|
|
int64 i64 = get_int64_value_from_config(config_file, key, defaultValue);
|
|
if (i64 > UINT_MAX) {
|
|
return defaultValue;
|
|
} else if (i64 < 0) {
|
|
return defaultValue;
|
|
}
|
|
|
|
return (uint32)i64;
|
|
}
|
|
|
|
/*
|
|
* @Description: get value of paramater from configuration file
|
|
*
|
|
* @in config_file: configuration file path
|
|
* @in key: name of paramater
|
|
* @in defaultValue: default value of parameter
|
|
*
|
|
* @out: value of parameter
|
|
*/
|
|
int64 get_int64_value_from_config(const char* config_file, const char* key, int64 defaultValue)
|
|
{
|
|
char buf[BUF_LEN];
|
|
FILE* fd = NULL;
|
|
int64 int64Value = defaultValue;
|
|
errno_t rc = 0;
|
|
|
|
Assert(key);
|
|
if (config_file == NULL) {
|
|
printf("no config file! exit.\n");
|
|
exit(1);
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
char errBuffer[ERROR_LIMIT_LEN];
|
|
printf("open config file failed:%s ,error:%s\n", config_file, pqStrerror(errno, errBuffer, ERROR_LIMIT_LEN));
|
|
exit(1);
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, sizeof(buf), 0, sizeof(buf));
|
|
securec_check_errno(rc, );
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_line(buf) == 1) {
|
|
continue; /* skip # comment */
|
|
}
|
|
|
|
if (strstr(buf, key) != NULL) {
|
|
/* only check the first line */
|
|
char* subStr = NULL;
|
|
char countStr[COUNTSTR_LEN] = {0};
|
|
int ii = 0;
|
|
int jj = 0;
|
|
|
|
subStr = strchr(buf, '=');
|
|
if (subStr != NULL) {
|
|
/* find = */
|
|
ii = 1;
|
|
|
|
/* skip blank */
|
|
while (1) {
|
|
if (*(subStr + ii) == ' ') {
|
|
ii++; /* skip blank */
|
|
} else if (isdigit(*(subStr + ii))) {
|
|
/* number find.break */
|
|
break;
|
|
} else {
|
|
/* invalid character. */
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
while (isdigit(*(subStr + ii))) {
|
|
/* end when no number */
|
|
if (jj >= COUNTSTR_LEN - 1) {
|
|
write_runlog(ERROR, "length is not enough for constr\n");
|
|
goto out;
|
|
}
|
|
countStr[jj] = *(subStr + ii);
|
|
|
|
ii++;
|
|
jj++;
|
|
}
|
|
countStr[jj] = 0; /* jj maybe have added itself.terminate string. */
|
|
|
|
if (countStr[0] != 0) {
|
|
int64Value = strtoll(countStr, NULL, 10);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
fclose(fd);
|
|
return int64Value;
|
|
}
|
|
|
|
#define ALARM_REPORT_INTERVAL "alarm_report_interval"
|
|
#define ALARM_REPORT_INTERVAL_DEFAULT 10
|
|
|
|
#define ALARM_REPORT_MAX_COUNT "alarm_report_max_count"
|
|
#define ALARM_REPORT_MAX_COUNT_DEFAULT 5
|
|
|
|
/* trim blank characters on both ends */
|
|
char* trim(char* src)
|
|
{
|
|
char* s = 0;
|
|
char* e = 0;
|
|
char* c = 0;
|
|
|
|
for (c = src; (c != NULL) && *c; ++c) {
|
|
if (isspace(*c)) {
|
|
if (e == NULL) {
|
|
e = c;
|
|
}
|
|
} else {
|
|
if (s == NULL) {
|
|
s = c;
|
|
}
|
|
e = 0;
|
|
}
|
|
}
|
|
if (s == NULL) {
|
|
s = src;
|
|
}
|
|
if (e != NULL) {
|
|
*e = 0;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
/* Check this line is comment line or not, which is in cm_server.conf file */
|
|
static bool is_comment_entity(char* str_line)
|
|
{
|
|
char* src = NULL;
|
|
if (str_line == NULL || strlen(str_line) < 1) {
|
|
return false;
|
|
}
|
|
src = str_line;
|
|
src = trim(src);
|
|
if (src == NULL || strlen(src) < 1) {
|
|
return true;
|
|
}
|
|
if (*src == '#') {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int is_digit_string(char* str)
|
|
{
|
|
#define isDigital(_ch) (((_ch) >= '0') && ((_ch) <= '9'))
|
|
|
|
int i = 0;
|
|
int len = -1;
|
|
char* p = NULL;
|
|
if (str == nullptr) {
|
|
return 0;
|
|
}
|
|
if ((len = strlen(str)) <= 0) {
|
|
return 0;
|
|
}
|
|
p = str;
|
|
for (i = 0; i < len; i++) {
|
|
if (!isDigital(p[i])) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
static void get_alarm_parameters(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN] = {0};
|
|
FILE* fd = NULL;
|
|
char* index1 = NULL;
|
|
char* index2 = NULL;
|
|
char* src = NULL;
|
|
char* key = NULL;
|
|
char* value = NULL;
|
|
errno_t rc = 0;
|
|
|
|
if (config_file == NULL) {
|
|
return;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
return;
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_entity(buf) == true) {
|
|
continue;
|
|
}
|
|
index1 = strchr(buf, '#');
|
|
if (index1 != NULL) {
|
|
*index1 = '\0';
|
|
}
|
|
index2 = strchr(buf, '=');
|
|
if (index2 == NULL) {
|
|
continue;
|
|
}
|
|
src = buf;
|
|
src = trim(src);
|
|
index2 = strchr(src, '=');
|
|
key = src;
|
|
/* jump to the beginning of recorded values */
|
|
value = index2 + 1;
|
|
|
|
key = trim(key);
|
|
value = trim(value);
|
|
if (strncmp(key, ALARM_REPORT_INTERVAL, strlen(ALARM_REPORT_INTERVAL)) == 0) {
|
|
if (is_digit_string(value)) {
|
|
g_alarmReportInterval = atoi(value);
|
|
if (g_alarmReportInterval == -1) {
|
|
g_alarmReportInterval = ALARM_REPORT_INTERVAL_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
fclose(fd);
|
|
}
|
|
|
|
static void get_alarm_report_max_count(const char* config_file)
|
|
{
|
|
char buf[BUF_LEN] = {0};
|
|
FILE* fd = NULL;
|
|
char* index1 = NULL;
|
|
char* index2 = NULL;
|
|
char* src = NULL;
|
|
char* key = NULL;
|
|
char* value = NULL;
|
|
errno_t rc = 0;
|
|
|
|
if (config_file == NULL) {
|
|
return;
|
|
}
|
|
|
|
fd = fopen(config_file, "r");
|
|
if (fd == NULL) {
|
|
return;
|
|
}
|
|
|
|
while (!feof(fd)) {
|
|
rc = memset_s(buf, BUF_LEN, 0, BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
(void)fgets(buf, BUF_LEN, fd);
|
|
|
|
if (is_comment_entity(buf)) {
|
|
continue;
|
|
}
|
|
index1 = strchr(buf, '#');
|
|
if (index1 != NULL) {
|
|
*index1 = '\0';
|
|
}
|
|
index2 = strchr(buf, '=');
|
|
if (index2 == NULL) {
|
|
continue;
|
|
}
|
|
src = buf;
|
|
src = trim(src);
|
|
index2 = strchr(src, '=');
|
|
key = src;
|
|
/* jump to the beginning of recorded values */
|
|
value = index2 + 1;
|
|
|
|
key = trim(key);
|
|
value = trim(value);
|
|
if (strncmp(key, ALARM_REPORT_MAX_COUNT, strlen(ALARM_REPORT_MAX_COUNT)) == 0) {
|
|
if (is_digit_string(value)) {
|
|
g_alarmReportMaxCount = atoi(value);
|
|
if (g_alarmReportMaxCount == -1) {
|
|
g_alarmReportMaxCount = ALARM_REPORT_MAX_COUNT_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
fclose(fd);
|
|
}
|
|
|
|
/*
|
|
* This function is for reading cm_server.conf parameters, which have been applied at server side.
|
|
* In cm_server this function is ugly, it should be rewritten at new version.
|
|
*/
|
|
static void get_alarm_report_interval(const char* conf)
|
|
{
|
|
get_alarm_parameters(conf);
|
|
}
|
|
|
|
void get_log_paramter(const char* confDir)
|
|
{
|
|
get_log_level(confDir);
|
|
get_log_file_size(confDir);
|
|
GetStringFromConf(confDir, sys_log_path, sizeof(sys_log_path), "log_dir");
|
|
GetStringFromConf(confDir, g_alarmComponentPath, sizeof(g_alarmComponentPath), "alarm_component");
|
|
get_alarm_report_interval(confDir);
|
|
get_alarm_report_max_count(confDir);
|
|
}
|
|
|
|
/*
|
|
* @GaussDB@
|
|
* Brief : close the current file, and open the next file
|
|
* Description :
|
|
* Notes :
|
|
*/
|
|
void switchLogFile(void)
|
|
{
|
|
char log_new_name[MAXPGPATH] = {0};
|
|
mode_t oumask;
|
|
char current_localtime[LOG_MAX_TIMELEN] = {0};
|
|
pg_time_t current_time;
|
|
struct tm* systm;
|
|
|
|
int len_log_cur_name = 0;
|
|
int len_suffix_name = 0;
|
|
int len_log_new_name = 0;
|
|
int ret = 0;
|
|
errno_t rc = 0;
|
|
|
|
current_time = time(NULL);
|
|
|
|
systm = localtime(¤t_time);
|
|
|
|
if (systm != nullptr) {
|
|
(void)strftime(current_localtime, LOG_MAX_TIMELEN, "-%Y-%m-%d_%H%M%S", systm);
|
|
}
|
|
|
|
/* close the current file */
|
|
if (syslogFile != NULL) {
|
|
fclose(syslogFile);
|
|
syslogFile = NULL;
|
|
}
|
|
|
|
/* renamed the current file without Mark */
|
|
len_log_cur_name = strlen(curLogFileName);
|
|
len_suffix_name = strlen(curLogFileMark);
|
|
len_log_new_name = len_log_cur_name - len_suffix_name;
|
|
|
|
rc = strncpy_s(log_new_name, MAXPGPATH, curLogFileName, len_log_new_name);
|
|
securec_check_errno(rc, );
|
|
rc = strncat_s(log_new_name, MAXPGPATH, ".log", strlen(".log"));
|
|
securec_check_errno(rc, );
|
|
ret = rename(curLogFileName, log_new_name);
|
|
if (ret != 0) {
|
|
printf(_("%s: rename log file %s failed! \n"), prefix_name, curLogFileName);
|
|
return;
|
|
}
|
|
|
|
/* new current file name */
|
|
rc = memset_s(curLogFileName, MAXPGPATH, 0, MAXPGPATH);
|
|
securec_check_errno(rc, );
|
|
ret = snprintf_s(curLogFileName,
|
|
MAXPGPATH,
|
|
MAXPGPATH - 1,
|
|
"%s/%s%s%s",
|
|
sys_log_path,
|
|
prefix_name,
|
|
current_localtime,
|
|
curLogFileMark);
|
|
securec_check_intval(ret, );
|
|
|
|
oumask = umask((mode_t)((~(mode_t)(S_IRUSR | S_IWUSR | S_IXUSR)) & (S_IRWXU | S_IRWXG | S_IRWXO)));
|
|
|
|
syslogFile = fopen(curLogFileName, "a");
|
|
|
|
(void)umask(oumask);
|
|
|
|
if (syslogFile == NULL) {
|
|
(void)printf("switchLogFile,switch new log file failed %s\n", strerror(errno));
|
|
} else {
|
|
if (SetFdCloseExecFlag(syslogFile) == -1) {
|
|
(void)printf("set file flag failed, filename:%s, errmsg: %s.\n", curLogFileName, strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @GaussDB@
|
|
* Brief:
|
|
* Description: write info to the files
|
|
* Notes: if the current file size is full, switch to the next
|
|
*/
|
|
void write_log_file(const char* buffer, int count)
|
|
{
|
|
int rc = 0;
|
|
|
|
(void)pthread_rwlock_wrlock(&syslog_write_lock);
|
|
|
|
if (syslogFile == NULL) {
|
|
/* maybe syslogFile no init. */
|
|
syslogFile = logfile_open(sys_log_path, "a");
|
|
}
|
|
if (syslogFile != NULL) {
|
|
count = strlen(buffer);
|
|
|
|
/* switch to the next file when current file full */
|
|
if ((ftell(syslogFile) + count) > (maxLogFileSize)) {
|
|
switchLogFile();
|
|
}
|
|
|
|
if (syslogFile != NULL) {
|
|
rc = fwrite(buffer, 1, count, syslogFile);
|
|
if (rc != count) {
|
|
printf("could not write to log file: %s %m\n", curLogFileName);
|
|
}
|
|
} else {
|
|
printf("write_log_file could not open log file %s : %m\n", curLogFileName);
|
|
}
|
|
} else {
|
|
printf("write_log_file,log file is null now:%s\n", buffer);
|
|
}
|
|
|
|
(void)pthread_rwlock_unlock(&syslog_write_lock);
|
|
}
|
|
|
|
char *errmsg(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int count = 0;
|
|
int rcs;
|
|
errno_t rc;
|
|
char errbuf[BUF_LEN] = {0};
|
|
fmt = _(fmt);
|
|
va_start(ap, fmt);
|
|
rc = memset_s(errbuf_errmsg, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
securec_check_intval(count, );
|
|
va_end(ap);
|
|
|
|
rcs = snprintf_s(errbuf_errmsg, EREPORT_BUF_LEN, EREPORT_BUF_LEN - 1, "%s", "[ERRMSG]:");
|
|
securec_check_intval(rcs, );
|
|
rc = memcpy_s(errbuf_errmsg + strlen(errbuf_errmsg), BUF_LEN - strlen(errbuf_errmsg),
|
|
errbuf, BUF_LEN - strlen(errbuf_errmsg) - 1);
|
|
securec_check_errno(rc, (void)rc);
|
|
return errbuf_errmsg;
|
|
}
|
|
|
|
char* errdetail(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int count = 0;
|
|
int rcs;
|
|
errno_t rc;
|
|
char errbuf[BUF_LEN] = {0};
|
|
fmt = _(fmt);
|
|
va_start(ap, fmt);
|
|
rc = memset_s(errbuf_errdetail, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
securec_check_intval(count, );
|
|
va_end(ap);
|
|
rcs = snprintf_s(errbuf_errdetail, EREPORT_BUF_LEN,
|
|
EREPORT_BUF_LEN - 1, "%s", "[ERRDETAIL]:");
|
|
securec_check_intval(rcs, );
|
|
rc = memcpy_s(errbuf_errdetail + strlen(errbuf_errdetail), BUF_LEN - strlen(errbuf_errdetail),
|
|
errbuf, BUF_LEN - strlen(errbuf_errdetail) - 1);
|
|
securec_check_errno(rc, (void)rc);
|
|
return errbuf_errdetail;
|
|
}
|
|
|
|
char* errcode(int sql_state)
|
|
{
|
|
int i;
|
|
int rcs;
|
|
errno_t rc;
|
|
char buf[6] = {0};
|
|
rc = memset_s(errbuf_errcode, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
/* the length of sql code is 5 */
|
|
for (i = 0; i < 5; i++) {
|
|
buf[i] = PGUNSIXBIT(sql_state);
|
|
sql_state >>= 6;
|
|
}
|
|
buf[i] = '\0';
|
|
rcs = snprintf_s(errbuf_errcode, EREPORT_BUF_LEN, EREPORT_BUF_LEN - 1, "%s%s", "[ERRCODE]:", buf);
|
|
securec_check_intval(rcs, );
|
|
return errbuf_errcode;
|
|
}
|
|
|
|
char* errcause(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int count = 0;
|
|
int rcs;
|
|
errno_t rc;
|
|
char errbuf[BUF_LEN] = {0};
|
|
fmt = _(fmt);
|
|
va_start(ap, fmt);
|
|
rc = memset_s(errbuf_errcause, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
securec_check_intval(count, );
|
|
va_end(ap);
|
|
rcs = snprintf_s(errbuf_errcause, EREPORT_BUF_LEN,
|
|
EREPORT_BUF_LEN - 1, "%s", "[ERRCAUSE]:");
|
|
securec_check_intval(rcs, );
|
|
rc = memcpy_s(errbuf_errcause + strlen(errbuf_errcause), BUF_LEN - strlen(errbuf_errcause),
|
|
errbuf, BUF_LEN - strlen(errbuf_errcause) - 1);
|
|
securec_check_errno(rc, (void)rc);
|
|
return errbuf_errcause;
|
|
}
|
|
|
|
char* erraction(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int count = 0;
|
|
int rcs;
|
|
errno_t rc;
|
|
char errbuf[BUF_LEN] = {0};
|
|
fmt = _(fmt);
|
|
va_start(ap, fmt);
|
|
rc = memset_s(errbuf_erraction, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
count = vsnprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, fmt, ap);
|
|
securec_check_intval(count, );
|
|
va_end(ap);
|
|
rcs = snprintf_s(errbuf_erraction, EREPORT_BUF_LEN,
|
|
EREPORT_BUF_LEN - 1, "%s", "[ERRACTION]:");
|
|
securec_check_intval(rcs, );
|
|
rc = memcpy_s(errbuf_erraction + strlen(errbuf_erraction), BUF_LEN - strlen(errbuf_erraction),
|
|
errbuf, BUF_LEN - strlen(errbuf_erraction) - 1);
|
|
securec_check_errno(rc, (void)rc);
|
|
return errbuf_erraction;
|
|
}
|
|
|
|
|
|
char* errmodule(ModuleId id)
|
|
{
|
|
errno_t rc = memset_s(errbuf_errmodule, EREPORT_BUF_LEN, 0, EREPORT_BUF_LEN);
|
|
securec_check_c(rc, "\0", "\0");
|
|
int rcs = snprintf_s(errbuf_errmodule, EREPORT_BUF_LEN - 1,
|
|
EREPORT_BUF_LEN - 1, "%s", "[ERRMODULE]:");
|
|
securec_check_intval(rcs, (void)rcs);
|
|
rcs = snprintf_s(errbuf_errmodule + strlen(errbuf_errmodule),
|
|
EREPORT_BUF_LEN - strlen(errbuf_errmodule),
|
|
EREPORT_BUF_LEN - strlen(errbuf_errmodule) - 1, "%s",
|
|
get_valid_module_name(id));
|
|
securec_check_intval(rcs, (void)rcs);
|
|
return errbuf_errmodule;
|
|
}
|