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