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