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
63 char g_teePath[FILE_NAME_MAX_BUF] = {0};
64 char g_teeTempPath[FILE_NAME_MAX_BUF] = {0};
65 gid_t g_teePathGroup = 0;
66 #ifdef CONFIG_TEE_PRIVATE_LOGFILE
67 struct 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 };
75 static struct LogFile *g_files = NULL;
76 #endif
77 static char *g_compressFile = NULL;
78 static struct TeeUuid g_compressUuid;
79 char *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
94 static int32_t g_devFd = -1;
95 static char g_teeVersion[MAX_TEE_VERSION_LEN];
96 static int32_t g_readposCur = 0;
97
98 #ifdef CONFIG_TEE_PRIVATE_LOGFILE
GetLogPathBasePos(const char * temp,char ** pos)99 static 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 */
LogFilesMkdirR(const char * path)117 static 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
GetUuidStr(const struct TeeUuid * uuid,char * name,uint32_t nameLen)162 static 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
LogFilesAdd(const struct TeeUuid * uuid,const char * logName,FILE * file,long fileLen,uint32_t index)176 static 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
208 CLOSE_F:
209 (void)fclose(file);
210 return NULL;
211 }
212
CloseFileFd(int32_t * fd)213 static void CloseFileFd(int32_t *fd)
214 {
215 if (*fd < 0) {
216 return;
217 }
218
219 close(*fd);
220 *fd = -1;
221 }
222
LogFilesOpen(const char * logName,long * fileLen)223 static 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
IsTaUuid(const struct TeeUuid * uuid)273 static 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
291 struct FileNameAttr {
292 const char *uuidAscii;
293 bool isTa;
294 uint32_t index;
295 };
296
SetFileNameAttr(struct FileNameAttr * nameAttr,const char * uuidAscii,bool isTa,uint32_t index)297 static 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
LogAssembleFilename(char * logName,size_t logNameLen,const char * logPath,const struct FileNameAttr * nameAttr)305 static 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
LogAssembleCompressFilename(char * logName,size_t logNameLen,const char * logPath,const struct FileNameAttr * nameAttr)317 static 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
TriggerCompress(void)329 static 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
357 FREE_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
378 char g_logNameCompress[FILE_NAME_MAX_BUF] = {0};
379 char g_uuidAscii[UUID_MAX_STR_LEN] = {0};
380 char g_logName[FILE_NAME_MAX_BUF] = {0};
381
382 #ifdef CONFIG_TEE_PRIVATE_LOGFILE
GetCompressFile(const struct TeeUuid * uuid)383 static 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
ArrangeCompressFile(const struct TeeUuid * uuid)413 static 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
UnlinkTmpFile(const char * name)457 static 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
LogTmpDirClear(const char * tmpPath)475 static 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
MkdirTmpPath(const char * tmpPath)511 static 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
MoveFileToTmpPath(bool isTa,uint32_t index)531 static 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
LogFilesCompress(const struct TeeUuid * uuid)561 static 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
LogFileFull(uint32_t fileNum)600 static 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
LogFilesChecklimit(uint32_t fileNum)639 static 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
GetUsableFile(const struct TeeUuid * uuid)663 static 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
GetFileIndex(const char * uuidAscii,bool isTa,uint32_t * fileIndex)694 static 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
LogFilesGet(const struct TeeUuid * uuid,bool isTa)717 static 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
LogFilesClose(void)762 static 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
HelpShow(void)798 static 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
LogItemGetNext(const char * logBuffer,size_t scopeLen)805 static 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
LogSetReadposCur(void)830 static 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
LogSetTlogcatF(void)846 static 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
LogGetTlogcatF(void)863 static 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
WritePrivateLogFile(const struct LogItem * logItem,bool isTa)881 static 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
WriteLogFile(const struct LogItem * logItem)902 static 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
OutputLog(struct LogItem * logItem,bool writeFile)912 static 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
ReadLogBuffer(bool writeFile,const char * logBuffer,size_t readLen)929 static 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
ProcReadStatusError(void)954 static 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
ProcReadLog(bool writeFile,const fd_set * readset)963 static 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
1002 static void LogPrintTeeVersion(void);
1003
Func(bool writeFile)1004 static 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
GetTeePathGroup(void)1048 static 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"
GetTeeLogPath(void)1065 static 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
Prepare(void)1093 static 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
Destruct(void)1134 static 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
LogPrintTeeVersion(void)1156 static 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
LogCmdF(void)1163 static 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
1186 static bool g_defaultOp = true;
SwitchSelect(int32_t ch)1187 static 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
main(int32_t argc,char * argv[])1214 int32_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
1245 FREE_RES:
1246 Destruct();
1247 return 0;
1248 }
1249