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