1/* 2 * Copyright (C) 2022 Huawei Technologies Co., Ltd. 3 * Licensed under the Mulan PSL v2. 4 * You can use this software according to the terms and conditions of the Mulan PSL v2. 5 * You may obtain a copy of Mulan PSL v2 at: 6 * http://license.coscl.org.cn/MulanPSL2 7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR 8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR 9 * PURPOSE. 10 * See the Mulan PSL v2 for more details. 11 */ 12#include "tlogcat.h" 13 14#include <string.h> 15#include <unistd.h> 16#include <fcntl.h> 17#include <time.h> 18#include <errno.h> 19#include <ctype.h> 20#include <dirent.h> 21#include <sys/types.h> 22#include <sys/stat.h> 23#include <sys/ioctl.h> /* for ioctl */ 24#include <sys/select.h> 25#include <securec.h> 26 27#include "tee_log.h" 28#include "tarzip.h" 29#include "proc_tag.h" 30#include "sys_log_api.h" 31 32#ifdef LOG_TAG 33#undef LOG_TAG 34#endif 35#define LOG_TAG "tlogcat" 36 37#define LOG_FILE_TA_DEMO "LOG@A32B3D00CB5711E39C1A0800200C9A66-0" 38#define LOG_FILE_TA_COMPRESS_DEMO "LOG@A32B3D00CB5711E39C1A0800200C9A66-0.tar.gz" 39#define LOG_FILE_TEE_DEMO "teeOS_log-0" 40#define LOG_FILE_TEE_COMPRESS_DEMO "teeos-log-0.tar.gz" 41 42#define TLOGCAT_FILE_MODE 0750 43#define UUID_MAX_STR_LEN 40U 44/* for log item */ 45#define LOG_ITEM_MAGIC 0x5A5A 46#define LOG_ITEM_LEN_ALIGN 64 47#define LOG_READ_STATUS_ERROR 0x000FFFF 48 49#ifndef FILE_NAME_MAX_BUF 50#define FILE_NAME_MAX_BUF 256 51#endif 52 53#define LOG_BUFFER_LEN 0x2000 /* 8K */ 54#define LOG_FILES_MAX 128U 55#define FILE_VALID 0x5a5aa5a5 56#define LOG_FILE_LIMIT (500 * 1024) /* log file size limit:500k */ 57#define MAX_TEE_VERSION_LEN 256U 58 59#ifndef TEE_LOG_SUBFOLDER 60#define TEE_LOG_SUBFOLDER "tee" 61#endif 62 63char g_teePath[FILE_NAME_MAX_BUF] = {0}; 64char g_teeTempPath[FILE_NAME_MAX_BUF] = {0}; 65gid_t g_teePathGroup = 0; 66#ifdef CONFIG_TEE_PRIVATE_LOGFILE 67struct LogFile { 68 FILE *file; 69 struct TeeUuid uuid; 70 long fileLen; 71 uint32_t fileIndex; /* 0,1,2,3 */ 72 int32_t valid; /* FILE_VALID */ 73 char logName[FILE_NAME_MAX_BUF]; 74}; 75static struct LogFile *g_files = NULL; 76#endif 77static char *g_compressFile = NULL; 78static struct TeeUuid g_compressUuid; 79char *g_logBuffer = NULL; 80 81/* for ioctl */ 82#define TEELOGGERIO 0xBE 83#define GET_VERSION_BASE 5 84#define SET_READERPOS_CUR_BASE 6 85#define SET_TLOGCAT_STAT_BASE 7 86#define GET_TLOGCAT_STAT_BASE 8 87 88#define TEELOGGER_GET_VERSION _IOR(TEELOGGERIO, GET_VERSION_BASE, char[MAX_TEE_VERSION_LEN]) 89/* set the log reader pos to current pos */ 90#define TEELOGGER_SET_READERPOS_CUR _IO(TEELOGGERIO, SET_READERPOS_CUR_BASE) 91#define TEELOGGER_SET_TLOGCAT_STAT _IO(TEELOGGERIO, SET_TLOGCAT_STAT_BASE) 92#define TEELOGGER_GET_TLOGCAT_STAT _IO(TEELOGGERIO, GET_TLOGCAT_STAT_BASE) 93 94static int32_t g_devFd = -1; 95static char g_teeVersion[MAX_TEE_VERSION_LEN]; 96static int32_t g_readposCur = 0; 97 98#ifdef CONFIG_TEE_PRIVATE_LOGFILE 99static int32_t GetLogPathBasePos(const char *temp, char **pos) 100{ 101 if (access(TEE_LOG_PATH_BASE, F_OK) != 0) { 102 tloge("log dir is not exist\n"); 103 return -1; 104 } 105 106 if (strncmp(temp, TEE_LOG_PATH_BASE, strlen(TEE_LOG_PATH_BASE)) == 0) { 107 *pos += strlen(TEE_LOG_PATH_BASE); 108 } 109 return 0; 110} 111 112/* 113 * path:file path name. 114 * P: /data/vendor/log/hisi_logs/tee/ 115 * before P version: /data/hisi_logs/running_trace/teeos_logs/LOG@A32B3D00CB5711E39C1A0800200C9A66-0 116 */ 117static int32_t LogFilesMkdirR(const char *path) 118{ 119 int32_t ret; 120 bool check = false; 121 char *temp = strdup(path); 122 char *pos = temp; 123 124 if (temp == NULL) { 125 return -1; 126 } 127 128 ret = GetLogPathBasePos(temp, &pos); 129 if (ret != 0) { 130 free(temp); 131 return ret; 132 } 133 134 for (; *pos != '\0'; ++pos) { 135 if (*pos == '/') { 136 *pos = '\0'; 137 138 ret = mkdir(temp, S_IRWXU | S_IRWXG); 139 check = (ret < 0 && errno == EEXIST); 140 if (check) { 141 /* file is exist */ 142 *pos = '/'; 143 continue; 144 } else if (ret != 0) { 145 tloge("mkdir %s fail, errno %d\n", temp, errno); 146 free(temp); 147 return -1; 148 } 149 ret = chmod(temp, TLOGCAT_FILE_MODE); 150 if (ret < 0) { 151 tloge("chmod %s err %d\n", temp, ret); 152 } 153 tlogv("for %s\n", temp); 154 *pos = '/'; 155 } 156 } 157 158 free(temp); 159 return 0; 160} 161 162static void GetUuidStr(const struct TeeUuid *uuid, char *name, uint32_t nameLen) 163{ 164 int32_t ret = snprintf_s(name, nameLen, nameLen - 1, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", 165 uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, uuid->clockSeqAndNode[0], 166 uuid->clockSeqAndNode[1], uuid->clockSeqAndNode[2], uuid->clockSeqAndNode[3], 167 uuid->clockSeqAndNode[4], uuid->clockSeqAndNode[5], uuid->clockSeqAndNode[6], 168 uuid->clockSeqAndNode[7]); 169 if (ret <= 0) { 170 tloge("convert uuid to string failed\n"); 171 } 172 173 return; 174} 175 176static struct LogFile *LogFilesAdd(const struct TeeUuid *uuid, const char *logName, 177 FILE *file, long fileLen, uint32_t index) 178{ 179 uint32_t i; 180 errno_t rc; 181 182 for (i = 0; i < LOG_FILES_MAX; i++) { 183 /* filter valid file */ 184 if (g_files[i].file != NULL || g_files[i].valid == FILE_VALID) { 185 continue; 186 } 187 188 rc = memcpy_s(g_files[i].logName, sizeof(g_files[i].logName), logName, strlen(logName) + 1); 189 if (rc != EOK) { 190 tloge("memcpy log name failed\n"); 191 goto CLOSE_F; 192 } 193 194 rc = memcpy_s(&g_files[i].uuid, sizeof(g_files[i].uuid), uuid, sizeof(struct TeeUuid)); 195 if (rc != EOK) { 196 tloge("memcpy uuid failed\n"); 197 goto CLOSE_F; 198 } 199 200 g_files[i].file = file; 201 g_files[i].fileLen = fileLen; 202 g_files[i].fileIndex = index; 203 g_files[i].valid = FILE_VALID; 204 205 return &g_files[i]; 206 } 207 208CLOSE_F: 209 (void)fclose(file); 210 return NULL; 211} 212 213static void CloseFileFd(int32_t *fd) 214{ 215 if (*fd < 0) { 216 return; 217 } 218 219 close(*fd); 220 *fd = -1; 221} 222 223static FILE *LogFilesOpen(const char *logName, long *fileLen) 224{ 225 int32_t ret; 226 FILE *file = NULL; 227 bool isNewFile = false; 228 229 int32_t fd1 = open(logName, O_WRONLY); 230 if (fd1 < 0) { 231 /* file is not exist */ 232 file = fopen(logName, "a+"); 233 isNewFile = true; 234 } else { 235 /* file is exist */ 236 file = fdopen(fd1, "w"); 237 } 238 239 if (file == NULL) { 240 tloge("open error:logName %s, errno %d\n", logName, errno); 241 CloseFileFd(&fd1); 242 return NULL; 243 } 244 245 int32_t fd2 = fileno(file); 246 if (fd2 < 0) { 247 tloge("fileno is error\n"); 248 (void)fclose(file); 249 return NULL; 250 } 251 ret = fchmod(fd2, S_IRUSR | S_IWUSR | S_IRGRP); 252 if (ret < 0) { 253 tloge("chmod error\n"); 254 } 255 256 (void)fseek(file, 0L, SEEK_END); /* seek to file ending */ 257 if (fileLen != NULL) { 258 *fileLen = ftell(file); /* get file len */ 259 } 260 261 /* write tee version info */ 262 if (isNewFile) { 263 size_t ret1 = fwrite(g_teeVersion, 1, strlen(g_teeVersion), file); 264 if (ret1 == 0) { 265 tloge("write tee verion to %s failed %zu\n", logName, ret1); 266 } 267 } 268 269 return file; 270} 271#endif 272 273static bool IsTaUuid(const struct TeeUuid *uuid) 274{ 275 if (uuid == NULL) { 276 return false; 277 } 278 279 uint32_t i; 280 uint8_t *p = (uint8_t *)uuid; 281 for (i = 0; i < sizeof(*uuid); i++) { 282 if (p[i] != 0) { 283 return true; 284 } 285 } 286 287 return false; 288} 289 290#ifdef CONFIG_TEE_PRIVATE_LOGFILE 291struct FileNameAttr { 292 const char *uuidAscii; 293 bool isTa; 294 uint32_t index; 295}; 296 297static void SetFileNameAttr(struct FileNameAttr *nameAttr, const char *uuidAscii, 298 bool isTa, uint32_t index) 299{ 300 nameAttr->uuidAscii = uuidAscii; 301 nameAttr->isTa = isTa; 302 nameAttr->index = index; 303} 304 305static int32_t LogAssembleFilename(char *logName, size_t logNameLen, 306 const char *logPath, const struct FileNameAttr *nameAttr) 307{ 308 if (nameAttr->isTa) { 309 return snprintf_s(logName, logNameLen, strlen(LOG_FILE_TA_DEMO) + strlen(logPath), "%s%s%s-%u", 310 logPath, "LOG@", nameAttr->uuidAscii, nameAttr->index); 311 } else { 312 return snprintf_s(logName, logNameLen, strlen(LOG_FILE_TEE_DEMO) + strlen(logPath), "%s%s-%u", 313 logPath, "teeOS_log", nameAttr->index); 314 } 315} 316 317static int32_t LogAssembleCompressFilename(char *logName, size_t logNameLen, 318 const char *logPath, const struct FileNameAttr *nameAttr) 319{ 320 if (nameAttr->isTa) { 321 return snprintf_s(logName, logNameLen, strlen(LOG_FILE_TA_COMPRESS_DEMO) + strlen(logPath), 322 "%s%s%s-%u.tar.gz", logPath, "LOG@", nameAttr->uuidAscii, nameAttr->index); 323 } else { 324 return snprintf_s(logName, logNameLen, strlen(LOG_FILE_TEE_COMPRESS_DEMO) + strlen(logPath), 325 "%s%s-%u.tar.gz", logPath, "teeos-log", nameAttr->index); 326 } 327} 328 329static void TriggerCompress(void) 330{ 331 char *filesToCompress[LOG_FILE_INDEX_MAX] = {0}; 332 uint32_t i; 333 int32_t ret; 334 char uuidAscii[UUID_MAX_STR_LEN] = {0}; 335 struct FileNameAttr nameAttr = {0}; 336 bool isTa = IsTaUuid(&g_compressUuid); 337 338 GetUuidStr(&g_compressUuid, uuidAscii, sizeof(uuidAscii)); 339 340 for (i = 0; i < LOG_FILE_INDEX_MAX; i++) { 341 filesToCompress[i] = malloc(FILE_NAME_MAX_BUF); 342 if (filesToCompress[i] == NULL) { 343 tloge("malloc file for compress failed\n"); 344 goto FREE_RES; 345 } 346 347 SetFileNameAttr(&nameAttr, uuidAscii, isTa, i); 348 ret = LogAssembleFilename(filesToCompress[i], FILE_NAME_MAX_BUF, g_teeTempPath, &nameAttr); 349 if (ret < 0) { 350 tloge("snprintf file to compress error %d %s, %s, %u\n", ret, g_teeTempPath, uuidAscii, i); 351 continue; 352 } 353 } 354 355 TarZipFiles(LOG_FILE_INDEX_MAX, (const char**)filesToCompress, g_compressFile, g_teePathGroup); 356 357FREE_RES: 358 /* remove compressed logs */ 359 for (i = 0; i < LOG_FILE_INDEX_MAX; i++) { 360 if (filesToCompress[i] == NULL) { 361 continue; 362 } 363 364 ret = unlink(filesToCompress[i]); 365 if (ret < 0) { 366 tloge("unlink file %s failed, ret %d\n", filesToCompress[i], ret); 367 } 368 free(filesToCompress[i]); 369 } 370 371 ret = rmdir(g_teeTempPath); 372 if (ret < 0) { 373 tloge("rmdir failed %s, ret %d, errno %d\n", g_teeTempPath, ret, errno); 374 } 375} 376#endif 377 378char g_logNameCompress[FILE_NAME_MAX_BUF] = {0}; 379char g_uuidAscii[UUID_MAX_STR_LEN] = {0}; 380char g_logName[FILE_NAME_MAX_BUF] = {0}; 381 382#ifdef CONFIG_TEE_PRIVATE_LOGFILE 383static char *GetCompressFile(const struct TeeUuid *uuid) 384{ 385 uint32_t i; 386 struct FileNameAttr nameAttr = {0}; 387 bool isTa = IsTaUuid(uuid); 388 389 /* 390 * Find a suitable compressed file name, 391 * %s-0.tar.gz, %s-1.tar.gz %s-2.tar.gz %s-3.tar.gz then to zero, recycle using 392 */ 393 for (i = 0; i < LOG_FILE_INDEX_MAX; i++) { 394 SetFileNameAttr(&nameAttr, g_uuidAscii, isTa, i); 395 int32_t rc = LogAssembleCompressFilename(g_logNameCompress, sizeof(g_logNameCompress), g_teePath, &nameAttr); 396 if (rc < 0) { 397 tloge("snprintf log name compresserror error %d %s %s %u\n", rc, g_teePath, g_uuidAscii, i); 398 continue; 399 } 400 401 if (access(g_logNameCompress, F_OK) != 0) { 402 break; 403 } 404 } 405 406 if (i >= LOG_FILE_INDEX_MAX) { 407 return NULL; 408 } 409 410 return g_logNameCompress; 411} 412 413static void ArrangeCompressFile(const struct TeeUuid *uuid) 414{ 415 uint32_t i; 416 int32_t ret; 417 struct FileNameAttr nameAttr = {0}; 418 bool isTa = IsTaUuid(uuid); 419 420 /* delete first file, and other files's name number rename forward. */ 421 SetFileNameAttr(&nameAttr, g_uuidAscii, isTa, 0); 422 ret = LogAssembleCompressFilename(g_logName, sizeof(g_logName), g_teePath, &nameAttr); 423 if (ret < 0) { 424 tloge("arrange snprintf error %d %s %s %d\n", ret, g_teePath, g_uuidAscii, 0); 425 return; 426 } 427 ret = unlink(g_logName); 428 if (ret < 0) { 429 tloge("unlink failed %s, %d\n", g_logName, ret); 430 } 431 432 /* 433 * Updates the names of files except the first file. 434 * Use the last file name as the compress file name. 435 */ 436 for (i = 1; i < LOG_FILE_INDEX_MAX; i++) { 437 SetFileNameAttr(&nameAttr, g_uuidAscii, isTa, i); 438 ret = LogAssembleCompressFilename(g_logNameCompress, sizeof(g_logNameCompress), g_teePath, &nameAttr); 439 if (ret < 0) { 440 tloge("snprintf log name compress error %d %s %s %u\n", ret, g_teePath, g_uuidAscii, i); 441 continue; 442 } 443 444 ret = rename(g_logNameCompress, g_logName); 445 if (ret < 0) { 446 tloge("rename error %s, %s, %d, errno %d\n", g_logNameCompress, g_logName, ret, errno); 447 } 448 449 ret = memcpy_s(g_logName, sizeof(g_logName), g_logNameCompress, sizeof(g_logNameCompress)); 450 if (ret != EOK) { 451 tloge("memcpy_s error %d\n", ret); 452 return; 453 } 454 } 455} 456 457static void UnlinkTmpFile(const char *name) 458{ 459 struct stat st = {0}; 460 461 if (lstat(name, &st) < 0) { 462 tloge("lstat %s failed, errno is %d\n", name, errno); 463 return; 464 } 465 466 if (S_ISDIR(st.st_mode)) { 467 return; 468 } 469 470 if (unlink(name) < 0) { 471 tloge("unlink %s failed, errno is %d\n", name, errno); 472 } 473} 474 475static void LogTmpDirClear(const char *tmpPath) 476{ 477 int32_t ret; 478 char filePathName[FILE_NAME_MAX_BUF] = {0}; 479 480 DIR *dir = opendir(tmpPath); 481 if (dir == NULL) { 482 tloge("open dir %s failed, errno:%d\n", tmpPath, errno); 483 return; 484 } 485 486 struct dirent *de = readdir(dir); 487 488 while (de != NULL) { 489 if (strncmp(de->d_name, "..", sizeof("..")) == 0 || strncmp(de->d_name, ".", sizeof(".")) == 0) { 490 de = readdir(dir); 491 continue; 492 } 493 ret = snprintf_s(filePathName, sizeof(filePathName), sizeof(filePathName) - 1, 494 "%s/%s", tmpPath, de->d_name); 495 if (ret == -1) { 496 tloge("get fiel path name failed %d\n", ret); 497 de = readdir(dir); 498 continue; 499 } 500 UnlinkTmpFile(filePathName); 501 de = readdir(dir); 502 } 503 504 (void)closedir(dir); 505 ret = rmdir(tmpPath); 506 if (ret < 0) { 507 tloge("clear %s failed, err:%d, errno:%d\n", tmpPath, ret, errno); 508 } 509} 510 511static int32_t MkdirTmpPath(const char *tmpPath) 512{ 513 int32_t ret; 514 515 /* create a temp path, and move these files to this path for compressing */ 516 ret = rmdir(tmpPath); 517 518 bool check = (ret < 0 && errno != ENOENT); 519 if (check) { 520 LogTmpDirClear(tmpPath); 521 } 522 523 ret = mkdir(tmpPath, TLOGCAT_FILE_MODE); 524 if (ret < 0) { 525 tloge("mkdir %s failed, errno:%d\n", tmpPath, errno); 526 return -1; 527 } 528 return 0; 529} 530 531static void MoveFileToTmpPath(bool isTa, uint32_t index) 532{ 533 int32_t ret; 534 struct FileNameAttr nameAttr = {0}; 535 536 SetFileNameAttr(&nameAttr, g_uuidAscii, isTa, index); 537 ret = LogAssembleFilename(g_logName, sizeof(g_logName), g_teePath, &nameAttr); 538 if (ret < 0) { 539 tloge("snprintf log name error %d %s %s %u\n", ret, g_teePath, g_uuidAscii, index); 540 return; 541 } 542 543 ret = LogAssembleFilename(g_logNameCompress, sizeof(g_logNameCompress), g_teeTempPath, &nameAttr); 544 if (ret < 0) { 545 tloge("snprintf log name compress error %d %s %s %u\n", ret, g_teeTempPath, g_uuidAscii, index); 546 return; 547 } 548 549 ret = rename(g_logName, g_logNameCompress); 550 bool check = (ret < 0 && errno != ENOENT); 551 /* File is exist, but rename is failed */ 552 if (check) { 553 tloge("rename %s failed, err: %d, errno:%d\n", g_logName, ret, errno); 554 ret = unlink(g_logName); 555 if (ret < 0) { 556 tloge("unlink failed %s %d\n", g_logName, ret); 557 } 558 } 559} 560 561static void LogFilesCompress(const struct TeeUuid *uuid) 562{ 563 int32_t i; 564 int32_t rc; 565 bool isTa = IsTaUuid(uuid); 566 567 rc = MkdirTmpPath(g_teeTempPath); 568 if (rc != 0) { 569 return; 570 } 571 572 GetUuidStr(uuid, g_uuidAscii, sizeof(g_uuidAscii)); 573 574 for (i = LOG_FILE_INDEX_MAX - 1; i >= 0; i--) { 575 MoveFileToTmpPath(isTa, (uint32_t)i); 576 } 577 578 /* 579 * Find a suitable compressed file name, 580 * %s-0.tar.gz, %s-1.tar.gz %s-2.tar.gz %s-3.tar.gz then to zero, recycle using. 581 */ 582 if (GetCompressFile(uuid) == NULL) { 583 /* 584 * Delete first file, and other files's name number rename forward. 585 * Use the last file name as the compress file name. 586 */ 587 ArrangeCompressFile(uuid); 588 } 589 590 g_compressFile = g_logNameCompress; 591 rc = memcpy_s(&g_compressUuid, sizeof(g_compressUuid), uuid, sizeof(struct TeeUuid)); 592 if (rc != EOK) { 593 tloge("memcpy_s error %d\n", rc); 594 return; 595 } 596 597 TriggerCompress(); 598} 599 600static void LogFileFull(uint32_t fileNum) 601{ 602 char logName[FILE_NAME_MAX_BUF] = {0}; 603 char logName2[FILE_NAME_MAX_BUF] = {0}; 604 char uuidAscii[UUID_MAX_STR_LEN] = {0}; 605 int32_t rc; 606 struct FileNameAttr nameAttr = {0}; 607 608 if (g_files[fileNum].fileIndex >= LOG_FILE_INDEX_MAX) { 609 tloge("the file index is overflow %u\n", g_files[fileNum].fileIndex); 610 return; 611 } 612 613 bool isTa = IsTaUuid(&g_files[fileNum].uuid); 614 615 GetUuidStr(&g_files[fileNum].uuid, uuidAscii, sizeof(uuidAscii)); 616 617 SetFileNameAttr(&nameAttr, uuidAscii, isTa, 0); 618 rc = LogAssembleFilename(logName, sizeof(logName), g_teePath, &nameAttr); 619 if (rc < 0) { 620 tloge("snprintf log name error %d %s %s %d\n", rc, g_teePath, uuidAscii, 0); 621 return; 622 } 623 624 SetFileNameAttr(&nameAttr, uuidAscii, isTa, g_files[fileNum].fileIndex + 1); 625 rc = LogAssembleFilename(logName2, sizeof(logName2), g_teePath, &nameAttr); 626 if (rc < 0) { 627 tloge("snprintf log name2 error %d %s %s %u\n", rc, g_teePath, uuidAscii, g_files[fileNum].fileIndex + 1); 628 return; 629 } 630 631 rc = rename(logName, logName2); 632 if (rc < 0) { 633 tloge("file full and rename error %s, %s, %d, errno %d\n", logName, logName2, rc, errno); 634 } 635 636 return; 637} 638 639static int32_t LogFilesChecklimit(uint32_t fileNum) 640{ 641 if (g_files[fileNum].fileLen >= LOG_FILE_LIMIT) { 642 (void)fclose(g_files[fileNum].file); 643 644 if (g_files[fileNum].fileIndex >= (LOG_FILE_INDEX_MAX - 1)) { 645 /* four files are all full, need to compress files. */ 646 LogFilesCompress(&g_files[fileNum].uuid); 647 } else { 648 /* this file is full */ 649 LogFileFull(fileNum); 650 } 651 652 errno_t rc = memset_s(&g_files[fileNum], sizeof(g_files[fileNum]), 0, sizeof(struct LogFile)); 653 if (rc != EOK) { 654 tloge("memset failed %d\n", rc); 655 } 656 657 return -1; 658 } 659 660 return 0; 661} 662 663static struct LogFile *GetUsableFile(const struct TeeUuid *uuid) 664{ 665 uint32_t i; 666 667 for (i = 0; i < LOG_FILES_MAX; i++) { 668 if (memcmp(&g_files[i].uuid, uuid, sizeof(struct TeeUuid)) != 0) { 669 continue; 670 } 671 672 if (g_files[i].valid != FILE_VALID) { 673 continue; 674 } 675 676 if (g_files[i].file == NULL) { 677 tloge("unexpected error in index %u, file is null\n", i); 678 (void)memset_s(&g_files[i], sizeof(g_files[i]), 0, sizeof(g_files[i])); 679 continue; 680 } 681 682 /* check file len is limit */ 683 if (LogFilesChecklimit(i) != 0) { 684 continue; 685 } 686 687 tlogd("get log file %s\n", g_files[i].logName); 688 return &g_files[i]; 689 } 690 691 return NULL; 692} 693 694static void GetFileIndex(const char *uuidAscii, bool isTa, uint32_t *fileIndex) 695{ 696 char logName[FILE_NAME_MAX_BUF] = {0}; 697 int32_t i; 698 struct FileNameAttr nameAttr = {0}; 699 700 /* get the number of file */ 701 for (i = LOG_FILE_INDEX_MAX - 1; i >= 0; i--) { 702 *fileIndex = (uint32_t)i; 703 704 SetFileNameAttr(&nameAttr, uuidAscii, isTa, (uint32_t)i); 705 int32_t ret = LogAssembleFilename(logName, sizeof(logName), g_teePath, &nameAttr); 706 if (ret < 0) { 707 tloge("snprintf log name error %d %s %s %d\n", ret, g_teePath, uuidAscii, i); 708 continue; 709 } 710 711 if (access(logName, F_OK) == 0) { 712 break; 713 } 714 } 715} 716 717static struct LogFile *LogFilesGet(const struct TeeUuid *uuid, bool isTa) 718{ 719 uint32_t fileIndex; 720 errno_t rc; 721 char logName[FILE_NAME_MAX_BUF] = {0}; 722 char uuidAscii[UUID_MAX_STR_LEN] = {0}; 723 long fileLen; 724 FILE *file = NULL; 725 struct FileNameAttr nameAttr = {0}; 726 727 if (uuid == NULL) { 728 return NULL; 729 } 730 731 struct LogFile *logFile = GetUsableFile(uuid); 732 if (logFile != NULL) { 733 return logFile; 734 } 735 736 /* base on uuid data, new a file */ 737 if (LogFilesMkdirR(g_teePath) != 0) { 738 tloge("mkdir log path is failed\n"); 739 return NULL; 740 } 741 GetUuidStr(uuid, uuidAscii, sizeof(uuidAscii)); 742 743 /* get the number of file */ 744 GetFileIndex(uuidAscii, isTa, &fileIndex); 745 746 /* each time write the "-0" suffix name file */ 747 SetFileNameAttr(&nameAttr, uuidAscii, isTa, 0); 748 rc = LogAssembleFilename(logName, sizeof(logName), g_teePath, &nameAttr); 749 if (rc < 0) { 750 tloge("snprintf log name error %d %s %s\n", rc, g_teePath, uuidAscii); 751 return NULL; 752 } 753 754 file = LogFilesOpen(logName, &fileLen); 755 if (file == NULL) { 756 return NULL; 757 } 758 759 return LogFilesAdd(uuid, logName, file, fileLen, fileIndex); 760} 761 762static void LogFilesClose(void) 763{ 764 uint32_t i; 765 766 if (g_files == NULL) { 767 return; 768 } 769 770 /* 771 * Check whether the file size exceeds the value of LOG_FILE_LIMIT. If yes, create another file. 772 * If the four files are all full, compress the files and delete the original files. 773 */ 774 for (i = 0; i < LOG_FILES_MAX; i++) { 775 if (g_files[i].file == NULL) { 776 continue; 777 } 778 779 tlogd("close file %s, fileLen %ld\n", g_files[i].logName, g_files[i].fileLen); 780 (void)fflush(g_files[i].file); 781 (void)fclose(g_files[i].file); 782 783 if (g_files[i].fileLen >= LOG_FILE_LIMIT) { 784 if (g_files[i].fileIndex >= (LOG_FILE_INDEX_MAX - 1)) { 785 /* four files are all full, need to compress files. */ 786 LogFilesCompress(&g_files[i].uuid); 787 } else { 788 /* this file is full */ 789 LogFileFull(i); 790 } 791 } 792 793 (void)memset_s(&g_files[i], sizeof(g_files[i]), 0, sizeof(g_files[i])); 794 } 795} 796#endif 797 798static void HelpShow(void) 799{ 800 printf("this is help, you should input:\n"); 801 printf(" -v: print Tee version\n"); 802 printf(" -t: only print the new log\n"); 803} 804 805static struct LogItem *LogItemGetNext(const char *logBuffer, size_t scopeLen) 806{ 807 if (logBuffer == NULL) { 808 return NULL; 809 } 810 811 struct LogItem *logItemNext = (struct LogItem *)logBuffer; 812 813 size_t itemMaxSize = ((scopeLen > LOG_ITEM_MAX_LEN) ? LOG_ITEM_MAX_LEN : scopeLen); 814 815 bool isValidItem = ((logItemNext->magic == LOG_ITEM_MAGIC) && 816 (logItemNext->logBufferLen > 0) && (logItemNext->logRealLen > 0) && 817 (logItemNext->logBufferLen % LOG_ITEM_LEN_ALIGN == 0) && 818 (logItemNext->logRealLen <= logItemNext->logBufferLen) && 819 ((logItemNext->logBufferLen - logItemNext->logRealLen) < LOG_ITEM_LEN_ALIGN) && 820 (logItemNext->logBufferLen + sizeof(struct LogItem) <= itemMaxSize)); 821 if (isValidItem) { 822 return logItemNext; 823 } 824 825 tlogd("logItemNext info: magic %x, logBufferLen %x, logRealLen %x\n", 826 logItemNext->magic, logItemNext->logBufferLen, logItemNext->logRealLen); 827 return NULL; 828} 829 830static void LogSetReadposCur(void) 831{ 832 int32_t ret; 833 if (g_devFd < 0) { 834 tloge("open log device error\n"); 835 return; 836 } 837 ret = ioctl(g_devFd, TEELOGGER_SET_READERPOS_CUR, 0); 838 if (ret != 0) { 839 tloge("set readpos cur failed %d\n", ret); 840 } 841 842 g_readposCur = 1; 843 return; 844} 845 846static int32_t LogSetTlogcatF(void) 847{ 848 int32_t ret; 849 850 if (g_devFd < 0) { 851 tloge("open log device error\n"); 852 return -1; 853 } 854 855 ret = ioctl(g_devFd, TEELOGGER_SET_TLOGCAT_STAT, 0); 856 if (ret != 0) { 857 tloge("set tlogcat status failed %d\n", ret); 858 } 859 860 return ret; 861} 862 863static int32_t LogGetTlogcatF(void) 864{ 865 int32_t ret; 866 867 if (g_devFd < 0) { 868 tloge("open log device error\n"); 869 return -1; 870 } 871 872 ret = ioctl(g_devFd, TEELOGGER_GET_TLOGCAT_STAT, 0); 873 if (ret != 0) { 874 tloge("get tlogcat status failed %d\n", ret); 875 } 876 877 return ret; 878} 879 880#ifdef CONFIG_TEE_PRIVATE_LOGFILE 881static void WritePrivateLogFile(const struct LogItem *logItem, bool isTa) 882{ 883 size_t writeNum; 884 885 struct LogFile *logFile = LogFilesGet((struct TeeUuid *)logItem->uuid, isTa); 886 if ((logFile == NULL) || (logFile->file == NULL)) { 887 tloge("can not save log, file is null\n"); 888 return; 889 } 890 891 writeNum = fwrite(logItem->logBuffer, 1, (size_t)logItem->logRealLen, logFile->file); 892 if (writeNum != (size_t)logItem->logRealLen) { 893 tloge("save file failed %zu, %u\n", writeNum, logItem->logRealLen); 894 (void)fclose(logFile->file); 895 (void)memset_s(logFile, sizeof(struct LogFile), 0, sizeof(struct LogFile)); 896 } 897 898 logFile->fileLen += (long)writeNum; 899} 900#endif 901 902static void WriteLogFile(const struct LogItem *logItem) 903{ 904 bool isTa = IsTaUuid((struct TeeUuid *)logItem->uuid); 905 906 LogWriteSysLog(logItem, isTa); 907#ifdef CONFIG_TEE_PRIVATE_LOGFILE 908 WritePrivateLogFile(logItem, isTa); 909#endif 910} 911 912static void OutputLog(struct LogItem *logItem, bool writeFile) 913{ 914 if (writeFile) { 915 /* write log file */ 916 WriteLogFile(logItem); 917 return; 918 } 919 920 /* ouput log info to display interface */ 921 if (logItem->logRealLen < logItem->logBufferLen) { 922 logItem->logBuffer[logItem->logRealLen] = 0; 923 } else { 924 logItem->logBuffer[logItem->logRealLen - 1] = 0; 925 } 926 printf("%s", (char *)logItem->logBuffer); 927} 928 929static void ReadLogBuffer(bool writeFile, const char *logBuffer, size_t readLen) 930{ 931 size_t logItemTotalLen = 0; 932 933 /* Cyclically processes all log records. */ 934 struct LogItem *logItem = LogItemGetNext(logBuffer, readLen); 935 936 while (logItem != NULL) { 937 tlogd("get log length %u\n", logItem->logBufferLen); 938 939 OutputLog(logItem, writeFile); 940 941 /* check log item have been finished */ 942 logItemTotalLen += logItem->logBufferLen + sizeof(struct LogItem); 943 if (logItemTotalLen >= readLen) { 944 tlogd("totallen %zd, readLen %zd\n", logItemTotalLen, readLen); 945 break; 946 } 947 948 logItem = LogItemGetNext((char *)(logItem->logBuffer + logItem->logBufferLen), 949 readLen - logItemTotalLen); 950 } 951} 952 953#define SLEEP_NAO_SECONDS 300000000 954static void ProcReadStatusError(void) 955{ 956 /* sleep 300 ms then retry, tv_nsec' unit is nanosecond */ 957 struct timespec requst = {0}; 958 959 requst.tv_nsec = SLEEP_NAO_SECONDS; 960 (void)nanosleep(&requst, NULL); 961} 962 963static int32_t ProcReadLog(bool writeFile, const fd_set *readset) 964{ 965 ssize_t ret; 966 size_t readLen; 967 968 if (FD_ISSET(g_devFd, readset)) { 969 READ_RETRY: 970 ret = read(g_devFd, g_logBuffer, LOG_BUFFER_LEN); 971 if (ret == 0) { 972 tlogd("tlogcat read no data:ret=%zd\n", ret); 973 return -1; 974 } else if (ret < 0) { 975 tloge("tlogcat read failed:ret=%zd\n", ret); 976 return -1; 977 } else if (ret > LOG_BUFFER_LEN) { 978 tloge("invalid read length = %zd\n", ret); 979 return -1; 980 } else { 981 tlogd("read length ret = %zd\n", ret); 982 } 983 984 readLen = (size_t)ret; 985 986 /* if the log crc check is error , maybe the log memory need update, wait a while and try again */ 987 if (ret == LOG_READ_STATUS_ERROR) { 988 ProcReadStatusError(); 989 goto READ_RETRY; 990 } 991 992 /* Cyclically processes all log records. */ 993 ReadLogBuffer(writeFile, g_logBuffer, readLen); 994 goto READ_RETRY; /* read next buffer from log mem */ 995 } else { 996 tloge("no have read signal\n"); 997 } 998 999 return 0; 1000} 1001 1002static void LogPrintTeeVersion(void); 1003 1004static void Func(bool writeFile) 1005{ 1006 int32_t result; 1007 int32_t ret; 1008 fd_set readset; 1009 1010 if (!writeFile) { 1011 LogPrintTeeVersion(); 1012 } 1013 1014 while (1) { 1015 /* 1016 * When current logs read finished, the code will return here, close this file, 1017 * and waiting a new start reading. 1018 */ 1019#ifdef CONFIG_TEE_PRIVATE_LOGFILE 1020 LogFilesClose(); 1021#endif 1022 /* Wait for the log memory read signal. */ 1023 do { 1024 FD_ZERO(&readset); 1025 FD_SET(g_devFd, &readset); 1026 tlogd("while select\n"); 1027 result = select((g_devFd + 1), &readset, NULL, NULL, NULL); 1028 } while (result == -1 && errno == EINTR); 1029 1030 if (result < 0) { 1031 continue; 1032 } 1033 1034 ret = ProcReadLog(writeFile, &readset); 1035 if (ret != 0) { 1036 continue; 1037 } 1038#ifdef CONFIG_TEE_PRIVATE_LOGFILE 1039 /* close file */ 1040 LogFilesClose(); 1041#endif 1042 FreeTagNode(); 1043 } 1044 1045 return; 1046} 1047 1048static void GetTeePathGroup(void) 1049{ 1050#ifdef AID_SYSTEM 1051 g_teePathGroup = AID_SYSTEM; 1052#else 1053 struct stat pathStat = {0}; 1054 1055 if (stat(TEE_LOG_PATH_BASE, &pathStat) != 0) { 1056 tloge("get base path stat failed\n"); 1057 return; 1058 } 1059 g_teePathGroup = pathStat.st_gid; 1060#endif 1061} 1062 1063#define MAX_TEE_LOG_SUBFOLDER_LEN 30U 1064#define TEE_COMPRESS_SUBFOLDER "_tmp" 1065static int32_t GetTeeLogPath(void) 1066{ 1067 int32_t ret; 1068 1069 if (strnlen(TEE_LOG_PATH_BASE, FILE_NAME_MAX_BUF) >= FILE_NAME_MAX_BUF || 1070 strnlen(TEE_LOG_SUBFOLDER, MAX_TEE_LOG_SUBFOLDER_LEN) >= MAX_TEE_LOG_SUBFOLDER_LEN) { 1071 tloge("invalid tee path params cfg, please check make scripts\n"); 1072 return -1; 1073 } 1074 1075 GetTeePathGroup(); 1076 1077 ret = snprintf_s(g_teePath, sizeof(g_teePath), sizeof(g_teePath) - 1, 1078 "%s/%s/", TEE_LOG_PATH_BASE, TEE_LOG_SUBFOLDER); 1079 if (ret < 0) { 1080 tloge("get tee log path failed\n"); 1081 return -1; 1082 } 1083 1084 ret = snprintf_s(g_teeTempPath, sizeof(g_teeTempPath), sizeof(g_teeTempPath) - 1, 1085 "%s/%s/", g_teePath, TEE_COMPRESS_SUBFOLDER); 1086 if (ret < 0) { 1087 tloge("get tee temp log path failed\n"); 1088 return -1; 1089 } 1090 return 0; 1091} 1092 1093static int32_t Prepare(void) 1094{ 1095 int32_t ret = GetTeeLogPath(); 1096 if (ret != 0) { 1097 return ret; 1098 } 1099 1100 g_logBuffer = malloc(LOG_BUFFER_LEN); 1101 if (g_logBuffer == NULL) { 1102 tloge("malloc log buffer failed\n"); 1103 return -1; 1104 } 1105 1106#ifdef CONFIG_TEE_PRIVATE_LOGFILE 1107 g_files = malloc(sizeof(struct LogFile) * LOG_FILES_MAX); 1108 if (g_files == NULL) { 1109 tloge("malloc files failed\n"); 1110 return -1; 1111 } 1112 1113 (void)memset_s(g_files, (sizeof(struct LogFile) * LOG_FILES_MAX), 0, (sizeof(struct LogFile) * LOG_FILES_MAX)); 1114#endif 1115 1116 g_devFd = open("/dev/teelog", O_RDONLY); 1117 if (g_devFd < 0) { 1118 tloge("open log device error\n"); 1119 return -1; 1120 } 1121 1122 tlogd("open dev success g_devFd=%d\n", g_devFd); 1123 1124 /* get tee version info */ 1125 ret = ioctl(g_devFd, TEELOGGER_GET_VERSION, g_teeVersion); 1126 if (ret != 0) { 1127 tloge("get tee verison failed %d\n", ret); 1128 } 1129 1130 OpenTeeLog(); 1131 return 0; 1132} 1133 1134static void Destruct(void) 1135{ 1136 if (g_logBuffer != NULL) { 1137 free(g_logBuffer); 1138 g_logBuffer = NULL; 1139 } 1140 1141#ifdef CONFIG_TEE_PRIVATE_LOGFILE 1142 if (g_files != NULL) { 1143 free(g_files); 1144 g_files = NULL; 1145 } 1146#endif 1147 1148 if (g_devFd >= 0) { 1149 close(g_devFd); 1150 g_devFd = -1; 1151 } 1152 1153 CloseTeeLog(); 1154} 1155 1156static void LogPrintTeeVersion(void) 1157{ 1158 g_teeVersion[sizeof(g_teeVersion) - 1] = '\0'; 1159 printf("%s\n", g_teeVersion); 1160} 1161 1162#define SET_TLOGCAT_F 1 1163static int32_t LogCmdF(void) 1164{ 1165 printf("HAVE option: -f\n"); 1166 1167 if (LogGetTlogcatF() == SET_TLOGCAT_F) { 1168 tlogd("tlogcat is running\n"); 1169 printf("tlogcat -f is running, only one instance is allowed at the same time\n"); 1170 return 0; 1171 } else { 1172 tlogd("tlogcat running prop has not been set, first time running tlogat -f\n"); 1173 } 1174 1175 if (LogSetTlogcatF() != 0) { 1176 tloge("set tlogcat running prop to 1 failed\n"); 1177 return -1; 1178 } else { 1179 tlogi("set tlogcat running prop to 1 succ\n"); 1180 } 1181 1182 Func(true); 1183 return 0; 1184} 1185 1186static bool g_defaultOp = true; 1187static int32_t SwitchSelect(int32_t ch) 1188{ 1189 switch (ch) { 1190 case 'v': 1191 LogPrintTeeVersion(); 1192 g_defaultOp = false; 1193 break; 1194 case 't': 1195 LogSetReadposCur(); 1196 break; 1197 case 'f': 1198 if (LogCmdF() != 0) { 1199 return -1; 1200 } 1201 break; 1202 case 'h': 1203 printf("HAVE option: -h\n"); 1204 HelpShow(); 1205 break; 1206 default: 1207 printf("Unknown option: %c\n", (char)optopt); 1208 HelpShow(); 1209 break; 1210 } 1211 return 0; 1212} 1213 1214int32_t main(int32_t argc, char *argv[]) 1215{ 1216 printf("tlogcat start ++\n"); 1217 int32_t ch; 1218 g_defaultOp = true; 1219 1220 if (Prepare() < 0) { 1221 goto FREE_RES; 1222 } 1223 1224 while ((ch = getopt(argc, argv, "f::ms:ghvt")) != -1) { 1225 g_defaultOp = false; 1226 if (optind > 0 && optind < argc) { 1227 tlogd("optind: %d, argc:%d, argv[%d]:%s\n", optind, argc, optind, argv[optind]); 1228 } 1229 if (SwitchSelect(ch) != 0) { 1230 tloge("option failed\n"); 1231 } 1232 1233 printf("----------------------------\n"); 1234 if (optind > 0 && optind < argc) { 1235 tlogd("optind=%d, argv[%d]=%s\n", optind, optind, argv[optind]); 1236 } 1237 } 1238 1239 if (g_defaultOp || g_readposCur != 0) { 1240 Func(false); 1241 } 1242 1243 printf("tlogcat end --\n"); 1244 1245FREE_RES: 1246 Destruct(); 1247 return 0; 1248} 1249