1 /*
2  * Copyright (c) 2020 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <securec.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <time.h>
23 #include <unistd.h>
24 
25 #include "hilog_command.h"
26 
27 #define HILOG_LOGBUFFER 2048
28 #ifndef HILOG_DIR
29 #define HILOG_DIR "/storage/data/log"
30 #endif
31 #define HILOG_PATH1 HILOG_DIR "/hilog1.txt"
32 #define HILOG_PATH2 HILOG_DIR "/hilog2.txt"
33 
34 #undef LOG_TAG
35 #define LOG_TAG "apphilogcat"
36 
37 static int file1Size = 0;
38 static int file2Size = 0;
39 
40 int FlushAndSync(FILE *fp);
41 
FileSize(const char * filename)42 static int FileSize(const char *filename)
43 {
44     FILE *fp = fopen(filename, "r");
45     if (!fp) {
46         return -1;
47     }
48 
49     int size = 0;
50     int ret = fseek(fp, 0L, SEEK_END);
51     if (ret == 0) {
52         size = ftell(fp);
53     }
54     fclose(fp);
55 
56     return size;
57 }
58 
FileClear(FILE ** fp,const char * filename)59 static FILE *FileClear(FILE **fp, const char *filename)
60 {
61     if (*fp != NULL) {
62         fclose(*fp);
63     }
64     *fp = fopen(filename, "w");
65     if (*fp == NULL) {
66         return NULL;
67     }
68     printf("write file switch %s\n", filename);
69     return *fp;
70 }
71 
SelectWriteFile(FILE ** fp1,FILE * fp2)72 FILE *SelectWriteFile(FILE **fp1, FILE *fp2)
73 {
74     file1Size = FileSize(HILOG_PATH1);
75     file2Size = FileSize(HILOG_PATH2);
76     if (file1Size < HILOG_MAX_FILELEN) {
77         return *fp1;
78     } else if (file2Size < HILOG_MAX_FILELEN) {
79         return fp2;
80     } else { // clear file1 write file 1
81         file1Size = 0;
82         return FileClear(fp1, HILOG_PATH1);
83     }
84 }
85 
SwitchWriteFile(FILE ** fp1,FILE ** fp2,FILE * curFp)86 FILE *SwitchWriteFile(FILE **fp1, FILE **fp2, FILE *curFp)
87 {
88     // select file, if file1 is full, record file2, file2 is full, record file1
89     if (file1Size < HILOG_MAX_FILELEN) {
90         return *fp1;
91     } else if (file2Size < HILOG_MAX_FILELEN) {
92         return *fp2;
93     } else if (curFp == *fp2) { // clear file1 write file 1
94         FlushAndSync(*fp2);
95         file1Size = 0;
96         return FileClear(fp1, HILOG_PATH1);
97     } else {
98         FlushAndSync(*fp1);
99         file2Size = 0;
100         return FileClear(fp2, HILOG_PATH2);
101     }
102 }
103 
FlushAndSync(FILE * fp)104 int FlushAndSync(FILE *fp)
105 {
106     if (fp == NULL) {
107         return 0;
108     }
109     if (fflush(fp) != 0) {
110         return -1;
111     }
112     int fd = fileno(fp);
113     if (fsync(fd) != 0) {
114         return -1;
115     }
116     return 0;
117 }
118 
NeedFlush(const char * buf)119 bool NeedFlush(const char *buf)
120 {
121 #define FLUSH_LOG_ARG_0 0
122 #define FLUSH_LOG_ARG_1 1
123 #define FLUSH_LOG_FLAG  0x07
124     if (buf[FLUSH_LOG_ARG_0] == FLUSH_LOG_FLAG && buf[FLUSH_LOG_ARG_1] == FLUSH_LOG_FLAG) {
125         return true;
126     }
127     return false;
128 }
129 
FileClose(FILE * file)130 static void FileClose(FILE *file)
131 {
132     if (file != NULL) {
133         fclose(file);
134     }
135 }
136 
main(int argc,char * argv[])137 int main(int argc, char *argv[])
138 {
139 #define HILOG_UMASK 0027
140     int fd = -1;
141     int ret = -1;
142     FILE *fpWrite = NULL;
143     bool printFlag = true;
144 
145     if (argc > 1) {
146         ret = HilogCmdProc(LOG_TAG, argc, argv);
147         if (ret == -1) {
148             return 0;
149         }
150     }
151 
152     fd = open(HILOG_DRIVER, O_RDONLY | O_CLOEXEC);
153     if (fd < 0) {
154         printf("hilog fd failed %s\n", strerror(errno));
155         return 0;
156     }
157 
158     umask(HILOG_UMASK);
159     FILE *fp1 = fopen(HILOG_PATH1, "at");
160     if (fp1 == NULL) {
161         printf("open err fp1 %s\n", strerror(errno));
162         close(fd);
163         return 0;
164     }
165 
166     FILE *fp2 = fopen(HILOG_PATH2, "at");
167     if (fp2 == NULL) {
168         printf("open err fp2 %s\n", strerror(errno));
169         FileClose(fp1);
170         close(fd);
171         return 0;
172     }
173     // First select
174     fpWrite = SelectWriteFile(&fp1, fp2);
175     if (fpWrite == NULL) {
176         printf("SelectWriteFile open err\n");
177         close(fd);
178         FileClose(fp1);
179         FileClose(fp2);
180         return 0;
181     }
182     char *buf = malloc(HILOG_LOGBUFFER + 1);
183     if (buf == NULL) {
184         close(fd);
185         FileClose(fp1);
186         FileClose(fp2);
187         return 0;
188     }
189     while (1) {
190         (void)memset_s(buf, HILOG_LOGBUFFER + 1, 0, HILOG_LOGBUFFER + 1);
191         ret = read(fd, buf, HILOG_LOGBUFFER);
192         if (ret < 0 || ret < sizeof(struct HiLogEntry)) {
193             continue;
194         }
195         struct HiLogEntry *head = (struct HiLogEntry *)buf;
196 
197         if (NeedFlush(head->msg)) {
198             if (FlushAndSync(fpWrite) != 0) {
199                 printf("flush and sync file err\n");
200             }
201             continue;
202         }
203 
204         time_t rawtime;
205         struct tm *info = NULL;
206         struct tm nowTime = {0};
207         unsigned int sec = head->sec;
208         rawtime = (time_t)sec;
209         /* Get local time */
210         info = localtime_r(&rawtime, &nowTime);
211 
212         printFlag = FilterLevelLog(g_hiviewConfig.level, *(head->msg));
213         if (!printFlag) {
214             continue;
215         }
216 #define MODULE_OFFSET 2
217         printFlag = FilterModuleLog(g_hiviewConfig.logOutputModule, (head->msg) + MODULE_OFFSET);
218         if (!printFlag) {
219             continue;
220         }
221 
222         if (info == NULL) {
223             continue;
224         }
225         buf[HILOG_LOGBUFFER - 1] = '\0';
226 
227         if (g_hiviewConfig.silenceMod == SILENT_MODE_OFF) {
228             printf("%02d-%02d %02d:%02d:%02d.%03d %d %d %s\n", info->tm_mon + 1, info->tm_mday, info->tm_hour,
229                 info->tm_min, info->tm_sec, head->nsec / NANOSEC_PER_MIRCOSEC, head->pid, head->taskId, head->msg);
230         }
231 
232         ret =
233             fprintf(fpWrite, "%02d-%02d %02d:%02d:%02d.%03d %d %d %s\n", info->tm_mon + 1, info->tm_mday, info->tm_hour,
234                 info->tm_min, info->tm_sec, head->nsec / NANOSEC_PER_MIRCOSEC, head->pid, head->taskId, head->msg);
235         if (ret < 0) {
236             printf("[FATAL]File can't write fpWrite %s\n", strerror(errno));
237             free(buf);
238             close(fd);
239             FileClose(fp1);
240             FileClose(fp2);
241             return 0;
242         }
243         if (fpWrite == fp1) {
244             file1Size += ret;
245         } else if (fpWrite == fp2) {
246             file2Size += ret;
247         }
248         // select file, if file1 is full, record file2, file2 is full, record file1
249         fpWrite = SwitchWriteFile(&fp1, &fp2, fpWrite);
250         if (fpWrite == NULL) {
251             printf("[FATAL]SwitchWriteFile failed\n");
252             free(buf);
253             close(fd);
254             FileClose(fp1);
255             FileClose(fp2);
256             return 0;
257         }
258     }
259     free(buf);
260     close(fd);
261     FileClose(fp1);
262     FileClose(fp2);
263     return 0;
264 }
265