123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- #include "precompile.h"
- #include <winpr/sysinfo.h>
- #include <winpr/handle.h>
- #include "sp_btr.h"
- #include "fileutil.h"
- #include "memutil.h"
- #include "shm_mem.h"
- #include "y2k_time.h"
- #include "SpBase.h"
- #include "sp_logwithlinkforc.h"
- #include <winpr/string.h>
- #include <winpr/wtypes.h>
- #include <winpr/file.h>
- #ifndef _WIN32
- #define min(a,b) (((a) < (b)) ? (a) : (b))
- #endif //NOT _WIN32
- #define MAX_LINE_CHAR 256
- // 1. 不需要补充[]关机没填写的部分,读取的时候默认为死机即可
- // 2. 写文件的时候该名称.tmp,写完再改回.log,
- // 3. 如果写得过程中停电关机,那文件肯定停留在.tmp的状态,因此当系统后面检测到.tmp文件时必须删除
- // 4. 系统使用ups电源,出现3的情况很少很少
- static int get_char_count(const char *s, char ch)
- {
- int cnt = 0;
- while (*s != 0) {
- if (*s == ch)
- cnt++;
- s++;
- }
- return cnt;
- }
- int sp_btr_write_on_start(const char *bootrec_path, sp_version_t *version, sp_btr_context_t **p_ctx)
- {
- SYSTEMTIME st;
- char szCurLog[MAX_PATH] = { 0 };
- char szPreLog[MAX_PATH] = { 0 };
- HANDLE hFile = INVALID_HANDLE_VALUE;
- char line[MAX_LINE_CHAR] = { 0 };
- char *pStart;
- DWORD nMoveLen;
- LONG negMoveLen;
- int nReadLen = 0;
- char *pTemp = NULL;
- DWORD dwStartTime = 0, dwEndTime = 0;
- DWORD v1 = 0, v2 = 0, v3 = 0, v4 = 0;
- DWORD wReason = 0, wReasonNum = 0, wWay = 0, wWayNum = 0;
- int n = 0;
- BOOL bFirst;
- DWORD dwBytesWritten = 0;
- if (!ExistsDirA(bootrec_path)) {
- CreateDirA(bootrec_path, FALSE);
- }
- GetLocalTime(&st);
- sprintf(szCurLog, "%s" SPLIT_SLASH_STR "%04d%02d.log", bootrec_path, st.wYear, st.wMonth);
- *p_ctx = (sp_btr_context_t*)shm_malloc(sizeof(sp_btr_context_t));
- memset(*p_ctx, 0, sizeof(sp_btr_context_t));
- (*p_ctx)->cur_start_time = y2k_time_now();
- (*p_ctx)->cur_version = *version;
- if (st.wMonth > 1) {
- st.wMonth--;
- }
- else {
- st.wMonth = 12;
- st.wYear--;
- }
- sprintf(szPreLog, "%s" SPLIT_SLASH_STR "%04d%02d.log", bootrec_path, st.wYear, st.wMonth);
- // read last reboot way & reason from boot log
- if (ExistsFileA(szCurLog))
- hFile = CreateFileA(szCurLog, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- else if (ExistsFileA(szPreLog))
- hFile = CreateFileA(szPreLog, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- else
- {
- goto WriteLog;
- }
- if (hFile == INVALID_HANDLE_VALUE)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"open boot log file fail");
- return -11;
- }
- // read last line
- nMoveLen = min(GetFileSize(hFile, NULL), MAX_LINE_CHAR-1);
- negMoveLen = -((LONG)nMoveLen);
- if (SetFilePointer(hFile, negMoveLen, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"set file pos fail: %d", GetLastError());
- CloseHandle(hFile);
- return -2;
- }
- if (!ReadFile(hFile, line, nMoveLen, &nReadLen, NULL) || nReadLen < nMoveLen)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"read boot log fail: %d", GetLastError());
- CloseHandle(hFile);
- return -3;
- }
- CloseHandle(hFile);
- pStart = line;
- do
- {
- /** TODO: [Gifur@20201123]*/
- #ifdef _WIN32
- pTemp = strstr(pStart, "\r\n");
- if (pTemp != NULL)
- pStart = pTemp + 2;
- #else
- pTemp = strstr(pStart, "\n");
- if (pTemp != NULL)
- pStart = pTemp + 1;
- #endif //_WIN32
- } while (pTemp != NULL);
- // 20160914: 解析异常时,不退出,换行写入当前启动日志
- if (get_char_count(pStart, ',') < 1 || get_char_count(pStart, '.') < 3)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"invalide rec: [%s]", pStart);
- //return -31;
- }
- else
- {
- n = sscanf_s(pStart, "0x%X,%d.%d.%d.%d,0x%X,%d,%d,%d,%d", &dwStartTime, &v1, &v2, &v3, &v4,
- &dwEndTime, &wReason, &wReasonNum, &wWay, &wWayNum);
- if (n != 5 && n != 10)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"parse boot rec fail: [%s](%d)", pStart, n);
- #ifndef _WIN32
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"strerror: %s", strerror(errno));
- #endif //NOT _WIN32
- }
- else
- {
- (*p_ctx)->last_boot_info.tm_start = dwStartTime;
- (*p_ctx)->last_boot_info.version.major = v1;
- (*p_ctx)->last_boot_info.version.minor = v2;
- (*p_ctx)->last_boot_info.version.revision = v3;
- (*p_ctx)->last_boot_info.version.build = v4;
- if (n == 5)
- {
- DbgWithLinkForC(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM,"last shutdown time & reason unknown");
- }
- else if (n == 10)
- {
- char tmp[64] = { 0 };
- y2k_to_string(dwEndTime, tmp, sizeof(tmp));
- /** TODO: convert number to plain text [Gifur@20201123]*/
- DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM,"last shutdown at %s, reason: %d, way: %d", tmp, wReason, wWay);
- (*p_ctx)->last_boot_info.tm_shutdown = dwEndTime;
- (*p_ctx)->last_boot_info.shutdown_reason = wReason;
- (*p_ctx)->last_boot_info.shutdown_reason_cnt = wReasonNum;
- (*p_ctx)->last_boot_info.shutdown_way = wWay;
- (*p_ctx)->last_boot_info.shutdown_way_cnt = wWayNum;
- }
- }
- }
- WriteLog:
- // write boot start record
- bFirst = !ExistsFileA(szCurLog);
- hFile = CreateFileA(szCurLog, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM, "open boot file fail: %s(%d)(%d)", szCurLog, bFirst, GetLastError());
- return -5;
- }
- if (SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"set file pos fail: %d", GetLastError());
- CloseHandle(hFile);
- return -51;
- }
- memset(line, 0, sizeof(line));
- #ifdef _WIN32
- sprintf(line, "%s0x%X,%d.%d.%d.%d", bFirst ? "" : "\r\n",
- #else
- sprintf(line, "%s0x%X,%d.%d.%d.%d", bFirst ? "" : "\n",
- #endif //_WIN32
- (*p_ctx)->cur_start_time, version->major, version->minor, version->revision, version->build);
- // make startup record line
- WriteFile(hFile, line, strlen(line), &dwBytesWritten, NULL);
- if (dwBytesWritten == 0)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"write boot start fail: %d", GetLastError());
- }
- FlushFileBuffers(hFile);
- CloseHandle(hFile);
- hFile = INVALID_HANDLE_VALUE;
- return 0;
- }
- int sp_btr_write_on_shutdown(const char *bootrec_path, sp_btr_context_t *ctx, int reason, int way)
- {
- int reason_count = 1;
- int reason_way_count = 1;
- char szCurLog[MAX_PATH] = { 0 };
- HANDLE hFile;
- char line[MAX_LINE_CHAR] = { 0 };
- DWORD dwBytesWritten = 0;
- SYSTEMTIME st = { 0 };
- BOOL bWriteBootInfo = FALSE;
- if (reason == ctx->last_boot_info.shutdown_reason)
- reason_count = ctx->last_boot_info.shutdown_reason_cnt + 1;
-
- if (way == ctx->last_boot_info.shutdown_way)
- reason_way_count = ctx->last_boot_info.shutdown_way_cnt + 1;
-
- y2k_to_localtime(ctx->cur_start_time, &st);
- sprintf(szCurLog, "%s" SPLIT_SLASH_STR "%04d%02d.log", bootrec_path, st.wYear, st.wMonth);
- bWriteBootInfo = !ExistsFileA(szCurLog);
- hFile = CreateFileA(szCurLog, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"open boot file %s fail: %d", szCurLog, GetLastError());
- return -1;
- }
- if (SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"set file pos fail: %d", GetLastError());
- CloseHandle(hFile);
- return -2;
- }
- // 20160914: 如果退出和启动对应不是同一个日志文件,需要重写启动信息
- if (bWriteBootInfo)
- {
- sprintf(line, "0x%X,%d.%d.%d.%d", ctx->cur_start_time, ctx->cur_version.major, ctx->cur_version.minor, ctx->cur_version.revision, ctx->cur_version.build);
- // make startup record line
- WriteFile(hFile, line, strlen(line), &dwBytesWritten, NULL);
- }
- //TODO: 不用加换行符??
- sprintf(line, ",0x%X,%d,%d,%d,%d", y2k_time_now(), reason, reason_count, way, reason_way_count);
- WriteFile(hFile, line, strlen(line), &dwBytesWritten, NULL);
- if (dwBytesWritten == 0)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"write reboot rec fail: %d", GetLastError());
- }
- FlushFileBuffers(hFile);
- CloseHandle(hFile);
- return 0;
- }
- // 解析一行记录
- static BOOL parse_boot_record_line(const char *pLine, unsigned int before_this_time, sp_btr_reocrd_t **ppRec)
- {
- DWORD dwStartTime = 0, dwEndTime = 0;
- DWORD v1 = 0, v2 = 0, v3 = 0, v4 = 0;
- DWORD wReason = 0, wReasonNum = 0, wWay = 0, wWayNum = 0;
- int n = 0;
- if (get_char_count(pLine, ',') < 1 || get_char_count(pLine, '.') < 3)
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"invalide rec: [%s]", pLine);
- return FALSE;
- }
- n = sscanf_s(pLine, "0x%X,%d.%d.%d.%d,0x%X,%d,%d,%d,%d", &dwStartTime, &v1, &v2, &v3, &v4,
- &dwEndTime, &wReason, &wReasonNum, &wWay, &wWayNum);
- if (n == 5 || n == 10)
- {
- if (dwStartTime >= before_this_time)
- return FALSE;
- if (*ppRec == NULL)
- *ppRec = malloc(sizeof(sp_btr_reocrd_t));
- memset(*ppRec, 0, sizeof(sp_btr_reocrd_t));
- (*ppRec)->tm_start = dwStartTime;
- (*ppRec)->version.major = v1;
- (*ppRec)->version.minor = v2;
- (*ppRec)->version.revision = v3;
- (*ppRec)->version.build = v4;
- if (n == 10)
- {
- (*ppRec)->tm_shutdown = dwEndTime;
- (*ppRec)->shutdown_reason = wReason;
- (*ppRec)->shutdown_reason_cnt = wReasonNum;
- (*ppRec)->shutdown_way = wWay;
- (*ppRec)->shutdown_way_cnt = wWayNum;
- }
- }
- return TRUE;
- }
- // 解析一个日志文件
- static sp_btr_reocrd_t* find_rec_from_file_before(const char *pLogName, unsigned int before_this_time)
- {
- sp_btr_reocrd_t *pRec = NULL;
- char szLine[8 * 1024] = { 0 };
- int nLeftLen = 0;
- HANDLE hFile = INVALID_HANDLE_VALUE;
- BOOL bHasLeft = TRUE;
-
- hFile = CreateFileA(pLogName, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- return NULL;
- while (bHasLeft)
- {
- DWORD nReadLen = 0;
- char *pStart = szLine;
- BOOL bRet = ReadFile(hFile, pStart + nLeftLen, sizeof(szLine)-nLeftLen - 1, &nReadLen, NULL);
- if (!bRet || nReadLen == 0)
- break;
- if (nReadLen < sizeof(szLine)-nLeftLen - 1)
- bHasLeft = FALSE;
- nLeftLen += nReadLen;
- szLine[nLeftLen] = 0;
- // 解析行
- while (TRUE)
- {
- char *p = strstr(pStart, "\r\n");
- if (p == NULL && bHasLeft)
- break;
- if (p != NULL)
- {
- *p = 0;
- *(p + 1) = 0;
- }
- // 返回失败(启动时间超出或格式错误)则返回
- if (!parse_boot_record_line(pStart, before_this_time, &pRec))
- goto RETURN;
- if (p != NULL)
- {
- nLeftLen -= p + 2 - pStart;
- pStart = p + 2;
- }
- else
- goto RETURN;
- }
- // 重新移动数据
- if (szLine != pStart && nLeftLen > 0)
- {
- memmove_s(szLine, sizeof(szLine), pStart, nLeftLen);
- memset(szLine + nLeftLen, 0, sizeof(szLine)-nLeftLen); // memory set zero
- }
- }
- RETURN:
- CloseHandle(hFile);
- return pRec;
- }
- sp_btr_reocrd_t* sp_btr_get_rec_before(const char *bootrec_path, sp_btr_context_t *ctx, unsigned int before_this_time)
- {
- SYSTEMTIME st = { 0 };
- char szBootLog[MAX_PATH] = { 0 };
- sp_btr_reocrd_t *pRec = NULL;
- int nTryCount = 0;
- // 返回上次重启记录
- if (before_this_time == 0)
- {
- if (ctx->last_boot_info.tm_start == 0)
- return NULL;
- pRec = (sp_btr_reocrd_t*)malloc(sizeof(sp_btr_reocrd_t));
- *pRec = ctx->last_boot_info;
- return pRec;
- }
- y2k_to_localtime(before_this_time, &st);
- while (nTryCount++ <= 12)
- {
- sprintf(szBootLog, "%s" SPLIT_SLASH_STR "%04d%02d.log", bootrec_path, st.wYear, st.wMonth);
- if (!ExistsFileA(szBootLog))
- {
- DbgWithLinkForC(LOG_LEVEL_ERROR, LOG_TYPE_SYSTEM,"boot log %s not exists", szBootLog);
- }
- else
- {
- DbgWithLinkForC(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM, "parse log %s now", szBootLog);
- pRec = find_rec_from_file_before(szBootLog, before_this_time);
- if (pRec != NULL)
- return pRec;
- }
- if (st.wMonth > 1)
- st.wMonth--;
- else
- {
- st.wMonth = 12;
- st.wYear--;
- }
- }
- return NULL;
- }
|