1 /*
2  * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3  */
4 
5 #include "ulog_session_file.h"
6 
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "aos/errno.h"
12 #include "aos/kernel.h"
13 #include "cJSON.h"
14 #include "uagent.h"
15 #include "ulog/ulog.h"
16 #include "ulog_api.h"
17 
18 /**
19  * record the log files operating. Recover(reset or get) in reload_log_argu()
20  * used and count in write_log_line()
21  */
22 static uint32_t operating_file_offset = 0;
23 static uint32_t gu32_log_file_size = LOCAL_FILE_SIZE;
24 static char guc_logfile_path[ULOG_FILE_PATH_SIZE / 2] = { 0 };
25 /**
26  * indicates if log on fs feature initialized
27  *
28  */
29 static uint8_t session_fs_init = 0;
30 
31 static uint8_t log_file_failed = 0;
32 
33 #if ULOG_RESERVED_FS
34 static char *ulog_fs_tmp[ULOG_RESERVED_FS_SIZE] = { NULL };
35 
36 static uint16_t tmp_queue_in = 0;
37 static uint16_t tmp_queue_out = 0;
38 
39 static void stop_operating();
40 
push_fs_tmp(const char * data,const unsigned short len)41 static int push_fs_tmp(const char *data, const unsigned short len)
42 {
43     int rc = -1;
44     if (NULL != data && len != 0 && ((tmp_queue_in + 1) % ULOG_RESERVED_FS_SIZE) != tmp_queue_out) {
45         if (NULL == ulog_fs_tmp[tmp_queue_in]) {
46             ulog_fs_tmp[tmp_queue_in] = (char *)aos_malloc(len + 1);
47             if (NULL != ulog_fs_tmp[tmp_queue_in]) {
48                 memcpy(ulog_fs_tmp[tmp_queue_in], data, len);
49                 ulog_fs_tmp[tmp_queue_in][len] = '\0';
50                 tmp_queue_in = (tmp_queue_in + 1) % ULOG_RESERVED_FS_SIZE;
51                 rc = 0;
52             }
53         }
54     }
55     return rc;
56 }
57 
pop_fs_tmp(char * data,const unsigned short len)58 static int pop_fs_tmp(char *data, const unsigned short len)
59 {
60     int rc = -EINVAL;
61     if (NULL != data && len != 0) {
62         if (tmp_queue_in == tmp_queue_out) {
63             rc = -1;
64         } else {
65             if (NULL != ulog_fs_tmp[tmp_queue_out]) {
66                 strncpy(data, ulog_fs_tmp[tmp_queue_out], len - 1);
67                 aos_free(ulog_fs_tmp[tmp_queue_out]);
68                 ulog_fs_tmp[tmp_queue_out] = NULL;
69                 tmp_queue_out = (tmp_queue_out + 1) % ULOG_RESERVED_FS_SIZE;
70                 rc = 0;
71 
72             } else {
73                 rc = -EIO;
74             }
75         }
76     }
77     return rc;
78 }
79 #endif
80 
81 #if ULOG_UPLOAD_LOG_FILE
82 #include "httpclient.h"
83 #include "sys/socket.h"
84 static httpclient_t *httpc_handle = NULL;
85 
86 static char *up_uri = NULL;
87 static bool http_client_initd = false;
88 
get_server_uri(const char * url,char ** server,char ** uri)89 static int get_server_uri(const char *url, char **server, char **uri)
90 {
91     int rc = -1;
92     if (NULL != url) {
93         uint8_t pos = -1;
94         if (0 == strncmp(url, URL_PREFIX_HTTP, strlen(URL_PREFIX_HTTP))) {
95             pos = strlen(URL_PREFIX_HTTP);
96         } else if (0 == strncmp(url, URL_PREFIX_HTTPS, strlen(URL_PREFIX_HTTPS))) {
97             pos = strlen(URL_PREFIX_HTTPS);
98         }
99         if (pos > 0) {
100             char *p = NULL;
101             p = strchr(&url[pos], '/');
102             if (NULL != p) {
103                 p++;
104                 *server = (char *)aos_malloc(p - url + 1);
105                 if (NULL != *server) {
106                     memcpy(*server, url, p - url);
107                     (*server)[p - url] = '\0';
108                     const short n = strlen(p);
109                     *uri = (char *)aos_malloc(n + 1);
110                     if (NULL != *uri) {
111                         memcpy(*uri, p, n);
112                         (*uri)[n] = '\0';
113                         rc = 0;
114                     } else {
115                         aos_free(*server);
116                         *server = NULL;
117                     }
118                 }
119             }
120         }
121     }
122     return rc;
123 }
124 
report_up_process(const http_upload_fail_t status,const char process,const ulog_idx_type idx)125 static void report_up_process(const http_upload_fail_t status, const char process, const ulog_idx_type idx)
126 {
127     cJSON *resp = cJSON_CreateObject();
128     if (NULL != resp) {
129         char *text = NULL;
130         cJSON_AddItemToObject(resp, "idx", cJSON_CreateNumber(idx));
131         if (status >= http_upload_start) {
132             cJSON_AddItemToObject(resp, "process", cJSON_CreateNumber(process));
133         } else {
134             cJSON_AddItemToObject(resp, "error", cJSON_CreateNumber(status));
135         }
136         text = cJSON_PrintUnformatted(resp);
137         cJSON_Delete(resp);
138         uagent_send(UAGENT_MOD_ULOG, ULOG_LOG_LIST, strlen(text), text, send_policy_object);
139         cJSON_free(text);
140     }
141 }
142 
http_start(const char * url,const unsigned short idx)143 int http_start(const char *url, const unsigned short idx)
144 {
145     int rc = -1;
146     if (!http_client_initd) {
147         http_client_initd = true;
148     }
149 
150     if (httpc_handle == NULL) {
151         LOGI(ULOG_TAG_SELF, "http start %s idx %d", url, idx);
152         httpc_handle = (httpclient_t *)aos_malloc(sizeof(httpclient_t));
153         if (NULL != httpc_handle) {
154             up_uri = (uint8_t *)aos_malloc(strlen(url));
155             if (NULL != up_uri) {
156                 strncpy(up_uri, url, strlen(url));
157                 char buf[16];
158                 snprintf(buf, 16, "up idx=%d", idx);
159                 rc = ulog_man(buf);
160             } else {
161                 aos_free(httpc_handle);
162                 httpc_handle = NULL;
163             }
164         } else {
165             LOGE(ULOG_TAG_SELF, "allock http connect instanse fail");
166         }
167     } else {
168         LOGE(ULOG_TAG_SELF, "Last upload not finish");
169     }
170     return rc;
171 }
172 
173 static uint8_t *rsp_buf = NULL;
174 static uint8_t *req_buf = NULL;
on_fs_upload(const uint32_t idx,const uint32_t start)175 void on_fs_upload(const uint32_t idx, const uint32_t start)
176 {
177     if (get_working_from_cfg_mm() == idx) {
178         on_fs_record_pause(1, 0);
179     }
180     int fd = open_log_file(idx, O_RDONLY, 0);
181     http_upload_fail_t http_operate = http_upload_common_fail;
182     if (fd >= 0) {
183         char *customer_header = "Accept: text/xml,text/javascript,text/html,application/json\r\n";
184         httpclient_set_custom_header(httpc_handle, customer_header);
185         char *upload_stream = (char *)aos_malloc(gu32_log_file_size + ULOG_SIZE);
186         if (NULL != upload_stream) {
187             int n = -1;
188             n = aos_read(fd, upload_stream, gu32_log_file_size + ULOG_SIZE);
189             if (0 < n) {
190                 char retry = HTTP_REQ_RETRY;
191                 httpclient_data_t client_data = { 0 };
192                 rsp_buf = (uint8_t *)aos_malloc(RSP_BUF_SIZE);
193                 req_buf = (uint8_t *)aos_malloc(RSP_BUF_SIZE);
194                 if (rsp_buf != NULL && req_buf != NULL) {
195                     memset(req_buf, 0, sizeof(req_buf));
196                     client_data.header_buf = req_buf;
197                     client_data.header_buf_len = sizeof(req_buf);
198 
199                     memset(rsp_buf, 0, sizeof(rsp_buf));
200                     client_data.response_buf = rsp_buf;
201                     client_data.response_buf_len = sizeof(rsp_buf);
202 
203                     client_data.post_buf = upload_stream;
204                     client_data.post_buf_len = n;
205                     client_data.post_content_type = "text/plain";
206 
207                     while (HTTP_SUCCESS != httpclient_put(httpc_handle, up_uri, &client_data)) {
208                         if (--retry <= 0) {
209                             break;
210                         } else {
211                             LOGW(ULOG_TAG_SELF, "fs rqst %d fail", n);
212                             aos_msleep(1000);
213                         }
214                     }
215                     if (retry > 0) {
216                         http_operate = http_upload_finish;
217                     } else {
218                         http_operate = http_upload_memory_fail;
219                     }
220                 }
221             } else {
222                 http_operate = http_upload_text_empty;
223                 LOGW(ULOG_TAG_SELF, "nothing read");
224             }
225             aos_free(upload_stream);
226         } else {
227             http_operate = http_upload_memory_fail;
228             LOGE(ULOG_TAG_SELF, "allocate file fail");
229         }
230     } else {
231         LOGE(ULOG_TAG_SELF, "http construct header fail");
232     }
233     aos_close(fd);
234 
235     report_up_process(http_operate, http_operate == http_upload_finish ? 100 : 0, idx);
236 
237     httpclient_clse(httpc_handle);
238     aos_free(rsp_buf);
239     rsp_buf = NULL;
240     aos_free(req_buf);
241     req_buf = NULL;
242     aos_free(up_uri);
243     up_uri = NULL;
244     aos_free(httpc_handle);
245     httpc_handle = NULL;
246     /* try re-start record, no impact even the record no abort before */
247     on_fs_record_pause(0, 1);
248 }
249 
250 #endif
251 
252 /**
253  *
254  * Check if file already exist
255  *
256  * @param  file_idx file index to be checked
257  * @return true indicats it is existed, or else not.
258  */
log_file_exist(const uint16_t file_idx)259 static bool log_file_exist(const uint16_t file_idx)
260 {
261     bool rc = false;
262     char ulog_file_name[ULOG_FILE_PATH_SIZE] = { 0 };
263     int fd = -1;
264 
265     if (file_idx <= LOCAL_FILE_CNT) {
266         snprintf(ulog_file_name, sizeof(ulog_file_name), ULOG_FILE_FORMAT, guc_logfile_path, file_idx);
267         fd = aos_open(ulog_file_name, (O_RDWR | O_CREAT | O_EXCL)
268 #ifdef CSP_LINUXHOST
269                      , 0644
270 #endif
271         );
272         SESSION_FS_DEBUG("check if file %s exist %d\n", ulog_file_name, fd);
273 
274         if (fd < 0) {
275 #ifdef CSP_LINUXHOST
276             if (EEXIST == errno) {
277                 SESSION_FS_DEBUG("file %s alreay exist\n", ulog_file_name);
278                 rc = true;
279             }
280 #else  /* !CSP_LINUXHOST */
281             if (fd == -EEXIST) {
282                 SESSION_FS_DEBUG("file %s alreay exist\n", ulog_file_name);
283                 rc = true;
284             }
285 #endif /* CSP_LINUXHOST */
286         } else {
287             /*TODO:why not close*/
288             aos_close(fd);
289             aos_unlink(ulog_file_name);
290         }
291     }
292     return rc;
293 }
294 
open_create_log_file(const ulog_idx_type file_idx,const bool keep_open)295 static int open_create_log_file(const ulog_idx_type file_idx, const bool keep_open)
296 {
297     int fd = -1;
298     char ulog_file_name[ULOG_FILE_PATH_SIZE] = { 0 };
299 
300     snprintf(ulog_file_name, sizeof(ulog_file_name), ULOG_FILE_FORMAT, guc_logfile_path, file_idx);
301     SESSION_FS_DEBUG("open create log %s\n", ulog_file_name);
302     aos_unlink(ulog_file_name);
303     fd = aos_open(ulog_file_name, (O_RDWR | O_CREAT | O_TRUNC)
304 #ifdef CSP_LINUXHOST
305                                       ,
306                   0644
307 #endif
308     );
309     if (fd >= 0) {
310         if (!keep_open) {
311             aos_close(fd);
312         }
313     } else {
314         SESSION_FS_INFO("open create file %s fail fd %d, errno %d\n", ulog_file_name, fd, errno);
315     }
316     return fd;
317 }
318 
open_log_file(const ulog_idx_type file_idx,int flag,const off_t off)319 int open_log_file(const ulog_idx_type file_idx, int flag, const off_t off)
320 {
321     int fd = -1;
322     char ulog_file_name[ULOG_FILE_PATH_SIZE];
323     memset(ulog_file_name, 0, sizeof(ulog_file_name));
324     snprintf(ulog_file_name, sizeof(ulog_file_name), ULOG_FILE_FORMAT, guc_logfile_path, file_idx);
325     fd = aos_open(ulog_file_name, flag);
326     if (fd >= 0) {
327         const int seek_off = aos_lseek(fd, off, SEEK_SET);
328         if (seek_off != off) {
329             SESSION_FS_INFO("seek fail %s %d\n", ulog_file_name, seek_off);
330             aos_close(fd);
331             fd = -1;
332         }
333     } else {
334         SESSION_FS_INFO("open %s flag %d fail fd %d\n", ulog_file_name, flag, fd);
335     }
336     return fd;
337 }
338 
339 /**
340  *
341  * Copies one line from file_instanse into buf, On sucessful the destination buf
342  * buf is changed into NULL terminated C String. If log content size is longer
343  * than buf_len-1, remain will be not saved and NULL terminatated is implicitly
344  * appended at the end of destination.
345  *
346  * @param  file_instanse file description from aos_open() before
347  * @param  buf local buffer use for saved, ZERO format is not MUST
348  * @param  buf_len buffer size
349  * @return actual log text length readed in argumenent buf;
350  *         '\n',' is counted. Expected value: 1~buf_len-1
351  *         0 indicates EOF of the file, buf_len indicates the possible passing
352  * value is limited to read the whole line.
353  */
get_log_line(const int fd,char * buf,const uint16_t buf_len)354 int get_log_line(const int fd, char *buf, const uint16_t buf_len)
355 {
356     int rc = -1;
357     int cnt = 0;
358 
359     if (fd < 0 || NULL == buf || buf_len <= 0) {
360         return -1;
361     }
362 
363     memset(buf, 0, buf_len);
364     while ((cnt < buf_len) && (0 < aos_read(fd, &buf[cnt], 1))) {
365         if (buf[cnt] == LOG_LINE_SEPARATOR) {
366             break;
367         }
368         cnt++;
369     }
370 
371     if (cnt == 0) {
372         /* Nothing read, this is an empty file */
373         rc = 0;
374     } else if (cnt < buf_len) {
375         if (buf[cnt - 1] == LOG_LINE_SEPARATOR) {
376             /* replacement/end with null terminated */
377             buf[cnt - 1] = 0;
378         } else {
379             buf[cnt] = 0;
380         }
381         rc = cnt;
382 
383     } else { /* cnt == buf_len */
384         /* two possible result */
385         /* buffer len is just fit */
386         /* buffer is not sufficient to save whole line,
387         last characher will be missed and replace of null-terminated */
388         rc = cnt;
389 
390         /* replacement with null terminated */
391         buf[cnt - 1] = 0;
392     }
393 
394     return rc;
395 }
396 
397 /**
398  *
399  * Write one line into specify log file, which instance is file_instanse. Append
400  * a LOG_LINE_SEPARATOR after log context to separate logs
401  *
402  * @param  file_instanse file description from aos_open() before
403  * @param  buf local buffer use for write
404  * @param  keep_open keep opening after write finished
405  * @param operating indicates the rolling-back mechanism used.
406  * @return actual writen text length(includes length of LOG_LINE_SEPARATOR).
407  *         -EINVAL indicates parameter illegal, other value indicates call
408  * aos_write failure
409  */
write_log_line(const int file_instanse,const char * buf,const bool keep_open)410 int write_log_line(const int file_instanse, const char *buf, const bool keep_open)
411 {
412     int rtn = -EINVAL;
413     if (file_instanse >= 0 && buf != NULL) {
414         int rc = -1;
415         rtn = aos_write(file_instanse, buf, strlen(buf));
416         if (rtn > 0) {
417             rc = aos_write(file_instanse, LOG_LINE_END_STR, 1);
418             if (1 == rc) {
419                 rtn++;
420             } else {
421                 rtn = rc;
422             }
423             aos_sync(file_instanse);
424         } else {
425             SESSION_FS_INFO("write fail rc %d\n", rtn);
426         }
427 
428         if (!keep_open) {
429             aos_close(file_instanse);
430         }
431     }
432 
433     return rtn;
434 }
435 
436 /**
437  *
438  * Refresh ulog cfg item and saved in cfg file, also create the new ulog file
439  *
440  *
441  * @return  0 indicates create new log file sucessfully, but not means update
442  * config pass; -1 create new log file fail
443  */
update_new_log_file(const ulog_idx_type idx)444 static int update_new_log_file(const ulog_idx_type idx)
445 {
446     int rc = -1;
447     int fd = -1;
448 
449     if (0 == update_mm_cfg(ulog_cfg_type_working, idx, ulog_cfg_para_none, NULL)) {
450         /* read it for test */
451         if (get_working_from_cfg_mm() == idx) {
452             /* create log file */
453             if (open_create_log_file(idx, false) >= 0) {
454                 rc = 0;
455                 char time_start[24];
456 
457                 ulog_format_time(time_start, sizeof(time_start));
458 
459                 update_mm_cfg(ulog_cfg_type_list, idx, ulog_cfg_para_start, time_start);
460                 fd = open_create_log_file(ULOG_FILE_CFG_IDX, true);
461 
462                 if (fd >= 0) { /* need update cfg file */
463                     if (0 != cfg_mm_2_file(fd)) {
464                         /* sync to cfg file fail, have no impact unless the
465                          * board boot-up before it sync write */
466                         SESSION_FS_INFO("sync to cfg file fail %d\n", fd);
467                     }
468                     aos_close(fd);
469                 } else {
470                     SESSION_FS_INFO("refresh ulog cfg fail fd %d\n", fd);
471                 }
472 
473             } else {
474                 SESSION_FS_INFO("sync to cfg file fail %d\n", fd);
475             }
476         } else {
477             SESSION_FS_INFO("Fatal Error Operate ulog mm cfg\n");
478         }
479     } else {
480         SESSION_FS_INFO("Fatal Error update ulog mm cfg\n");
481     }
482 
483     return rc;
484 }
485 
486 /**
487  *
488  * Reload log history arguments from ulog cfg file(ulog_000.log) in fs,
489  * includes operating_file_idx & operating_file_offset. New ulog_000.log
490  * will be created if none ulog_000.log found or text is illegal.
491  * This is vital for ulog pop via fs, ulog pop via fs will be forbidden if
492  * this step fail.
493  *
494  * return 0 if this step pass, else indicates this step fail
495  *
496  */
reload_log_argu()497 static int reload_log_argu()
498 {
499     int rc = -1;
500     struct aos_stat st_logstat = { 0 };
501     char ulog_file_name[ULOG_FILE_PATH_SIZE] = { 0 };
502     ulog_idx_type tmp_idx = ULOG_FILE_IDX_INVALID;
503 
504     operating_file_offset = 0;
505 
506     if (log_file_exist(ULOG_FILE_CFG_IDX)) {
507         /* ulog cfg exist, try to read it */
508         load_cfg_2_mm();
509         tmp_idx = get_working_from_cfg_mm();
510 
511         SESSION_FS_INFO("[%s]log file idx %d\n", ULOG_TAG_SELF, tmp_idx);
512         if (tmp_idx <= LOCAL_FILE_CNT) {
513             snprintf(ulog_file_name, sizeof(ulog_file_name), ULOG_FILE_FORMAT, guc_logfile_path, tmp_idx);
514             rc = aos_stat(ulog_file_name, &st_logstat);
515             if (rc == 0) {
516                 operating_file_offset += st_logstat.st_size;
517             } else {
518                 /* no such log file exist, then create it */
519                 rc = update_new_log_file(tmp_idx);
520             }
521         }
522     }
523 
524     if (LOCAL_FILE_CNT < tmp_idx) {
525         rc = update_new_log_file(ULOG_FILE_IDX_START);
526     }
527 
528     return rc;
529 }
530 
on_show_ulog_file()531 void on_show_ulog_file()
532 {
533     aos_dir_t *dp;
534     SESSION_FS_INFO("log files in %s\n", guc_logfile_path);
535     dp = (aos_dir_t *)aos_opendir(guc_logfile_path);
536 
537     if (dp != NULL) {
538         aos_dirent_t *out_dirent;
539         while (1) {
540             out_dirent = (aos_dirent_t *)aos_readdir(dp);
541             if (out_dirent != NULL) {
542                 SESSION_FS_INFO("file name is %s\n", out_dirent->d_name);
543             } else {
544                 break;
545             }
546         }
547     }
548     aos_closedir(dp);
549 }
550 
stop_operating()551 static void stop_operating()
552 {
553     char time_stop[24];
554 
555     ulog_format_time(time_stop, sizeof(time_stop));
556     update_mm_cfg(ulog_cfg_type_list, get_working_from_cfg_mm(), ulog_cfg_para_end, time_stop);
557 }
558 
write_fail_retry()559 static void write_fail_retry()
560 {
561     int8_t retry = ULOG_FILE_FAIL_COUNT;
562     char log_file_name[ULOG_FILE_PATH_SIZE];
563     char buf[ULOG_SIZE];
564 
565     log_file_failed++;
566     if (log_file_failed >= ULOG_FILE_FAIL_COUNT) {
567         snprintf(log_file_name, ULOG_FILE_PATH_SIZE, ULOG_FILE_FORMAT, guc_logfile_path, get_working_from_cfg_mm());
568         while (0 != aos_unlink(log_file_name)) {
569             if (--retry <= 0) {
570                 SESSION_FS_INFO("file %s error on remove, retry %d\n", log_file_name, retry);
571                 break;
572             }
573         }
574 
575         if (retry > 0) {
576             SESSION_FS_INFO("remove file %s, then create new one %d\n", log_file_name, get_working_from_cfg_mm());
577             if (0 == update_new_log_file(get_working_from_cfg_mm())) {
578 #if ULOG_RESERVED_FS
579                 memset(buf, 0, ULOG_SIZE);
580                 while (0 == pop_fs_tmp(buf, ULOG_SIZE)) {
581                     pop_out_on_fs(buf, strlen(buf));
582                     memset(buf, 0, ULOG_SIZE);
583                 }
584 #endif /* ULOG_RESERVED_FS */
585             }
586         }
587     }
588 }
589 
590 /**
591  * @brief not thread-safe, but only be used in one task(ulog), so not necessary
592  * considering mutex
593  * @param data
594  * @param len
595  *
596  * @return -1 indicates not send out sucessfully
597  *
598  */
pop_out_on_fs(const char * data,const uint16_t len)599 int32_t pop_out_on_fs(const char *data, const uint16_t len)
600 {
601     int32_t rc = -1;
602     int fd = 0;
603     int write_rlt = 0;
604     ulog_idx_type idx = ULOG_FILE_IDX_INVALID;
605 
606     idx = get_working_from_cfg_mm();
607     if (idx > LOCAL_FILE_CNT) {
608         SESSION_FS_INFO("fail to get working log file idx %d update working cfg\n", idx);
609         rc = reload_log_argu();
610         if (rc < 0) {
611             SESSION_FS_INFO("fail to pop log to fs for reload log cfg fail \n");
612             return -1;
613         }
614         /*this time idx will be fine not need to check*/
615         idx = get_working_from_cfg_mm();
616     }
617 
618     fd = open_log_file(idx, O_WRONLY, operating_file_offset);
619     if (fd < 0) {
620         SESSION_FS_INFO(
621             "fail to pop log to fs for open working log file %d offset fail %d "
622             "\n",
623             idx, operating_file_offset, errno);
624         rc = -1;
625 #if ULOG_RESERVED_FS
626         rc = push_fs_tmp(data, len);
627         if (0 != rc) {
628             SESSION_FS_INFO("*(%d)", rc);
629         }
630         return rc;
631 #endif
632     }
633 
634     write_rlt = write_log_line(fd, data, true);
635     aos_sync(fd);
636     aos_close(fd);
637     if (write_rlt < 0) {
638         SESSION_FS_INFO("write fail %d retry %d\n", write_rlt, log_file_failed);
639         rc = -1;
640 #if ULOG_RESERVED_FS
641         /* save them temporary */
642         rc = push_fs_tmp(data, len);
643         if (0 != rc) {
644             SESSION_FS_INFO("*(%d)", rc);
645         }
646 #endif /* ULOG_RESERVED_FS */
647         /* check fail count */
648         write_fail_retry();
649         return rc;
650     }
651 
652     log_file_failed = 0;
653     operating_file_offset += write_rlt;
654     if (operating_file_offset >= gu32_log_file_size) {
655         stop_operating();
656 
657         /* roll back if working index reaches end */
658         idx++;
659         if (idx > LOCAL_FILE_CNT) {
660             idx = ULOG_FILE_IDX_START;
661         }
662         operating_file_offset = 0;
663         rc = update_new_log_file(idx);
664         if (rc) {
665             SESSION_FS_INFO("creat new log file %d fail %d in pop to fs\n", idx, rc);
666         }
667     }
668 
669     return 0;
670 }
671 
on_fs_record_pause(const uint32_t on,const uint32_t off)672 void on_fs_record_pause(const uint32_t on, const uint32_t off)
673 {
674     if ((on ^ off) == 0) {
675         return;
676     }
677 
678     SESSION_FS_INFO(ULOG_TAG_SELF, "ulog fs ctrl on %d off %d\n", on, off);
679     if (1 == on) {
680         stop_operating();
681     } else { /* resume the file record */
682         if (0 == reload_log_argu()) {
683             LOGI(ULOG_TAG_SELF, "reload ulog idx %d off %d", get_working_from_cfg_mm(), operating_file_offset);
684 #if ULOG_RESERVED_FS
685             char buf[ULOG_SIZE];
686             memset(buf, 0, ULOG_SIZE);
687             while (0 == pop_fs_tmp(buf, ULOG_SIZE)) {
688                 pop_out_on_fs(buf, strlen(buf));
689                 memset(buf, 0, ULOG_SIZE);
690             }
691 #endif
692         } else {
693             LOGE(ULOG_TAG_SELF, "restart ulog fs fail");
694         }
695     }
696 }
697 
fs_control_cli(const char cmd,const char * param)698 void fs_control_cli(const char cmd, const char *param)
699 {
700     if (param != NULL) {
701         switch (cmd) {
702         case 't':
703             {
704                 int control_cmd = strtoul(param, NULL, 10);
705                 if (control_cmd) {
706                     ulog_man("fspause on=1");
707                 } else {
708                     ulog_man("fspause off=1");
709                 }
710                 break;
711             }
712         default:
713             break;
714         }
715     }
716 }
717 
ulog_fs_log_file_size(unsigned int filesize)718 int ulog_fs_log_file_size(unsigned int filesize)
719 {
720     if (filesize < ULOG_SIZE) {
721         return -1;
722     }
723 
724     gu32_log_file_size = filesize;
725     return 0;
726 }
727 
ulog_fs_log_file_path(char * filepath)728 int ulog_fs_log_file_path(char *filepath)
729 {
730     size_t len = 0;
731     size_t max_len = 0;
732     int ret = 0;
733     aos_dir_t *pstdir = NULL;
734     bool is_last_char_slash = false;
735 
736     if (NULL == filepath) {
737         return -1;
738     }
739 
740     len = strlen(filepath);
741     /*we need to reserve one byte for /0 and one byte for / */
742     max_len = (ULOG_FILE_PATH_SIZE / 2) - 1;
743     if (len > max_len) {
744         SESSION_FS_INFO("log file path length %d over size %d", len, max_len - 1);
745         return -1;
746     }
747     memset(guc_logfile_path, 0, sizeof(guc_logfile_path));
748     memcpy(guc_logfile_path, filepath, len);
749 
750     /*remove / at first to make dir ,then and / */
751     is_last_char_slash = (filepath[len - 1] == '/');
752     if (is_last_char_slash) {
753         guc_logfile_path[len - 1] = 0;
754     }
755 
756     /*check logfile path exist */
757     pstdir = aos_opendir(guc_logfile_path);
758     if (NULL == pstdir) {
759         /*log file path doesn't exist , creat it*/
760         ret = aos_mkdir(guc_logfile_path);
761         if (ret) {
762             SESSION_FS_INFO("%s %d log dir path %s doesn't exist and mkdir fail %d \r\n", __FILE__, __LINE__,
763                             guc_logfile_path, ret);
764             goto finish;
765         }
766     } else {
767         aos_closedir(pstdir);
768     }
769 
770 finish:
771     /*and / for log file process*/
772     if (is_last_char_slash) {
773         guc_logfile_path[len - 1] = '/';
774     }
775 
776     return ret;
777 }
778 
779 /**
780  * @brief ulog on fs init
781  *
782  * @return 0 indicates initialized sucessfully, or else fail
783  *
784  */
ulog_fs_init()785 int32_t ulog_fs_init()
786 {
787     int32_t rc = -1;
788     if (0 == session_fs_init) {
789         session_fs_init = 1;
790         cfg_init_mutex();
791         ulog_fs_log_file_path(ULOG_DEAULT_FS_PATH);
792         rc = reload_log_argu();
793         if (rc == 0) {
794             SESSION_FS_INFO("reload ulog idx %d len %d \n", get_working_from_cfg_mm(), operating_file_offset);
795         }
796     }
797     return rc;
798 }
799