Line data Source code
1 : /**
2 : * Copyright (C) 2015 Advanced Driver Information Technology.
3 : * This code is developed by Advanced Driver Information Technology.
4 : * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
5 : *
6 : * DLT offline log storage functionality source file.
7 : *
8 : * \copyright
9 : * This Source Code Form is subject to the terms of the
10 : * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
11 : * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 : *
13 : *
14 : * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015
15 : * \author Syed Hameed <shameed@jp.adit-jv.com> ADIT 2015
16 : *
17 : * \file: dlt_offline_logstorage_behavior.c
18 : * For further information see http://www.covesa.org/.
19 : */
20 :
21 : #include <syslog.h>
22 : #include <limits.h>
23 : #include <dirent.h>
24 : #include <string.h>
25 : #include <sys/types.h>
26 : #include <sys/stat.h>
27 : #include <unistd.h>
28 : #include <stdlib.h>
29 : #include <errno.h>
30 : #include <libgen.h>
31 :
32 : #include "dlt_log.h"
33 : #include "dlt_offline_logstorage.h"
34 : #include "dlt_offline_logstorage_behavior.h"
35 : #include "dlt_offline_logstorage_behavior_internal.h"
36 :
37 : unsigned int g_logstorage_cache_size;
38 :
39 : /**
40 : * dlt_logstorage_concat
41 : *
42 : * Concatenates two strings but keeps the size of the result less than dst_size.
43 : *
44 : * @param dst The destination string
45 : * @param src The source string to concat
46 : */
47 83 : DLT_STATIC void dlt_logstorage_concat_logfile_name(char* log_file_name, const char* append)
48 : {
49 83 : size_t dst_len = strnlen(log_file_name, DLT_MOUNT_PATH_MAX);
50 83 : size_t src_len = strlen(append);
51 :
52 83 : if (dst_len < DLT_MOUNT_PATH_MAX) {
53 83 : size_t rem_len = DLT_MOUNT_PATH_MAX - dst_len + 1;
54 : strncat(log_file_name, append, rem_len);
55 : } else {
56 0 : dlt_vlog(LOG_ERR, "Log file name reached max len: %s [%d]\n", log_file_name, DLT_MOUNT_PATH_MAX);
57 : }
58 :
59 83 : if (src_len + dst_len >= DLT_MOUNT_PATH_MAX) {
60 0 : dlt_vlog(LOG_ERR, "Log file path too long. Truncated: %s", log_file_name);
61 : }
62 83 : }
63 :
64 : /**
65 : * dlt_logstorage_log_file_name
66 : *
67 : * Create log file name in the form configured by the user
68 : * \<filename\>\<delimiter\>\<index\>\<delimiter\>\<timestamp\>.dlt
69 : *
70 : * filename: given in configuration file
71 : * delimiter: Punctuation characters (configured in dlt.conf)
72 : * timestamp: yyyy-mm-dd-hh-mm-ss (enabled/disabled in dlt.conf)
73 : * index: Index len depends on wrap around value in dlt.conf
74 : * ex: wrap around = 99, index will 01..99
75 : * (enabled/disabled in dlt.conf)
76 : *
77 : * @param[out] log_file_name target buffer for the complete logfile name.
78 : * it needs to fit DLT_MOUNT_PATH_MAX chars
79 : * @param[in] file_config User configurations for log file
80 : * @param[in] name file name given in configuration file
81 : * @param[in] num_files max files given in configuration file
82 : * @param[in] idx continous index of log files
83 : * @ return None
84 : */
85 40 : void dlt_logstorage_log_file_name(
86 : char* log_file_name, DltLogStorageUserConfig* file_config, const DltLogStorageFilterConfig* filter_config,
87 : const char* name, const int num_files, const int idx)
88 : {
89 40 : if ((log_file_name == NULL) || (file_config == NULL) || (filter_config == NULL))
90 : return;
91 :
92 39 : const char delim = file_config->logfile_delimiter;
93 39 : int index_width = (int)file_config->logfile_counteridxlen;
94 :
95 39 : if (file_config->logfile_maxcounter == UINT_MAX) {
96 : index_width = 0;
97 : }
98 :
99 39 : const char* suffix = filter_config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON ? ".dlt.gz" : ".dlt";
100 39 : const size_t smax = (size_t)DLT_MOUNT_PATH_MAX - strlen(suffix) - 1;
101 : size_t spos = 0;
102 39 : log_file_name[spos] = '\0';
103 : int rt;
104 :
105 : /* Append file name */
106 39 : spos += strlen(name);
107 39 : dlt_logstorage_concat_logfile_name(log_file_name, filter_config->file_name);
108 :
109 : /* Append index */
110 : /* Do not append if there is only one file and optional index mode is true*/
111 39 : if (!(num_files == 1 && file_config->logfile_optional_counter)) {
112 38 : rt = snprintf(log_file_name + spos, smax - spos, "%c%0*d", delim, index_width, idx);
113 38 : if ((size_t)rt >= smax - spos) {
114 0 : dlt_vlog(LOG_WARNING, "%s: snprintf truncation %s\n", __func__, log_file_name);
115 : spos = smax;
116 38 : } else if (rt < 0) {
117 0 : dlt_vlog(LOG_ERR, "%s: snprintf error rt=%d\n", __func__, rt);
118 : const char* fmt_err = "fmt_err";
119 : memcpy(log_file_name, fmt_err, strlen(fmt_err) + 1);
120 : spos = strlen(fmt_err) + 1;
121 : } else {
122 : spos += (size_t)rt;
123 : }
124 : }
125 :
126 : /* Add time stamp if user has configured */
127 39 : if (file_config->logfile_timestamp) {
128 5 : char stamp[DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1] = {0};
129 5 : time_t t = time(NULL);
130 : struct tm tm_info;
131 : ssize_t n = 0;
132 5 : tzset();
133 5 : localtime_r(&t, &tm_info);
134 5 : n = snprintf(
135 : stamp, DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1, "%c%04d%02d%02d-%02d%02d%02d", delim,
136 5 : 1900 + tm_info.tm_year, 1 + tm_info.tm_mon, tm_info.tm_mday, tm_info.tm_hour, tm_info.tm_min,
137 : tm_info.tm_sec);
138 5 : if (n < 0 || (size_t)n > (DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1)) {
139 0 : dlt_vlog(LOG_WARNING, "%s: snprintf truncation %s\n", __func__, stamp);
140 : }
141 5 : dlt_logstorage_concat_logfile_name(log_file_name, stamp);
142 : }
143 :
144 39 : dlt_logstorage_concat_logfile_name(log_file_name, ".dlt");
145 39 : if (filter_config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
146 0 : dlt_logstorage_concat_logfile_name(log_file_name, ".gz");
147 : }
148 : }
149 :
150 : /**
151 : * dlt_logstorage_sort_file_name
152 : *
153 : * Sort the filenames with index based ascending order (bubble sort)
154 : *
155 : * @param head Log filename list
156 : * @ return The last (biggest) index
157 : */
158 72 : unsigned int dlt_logstorage_sort_file_name(DltLogStorageFileList** head)
159 : {
160 : int done = 0;
161 : unsigned int max_idx = 0;
162 :
163 72 : if ((head == NULL) || (*head == NULL) || ((*head)->next == NULL))
164 : return 0;
165 :
166 69 : while (!done) {
167 : /* "source" of the pointer to the current node in the list struct */
168 : DltLogStorageFileList** pv = head;
169 36 : DltLogStorageFileList* nd = *head; /* local iterator pointer */
170 36 : DltLogStorageFileList* nx = (*head)->next; /* local next pointer */
171 :
172 : done = 1;
173 :
174 79 : while (nx) {
175 43 : max_idx = nx->idx;
176 43 : if (nd->idx > nx->idx) {
177 : max_idx = nd->idx;
178 4 : nd->next = nx->next;
179 4 : nx->next = nd;
180 4 : *pv = nx;
181 :
182 : done = 0;
183 : }
184 :
185 43 : pv = &nd->next;
186 : nd = nx;
187 43 : nx = nx->next;
188 : }
189 : }
190 :
191 : return max_idx;
192 : }
193 :
194 : /**
195 : * dlt_logstorage_rearrange_file_name
196 : *
197 : * Rearrange the filenames in the order of latest and oldest
198 : *
199 : * @param head Log filename list
200 : * @ return None
201 : */
202 3 : void dlt_logstorage_rearrange_file_name(DltLogStorageFileList** head)
203 : {
204 : DltLogStorageFileList* n_prev = NULL;
205 : DltLogStorageFileList* tail = NULL;
206 : DltLogStorageFileList* wrap_pre = NULL;
207 : DltLogStorageFileList* wrap_post = NULL;
208 : DltLogStorageFileList* n = NULL;
209 :
210 3 : if ((head == NULL) || (*head == NULL) || ((*head)->next == NULL))
211 : return;
212 :
213 2 : if ((*head)->idx != 1) {
214 : /* Do not sort */
215 : return;
216 : }
217 :
218 4 : for (n = *head; n != NULL; n = n->next) {
219 : /* Compare the diff between n->idx and n_prev->idx only if
220 : * wrap_post and wrap_pre are not set yet. Otherwise continue the loop
221 : * until the tail */
222 3 : if (n && n_prev && !wrap_post && !wrap_pre) {
223 1 : if ((n->idx - n_prev->idx) != 1) {
224 : wrap_post = n;
225 : wrap_pre = n_prev;
226 : }
227 : }
228 :
229 : n_prev = n;
230 : }
231 :
232 : tail = n_prev;
233 :
234 1 : if (wrap_post && wrap_pre) {
235 1 : wrap_pre->next = NULL;
236 1 : tail->next = *head;
237 1 : *head = wrap_post;
238 : }
239 : }
240 :
241 : /**
242 : * dlt_logstorage_get_idx_of_log_file
243 : *
244 : * Extract index of log file name passed as input argument
245 : *
246 : * @param file_config User configurations for log file
247 : * @param config Filter configurations for log file
248 : * @param file file name to extract the index from
249 : * @return index on success, -1 if no index is found
250 : */
251 110 : unsigned int dlt_logstorage_get_idx_of_log_file(
252 : DltLogStorageUserConfig* file_config, DltLogStorageFilterConfig* config, char* file)
253 : {
254 110 : if (file_config == NULL || config == NULL || file == NULL)
255 : return (unsigned int)-1;
256 :
257 : long idx = 0;
258 : size_t basename_len;
259 : char *sptr, *eptr;
260 :
261 : /* Find the next delimiter after the first one:
262 : * Eg. base-log-name_<idx>_<timestamp>.dlt
263 : * ^ ^
264 : * | |
265 : * From here --+ +--- To this position
266 : */
267 109 : basename_len = strlen(config->file_name);
268 109 : sptr = file + basename_len + 1;
269 109 : eptr = strchr(sptr, file_config->logfile_delimiter);
270 109 : idx = strtol(sptr, &eptr, 10);
271 :
272 109 : if (idx == 0)
273 0 : dlt_log(LOG_ERR, "Unable to calculate index from log file name. Reset to 001.\n");
274 :
275 109 : return (unsigned int)idx;
276 : }
277 :
278 : /**
279 : * dlt_logstorage_storage_dir_info
280 : *
281 : * Read file names of storage directory.
282 : * Update the file list, arrange it in order of latest and oldest
283 : *
284 : * @param file_config User configurations for log file
285 : * @param path Path to storage directory
286 : * @param config DltLogStorageFilterConfig
287 : * @return 0 on success, -1 on error
288 : */
289 71 : int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig* file_config, char* path, DltLogStorageFilterConfig* config)
290 : {
291 : int check = 0;
292 : int i = 0;
293 : int cnt = 0;
294 : int ret = 0;
295 : unsigned int max_idx = 0;
296 71 : struct dirent** files = {0};
297 : unsigned int current_idx = 0;
298 : DltLogStorageFileList* n = NULL;
299 : DltLogStorageFileList* n1 = NULL;
300 71 : char storage_path[DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN + 1] = {'\0'};
301 71 : char file_name[DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN + 1] = {'\0'};
302 : char* dir = NULL;
303 :
304 71 : if ((config == NULL) || (file_config == NULL) || (path == NULL) || (config->file_name == NULL))
305 : return -1;
306 :
307 : strncpy(storage_path, path, DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN);
308 :
309 70 : if (strstr(config->file_name, "/") != NULL) {
310 : /* Append directory path */
311 0 : char tmpdir[DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN + 1] = {'\0'};
312 0 : char tmpfile[DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN + 1] = {'\0'};
313 : char* file;
314 : strncpy(tmpdir, config->file_name, DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN);
315 : strncpy(tmpfile, config->file_name, DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN);
316 0 : dir = dirname(tmpdir);
317 0 : file = basename(tmpfile);
318 0 : if ((strlen(path) + strlen(dir)) > DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN) {
319 0 : dlt_vlog(LOG_ERR, "%s: Directory name [%s] is too long to store (file name [%s])\n", __func__, dir, file);
320 0 : return -1;
321 : }
322 0 : strncat(storage_path, dir, DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN - strlen(storage_path));
323 : strncpy(file_name, file, DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN);
324 : } else {
325 : strncpy(file_name, config->file_name, DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN);
326 : }
327 :
328 70 : cnt = scandir(storage_path, &files, 0, alphasort);
329 :
330 70 : if (cnt < 0) {
331 0 : dlt_vlog(LOG_ERR, "%s: Failed to scan directory [%s] for file name [%s]\n", __func__, storage_path, file_name);
332 0 : return -1;
333 : }
334 :
335 70 : dlt_vlog(LOG_DEBUG, "%s: Scanned [%d] files from %s\n", __func__, cnt, storage_path);
336 :
337 : /* In order to have a latest status of file list,
338 : * the existing records must be deleted before updating
339 : */
340 70 : n = config->records;
341 70 : if (config->records) {
342 131 : while (n) {
343 : n1 = n;
344 81 : n = n->next;
345 81 : free(n1->name);
346 : n1->name = NULL;
347 81 : free(n1);
348 : n1 = NULL;
349 : }
350 50 : config->records = NULL;
351 : }
352 :
353 70 : char* suffix = config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON ? ".dlt.gz" : ".dlt";
354 :
355 1733 : for (i = 0; i < cnt; i++) {
356 1663 : size_t len = strlen(file_name);
357 :
358 1663 : dlt_vlog(
359 1663 : LOG_DEBUG, "%s: Scanned file name=[%s], filter file name=[%s]\n", __func__, files[i]->d_name, file_name);
360 1663 : if (strncmp(files[i]->d_name, file_name, len) == 0) {
361 177 : if (config->num_files == 1 && file_config->logfile_optional_counter) {
362 : /* <filename>.dlt or <filename>_<tmsp>.dlt */
363 0 : if ((files[i]->d_name[len] == suffix[0])
364 0 : || (file_config->logfile_timestamp && (files[i]->d_name[len] == file_config->logfile_delimiter))) {
365 : current_idx = 1;
366 : } else {
367 92 : continue;
368 : }
369 : } else {
370 : /* <filename>_idx.dlt or <filename>_idx_<tmsp>.dlt */
371 177 : if (files[i]->d_name[len] == file_config->logfile_delimiter) {
372 85 : current_idx = dlt_logstorage_get_idx_of_log_file(file_config, config, files[i]->d_name);
373 : } else {
374 92 : continue;
375 : }
376 : }
377 :
378 : DltLogStorageFileList** tmp = NULL;
379 :
380 85 : if (config->records == NULL) {
381 53 : config->records = malloc(sizeof(DltLogStorageFileList));
382 :
383 53 : if (config->records == NULL) {
384 : ret = -1;
385 0 : dlt_log(LOG_ERR, "Memory allocation failed\n");
386 0 : break;
387 : }
388 :
389 53 : tmp = &config->records;
390 : } else {
391 32 : tmp = &config->records;
392 :
393 64 : while (*(tmp) != NULL)
394 32 : tmp = &(*tmp)->next;
395 :
396 32 : *tmp = malloc(sizeof(DltLogStorageFileList));
397 :
398 32 : if (*tmp == NULL) {
399 : ret = -1;
400 0 : dlt_log(LOG_ERR, "Memory allocation failed\n");
401 0 : break;
402 : }
403 : }
404 :
405 85 : char tmpfile[DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN + 1] = {'\0'};
406 85 : if (dir != NULL) {
407 : /* Append directory path */
408 : strcat(tmpfile, dir);
409 : strcat(tmpfile, "/");
410 : }
411 85 : strcat(tmpfile, files[i]->d_name);
412 85 : (*tmp)->name = strdup(tmpfile);
413 85 : (*tmp)->idx = current_idx;
414 85 : (*tmp)->next = NULL;
415 85 : check++;
416 : }
417 : }
418 :
419 70 : dlt_vlog(LOG_DEBUG, "%s: After dir scan: [%d] files of [%s]\n", __func__, check, file_name);
420 :
421 70 : if (ret == 0) {
422 70 : max_idx = dlt_logstorage_sort_file_name(&config->records);
423 :
424 : /* Fault tolerance:
425 : * In case there are some log files are removed but
426 : * the index is still not reaching maxcounter, no need
427 : * to perform rearrangement of filename.
428 : * This would help the log keeps growing until maxcounter is reached and
429 : * the maximum number of log files could be obtained.
430 : */
431 70 : if (max_idx == file_config->logfile_maxcounter)
432 0 : dlt_logstorage_rearrange_file_name(&config->records);
433 : }
434 :
435 : /* free scandir result */
436 1733 : for (i = 0; i < cnt; i++)
437 1663 : free(files[i]);
438 :
439 70 : free(files);
440 :
441 70 : return ret;
442 : }
443 :
444 : /**
445 : * dlt_logstorage_open_log_output_file
446 : *
447 : * Open a handle to the logfile
448 : *
449 : * @param config A pointer to the current DltLogStorageFilterConfig
450 : * @param fpath The file path
451 : * @param mode The mode to open the file with
452 : */
453 47 : DLT_STATIC void dlt_logstorage_open_log_output_file(
454 : DltLogStorageFilterConfig* config, const char* fpath, const char* mode)
455 : {
456 47 : FILE* file = fopen(fpath, mode);
457 47 : if (file == NULL) {
458 0 : dlt_vlog(LOG_DEBUG, "%s: could not open configuration file\n", __func__);
459 0 : return;
460 : }
461 47 : config->fd = fileno(file);
462 47 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
463 : #ifdef DLT_LOGSTORAGE_USE_GZIP
464 : dlt_vlog(LOG_DEBUG, "%s: Opening GZIP log file\n", __func__);
465 : config->gzlog = gzdopen(config->fd, mode);
466 : #endif
467 : } else {
468 47 : dlt_vlog(LOG_DEBUG, "%s: Opening log file\n", __func__);
469 47 : config->log = file;
470 : }
471 : }
472 :
473 : /**
474 : * dlt_logstorage_open_log_file
475 : *
476 : * Open a log file. Check storage directory for already created files and open
477 : * the oldest if there is enough space to store at least msg_size.
478 : * Otherwise create a new file, but take configured max number of files into
479 : * account and remove the oldest file if needed.
480 : *
481 : * @param config DltLogStorageFilterConfig
482 : * @param file_config User configurations for log file
483 : * @param dev_path Storage device path
484 : * @param msg_size Size of incoming message
485 : * @param is_update_required The file list needs to be updated
486 : * @return 0 on succes, -1 on error
487 : */
488 70 : int dlt_logstorage_open_log_file(
489 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, int msg_size,
490 : bool is_update_required, bool is_sync)
491 : {
492 : int ret = 0;
493 70 : char absolute_file_path[DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN + 1] = {'\0'};
494 70 : char storage_path[DLT_MOUNT_PATH_MAX + 1] = {'\0'};
495 70 : char file_name[DLT_OFFLINE_LOGSTORAGE_MAX_LOG_FILE_LEN + 1] = {'\0'};
496 : unsigned int num_log_files = 0;
497 : struct stat s;
498 : memset(&s, 0, sizeof(struct stat));
499 : DltLogStorageFileList** tmp = NULL;
500 : DltLogStorageFileList** newest = NULL;
501 :
502 70 : if (config == NULL)
503 : return -1;
504 :
505 69 : if (strlen(dev_path) > DLT_MOUNT_PATH_MAX) {
506 0 : dlt_vlog(LOG_ERR, "device path '%s' is too long to store\n", dev_path);
507 0 : return -1;
508 : }
509 :
510 69 : size_t dev_path_len = strnlen(dev_path, DLT_MOUNT_PATH_MAX - 2);
511 69 : if (dev_path_len + 2 > DLT_MOUNT_PATH_MAX) {
512 0 : dlt_vlog(LOG_ERR, "device path too long for storage_path buffer\n");
513 0 : return -1;
514 : }
515 : int written = snprintf(storage_path, DLT_MOUNT_PATH_MAX, "%s/", dev_path);
516 69 : if (written < 0 || (size_t)written >= DLT_MOUNT_PATH_MAX) {
517 0 : dlt_vlog(LOG_ERR, "snprintf truncated storage_path\n");
518 0 : return -1;
519 : }
520 :
521 : /* check if there are already files stored */
522 69 : if (config->records == NULL || is_update_required) {
523 69 : if (dlt_logstorage_storage_dir_info(file_config, storage_path, config) != 0)
524 : return -1;
525 : }
526 :
527 : /* obtain locations of newest, current file names, file count */
528 69 : tmp = &config->records;
529 :
530 154 : while (*(tmp) != NULL) {
531 85 : num_log_files += 1;
532 :
533 85 : if ((*tmp)->next == NULL)
534 : newest = tmp;
535 :
536 85 : tmp = &(*tmp)->next;
537 : }
538 :
539 : /* need new file*/
540 69 : if (num_log_files == 0) {
541 16 : dlt_logstorage_log_file_name(file_name, file_config, config, config->file_name, (int)config->num_files, 1);
542 :
543 : /* concatenate path and file and open absolute path */
544 : strcat(absolute_file_path, storage_path);
545 : strcat(absolute_file_path, file_name);
546 16 : config->working_file_name = strdup(file_name);
547 16 : dlt_logstorage_open_log_output_file(config, absolute_file_path, "a");
548 :
549 : /* Add file to file list */
550 16 : *tmp = malloc(sizeof(DltLogStorageFileList));
551 :
552 16 : if (*tmp == NULL) {
553 0 : dlt_log(LOG_ERR, "Memory allocation for file name failed\n");
554 0 : return -1;
555 : }
556 :
557 16 : (*tmp)->name = strdup(file_name);
558 16 : (*tmp)->idx = 1;
559 16 : (*tmp)->next = NULL;
560 : } else {
561 : strcat(absolute_file_path, storage_path);
562 :
563 : /* newest file available
564 : * Since the working file is already updated from newest file info
565 : * So if there is already wrap-up, the newest file will be the working file
566 : */
567 53 : if ((config->wrap_id == 0) || (config->working_file_name == NULL)) {
568 51 : if (config->working_file_name != NULL) {
569 50 : free(config->working_file_name);
570 50 : config->working_file_name = NULL;
571 : }
572 51 : config->working_file_name = strdup((*newest)->name);
573 : }
574 53 : size_t abs_len = strnlen(absolute_file_path, sizeof(absolute_file_path));
575 53 : size_t name_len = strnlen(config->working_file_name, sizeof(absolute_file_path) - abs_len - 1);
576 53 : if (abs_len + name_len >= sizeof(absolute_file_path)) {
577 0 : dlt_vlog(LOG_ERR, "absolute_file_path too small for working_file_name\n");
578 0 : return -1;
579 : }
580 53 : snprintf(absolute_file_path + abs_len, sizeof(absolute_file_path) - abs_len, "%s", config->working_file_name);
581 :
582 53 : dlt_vlog(
583 : LOG_DEBUG, "%s: Number of log files-newest file-wrap_id [%u]-[%s]-[%u]\n", __func__, num_log_files,
584 : config->working_file_name, config->wrap_id);
585 :
586 53 : ret = stat(absolute_file_path, &s);
587 :
588 : /* if file stats is read and, either
589 : * is_sync is true and (other than ON_MSG sync behavior and current size is less than configured size) or
590 : * msg_size fit into the size (ON_MSG or par of cache needs to be written into new file), open it */
591 53 : if ((ret == 0)
592 53 : && ((is_sync && (s.st_size < (long)config->file_size))
593 22 : || (!is_sync && (s.st_size + msg_size <= (long)config->file_size)))) {
594 31 : dlt_logstorage_open_log_output_file(config, absolute_file_path, "a");
595 31 : config->current_write_file_offset = (unsigned int)s.st_size;
596 : } else {
597 : /* no space in file or file stats cannot be read */
598 : unsigned int idx = 0;
599 :
600 : /* get index of newest log file */
601 22 : if (config->num_files == 1 && file_config->logfile_optional_counter) {
602 : idx = 1;
603 : } else {
604 22 : idx = dlt_logstorage_get_idx_of_log_file(file_config, config, config->working_file_name);
605 : }
606 :
607 : /* Check if file logging shall be stopped */
608 22 : if (config->overwrite == DLT_LOGSTORAGE_OVERWRITE_DISCARD_NEW) {
609 8 : dlt_vlog(
610 : LOG_DEBUG, "%s: num_files=%d, current_idx=%d (filename=%s)\n", __func__, config->num_files, idx,
611 : config->file_name);
612 :
613 8 : if (config->num_files == idx) {
614 4 : dlt_vlog(
615 : LOG_INFO, "%s: logstorage limit reached, stopping capture for filter: %s\n", __func__,
616 : config->file_name);
617 4 : config->skip = 1;
618 4 : return 0;
619 : }
620 : }
621 :
622 18 : idx += 1;
623 :
624 : /* wrap around if max index is reached or an error occurred
625 : * while calculating index from file name */
626 18 : if ((idx > file_config->logfile_maxcounter) || (idx == 0)) {
627 : idx = 1;
628 2 : config->wrap_id += 1;
629 : }
630 :
631 18 : dlt_logstorage_log_file_name(
632 18 : file_name, file_config, config, config->file_name, (int)config->num_files, (int)idx);
633 :
634 : /* concatenate path and file and open absolute path */
635 : memset(absolute_file_path, 0, sizeof(absolute_file_path) / sizeof(char));
636 : strcat(absolute_file_path, storage_path);
637 : strcat(absolute_file_path, file_name);
638 :
639 18 : if (config->working_file_name) {
640 18 : free(config->working_file_name);
641 18 : config->working_file_name = strdup(file_name);
642 : }
643 :
644 : /* If there is already wrap-up, check the existence of file
645 : * remove it and reopen it.
646 : * In this case number of log file won't be increased*/
647 18 : if (config->wrap_id && stat(absolute_file_path, &s) == 0) {
648 1 : remove(absolute_file_path);
649 1 : num_log_files -= 1;
650 1 : dlt_vlog(
651 : LOG_DEBUG, "%s: Remove '%s' (num_log_files: %u, config->num_files:%u)\n", __func__,
652 : absolute_file_path, num_log_files, config->num_files);
653 : }
654 :
655 18 : config->log = fopen(absolute_file_path, "w+");
656 :
657 18 : dlt_vlog(LOG_DEBUG, "%s: Filename and Index after updating [%s]-[%u]\n", __func__, file_name, idx);
658 :
659 : /* Add file to file list */
660 18 : *tmp = malloc(sizeof(DltLogStorageFileList));
661 :
662 18 : if (*tmp == NULL) {
663 0 : dlt_log(LOG_ERR, "Memory allocation for file name failed\n");
664 0 : return -1;
665 : }
666 :
667 18 : (*tmp)->name = strdup(file_name);
668 18 : (*tmp)->idx = idx;
669 18 : (*tmp)->next = NULL;
670 :
671 18 : num_log_files += 1;
672 :
673 : /* check if number of log files exceeds configured max value */
674 18 : if (num_log_files > config->num_files) {
675 11 : if (!(config->num_files == 1 && file_config->logfile_optional_counter)) {
676 : /* delete oldest */
677 : DltLogStorageFileList** head = &config->records;
678 11 : DltLogStorageFileList* n = *head;
679 : memset(absolute_file_path, 0, sizeof(absolute_file_path) / sizeof(char));
680 : strcat(absolute_file_path, storage_path);
681 11 : size_t abs_len2 = strnlen(absolute_file_path, sizeof(absolute_file_path));
682 11 : size_t head_name_len = strnlen((*head)->name, sizeof(absolute_file_path) - abs_len2 - 1);
683 11 : if (abs_len2 + head_name_len >= sizeof(absolute_file_path)) {
684 0 : dlt_vlog(LOG_ERR, "absolute_file_path too small for head->name\n");
685 0 : return -1;
686 : }
687 11 : snprintf(absolute_file_path + abs_len2, sizeof(absolute_file_path) - abs_len2, "%s", (*head)->name);
688 11 : dlt_vlog(
689 : LOG_DEBUG, "%s: Remove '%s' (num_log_files: %d, config->num_files:%d, file_name:%s)\n",
690 : __func__, absolute_file_path, num_log_files, config->num_files, config->file_name);
691 11 : if (remove(absolute_file_path) != 0)
692 0 : dlt_log(LOG_ERR, "Could not remove file\n");
693 :
694 11 : free((*head)->name);
695 11 : (*head)->name = NULL;
696 11 : *head = n->next;
697 : n->next = NULL;
698 11 : free(n);
699 : }
700 : }
701 : }
702 : }
703 :
704 : #ifdef DLT_LOGSTORAGE_USE_GZIP
705 : if (config->gzlog == NULL && config->log == NULL) {
706 : #else
707 65 : if (config->log == NULL) {
708 : #endif
709 0 : if (*tmp != NULL) {
710 0 : if ((*tmp)->name != NULL) {
711 0 : free((*tmp)->name);
712 0 : (*tmp)->name = NULL;
713 : }
714 0 : free(*tmp);
715 0 : *tmp = NULL;
716 : }
717 :
718 0 : if (config->working_file_name != NULL) {
719 0 : free(config->working_file_name);
720 0 : config->working_file_name = NULL;
721 : }
722 :
723 0 : dlt_vlog(LOG_ERR, "%s: Unable to open log file.\n", __func__);
724 0 : return -1;
725 : }
726 :
727 : return ret;
728 : }
729 :
730 : /**
731 : * dlt_logstorage_find_dlt_header
732 : *
733 : * search for dlt header in cache
734 : *
735 : * @param ptr cache starting position
736 : * @param offset offset
737 : * @param cnt count
738 : * @return index on success, -1 on error
739 : */
740 55 : DLT_STATIC int dlt_logstorage_find_dlt_header(void* ptr, unsigned int offset, unsigned int cnt)
741 : {
742 55 : const char magic[] = {'D', 'L', 'T', 0x01};
743 55 : const char* cache = (char*)ptr + offset;
744 :
745 : unsigned int i;
746 69 : for (i = 0; i < cnt; i++) {
747 68 : if ((cache[i] == 'D') && (strncmp(&cache[i], magic, 4) == 0))
748 54 : return (int)i;
749 : }
750 :
751 : return -1;
752 : }
753 :
754 : /**
755 : * dlt_logstorage_find_last_dlt_header
756 : *
757 : * search for last dlt header in cache
758 : *
759 : * @param ptr cache starting position
760 : * @param offset offset
761 : * @param cnt count
762 : * @return index on success, -1 on error
763 : */
764 14 : DLT_STATIC int dlt_logstorage_find_last_dlt_header(void* ptr, unsigned int offset, unsigned int cnt)
765 : {
766 14 : const char magic[] = {'D', 'L', 'T', 0x01};
767 14 : const char* cache = (char*)ptr + offset;
768 :
769 : int i;
770 896 : for (i = (int)cnt - (DLT_ID_SIZE - 1); i > 0; i--) {
771 887 : if ((cache[i] == 'D') && (strncmp(&cache[i], magic, 4) == 0))
772 5 : return i;
773 : }
774 :
775 : return -1;
776 : }
777 :
778 : /**
779 : * dlt_logstorage_write_to_log
780 : *
781 : * Write logdata to log storage file
782 : *
783 : * @param ptr A pointer to the data to write
784 : * @param size The size of the data blocks
785 : * @param nmemb The number of blocks to write
786 : * @param config A pointer to DltLogStorageFilterConfig
787 : */
788 5 : DLT_STATIC int dlt_logstorage_write_to_log(void* ptr, size_t size, size_t nmemb, DltLogStorageFilterConfig* config)
789 : {
790 : #ifdef DLT_LOGSTORAGE_USE_GZIP
791 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
792 : return (int)gzfwrite(ptr, size, nmemb, config->gzlog);
793 : } else {
794 : return (int)fwrite(ptr, size, nmemb, config->log);
795 : }
796 : #else
797 5 : return (int)fwrite(ptr, size, nmemb, config->log);
798 : #endif
799 : }
800 :
801 : /**
802 : * dlt_logstorage_check_write_ret
803 : *
804 : * check the return value of fwrite/gzfwrite
805 : *
806 : * @param config DltLogStorageFilterConfig
807 : * @param ret return value of fwrite/gzfwrite call
808 : */
809 42 : DLT_STATIC void dlt_logstorage_check_write_ret(DltLogStorageFilterConfig* config, int ret)
810 : {
811 42 : if (config == NULL) {
812 0 : dlt_vlog(LOG_ERR, "%s: cannot retrieve config information\n", __func__);
813 0 : return;
814 : }
815 :
816 42 : if (ret <= 0) {
817 0 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
818 : #ifdef DLT_LOGSTORAGE_USE_GZIP
819 : const char* msg = gzerror(config->gzlog, &ret);
820 : if (msg != NULL) {
821 : dlt_vlog(LOG_ERR, "%s: failed to write cache into log file: %s\n", __func__, msg);
822 : }
823 : #endif
824 : } else {
825 0 : if (ferror(config->log) != 0)
826 0 : dlt_vlog(LOG_ERR, "%s: failed to write cache into log file\n", __func__);
827 : }
828 : } else {
829 : /* force sync */
830 42 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
831 : #ifdef DLT_LOGSTORAGE_USE_GZIP
832 : if (gzflush(config->gzlog, Z_SYNC_FLUSH) != 0)
833 : dlt_vlog(LOG_ERR, "%s: failed to gzflush log file\n", __func__);
834 : #endif
835 : } else {
836 42 : if (fflush(config->log) != 0)
837 0 : dlt_vlog(LOG_ERR, "%s: failed to flush log file\n", __func__);
838 : }
839 :
840 42 : if (fsync(config->fd) != 0) {
841 : /* some filesystem doesn't support fsync() */
842 0 : if (errno != ENOSYS) {
843 0 : dlt_vlog(LOG_ERR, "%s: failed to sync log file\n", __func__);
844 : }
845 : }
846 : }
847 : }
848 :
849 : /**
850 : * dlt_logstorage_close_file
851 : *
852 : * Close open file handles if any exist in the provided
853 : * DltLogStorageFilterConfig
854 : *
855 : * @param config The DltLogStorageFilterConfig to operate on
856 : */
857 4 : DLT_STATIC void dlt_logstorage_close_file(DltLogStorageFilterConfig* config)
858 : {
859 : #ifdef DLT_LOGSTORAGE_USE_GZIP
860 : if (config->gzlog) {
861 : gzclose(config->gzlog);
862 : config->gzlog = NULL;
863 : }
864 : #endif
865 37 : if (config->log) {
866 58 : fclose(config->log);
867 58 : config->log = NULL;
868 : }
869 4 : }
870 :
871 : /**
872 : * dlt_logstorage_sync_to_file
873 : *
874 : * Write the log message to log file
875 : *
876 : * @param config DltLogStorageFilterConfig
877 : * @param file_config DltLogStorageUserConfig
878 : * @param dev_path Storage device mount point path
879 : * @param footer DltLogStorageCacheFooter
880 : * @param start_offset Start offset of the cache
881 : * @param end_offset End offset of the cache
882 : * @return 0 on success, -1 on error
883 : */
884 43 : DLT_STATIC int dlt_logstorage_sync_to_file(
885 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path,
886 : DltLogStorageCacheFooter* footer, unsigned int start_offset, unsigned int end_offset)
887 : {
888 : int ret = 0;
889 : int start_index = 0;
890 : int end_index = 0;
891 : int count = 0;
892 : unsigned int remain_file_size = 0;
893 :
894 43 : if ((config == NULL) || (file_config == NULL) || (dev_path == NULL) || (footer == NULL)) {
895 1 : dlt_vlog(LOG_ERR, "%s: cannot retrieve config information\n", __func__);
896 1 : return -1;
897 : }
898 :
899 42 : count = (int)(end_offset - start_offset);
900 :
901 : /* In case of cached-based strategy, the newest file information
902 : * must be updated everytime of synchronization.
903 : */
904 2 : dlt_logstorage_close_file(config);
905 42 : config->current_write_file_offset = 0;
906 :
907 42 : if (dlt_logstorage_open_log_file(config, file_config, dev_path, count, true, true) != 0) {
908 0 : dlt_vlog(LOG_ERR, "%s: failed to open log file\n", __func__);
909 0 : return -1;
910 : }
911 :
912 42 : if (config->skip == 1) {
913 0 : dlt_logstorage_close_file(config);
914 1 : return 0;
915 : }
916 :
917 41 : remain_file_size = (unsigned int)(config->file_size - config->current_write_file_offset);
918 :
919 41 : if ((unsigned int)count > remain_file_size) {
920 : /* Check if more than one message can fit into the remaining file */
921 12 : start_index = dlt_logstorage_find_dlt_header(config->cache, start_offset, remain_file_size);
922 12 : end_index = dlt_logstorage_find_last_dlt_header(
923 : config->cache, (unsigned int)start_offset + (unsigned int)start_index,
924 12 : remain_file_size - (unsigned int)start_index);
925 12 : count = (int)(end_index - start_index);
926 :
927 12 : if ((start_index >= 0) && (end_index > start_index) && (count > 0)
928 4 : && ((unsigned int)count <= remain_file_size)) {
929 4 : ret = dlt_logstorage_write_to_log(
930 4 : (uint8_t*)config->cache + start_offset + start_index, (size_t)count, 1, config);
931 4 : dlt_logstorage_check_write_ret(config, ret);
932 :
933 : /* Close log file */
934 0 : dlt_logstorage_close_file(config);
935 4 : config->current_write_file_offset = 0;
936 :
937 4 : footer->last_sync_offset = (unsigned int)start_offset + (unsigned int)count;
938 4 : start_offset = footer->last_sync_offset;
939 : } else {
940 : /* Close log file */
941 0 : dlt_logstorage_close_file(config);
942 8 : config->current_write_file_offset = 0;
943 : }
944 : }
945 :
946 41 : start_index = dlt_logstorage_find_dlt_header(config->cache, start_offset, (unsigned int)count);
947 41 : count = (int)(end_offset - start_offset - (unsigned int)start_index);
948 :
949 41 : if ((start_index >= 0) && (count > 0)) {
950 : /* Prepare log file */
951 : #ifdef DLT_LOGSTORAGE_USE_GZIP
952 : if (config->log == NULL && config->gzlog == NULL)
953 : #else
954 41 : if (config->log == NULL)
955 : #endif
956 : {
957 12 : if (dlt_logstorage_open_log_file(config, file_config, dev_path, count, true, false) != 0) {
958 0 : dlt_vlog(LOG_ERR, "%s: failed to open log file\n", __func__);
959 0 : dlt_logstorage_close_file(config);
960 0 : return -1;
961 : }
962 :
963 12 : if (config->skip == 1) {
964 0 : dlt_logstorage_close_file(config);
965 3 : return 0;
966 : }
967 : }
968 :
969 : ret =
970 38 : dlt_logstorage_write_to_log((uint8_t*)config->cache + start_offset + start_index, (size_t)count, 1, config);
971 38 : dlt_logstorage_check_write_ret(config, ret);
972 :
973 38 : config->current_write_file_offset += (unsigned int)count;
974 38 : footer->last_sync_offset = (unsigned int)end_offset;
975 : }
976 :
977 38 : footer->wrap_around_cnt = 0;
978 2 : dlt_logstorage_close_file(config);
979 2 : return 0;
980 : }
981 :
982 : /**
983 : * dlt_logstorage_prepare_on_msg
984 : *
985 : * Prepare the log file for a certain filer. If log file not open or log
986 : * files max size reached, open a new file.
987 : *
988 : * @param config DltLogStorageFilterConfig
989 : * @param file_config User configurations for log file
990 : * @param dev_path Storage device path
991 : * @param log_msg_size Size of log message
992 : * @param newest_file_info Info of newest file for corresponding filename
993 : * @return 0 on success, -1 on error
994 : */
995 93 : int dlt_logstorage_prepare_on_msg(
996 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, int log_msg_size,
997 : DltNewestFileName* newest_file_info)
998 : {
999 : int ret = 0;
1000 : struct stat s;
1001 :
1002 93 : if ((config == NULL) || (file_config == NULL) || (dev_path == NULL) || (newest_file_info == NULL)) {
1003 1 : dlt_vlog(LOG_INFO, "%s: Wrong paratemters\n", __func__);
1004 1 : return -1;
1005 : }
1006 :
1007 : /* This is for ON_MSG/UNSET strategy */
1008 : /* Handle log file open for ON_MSG/UNSET strategy */
1009 : #ifdef DLT_LOGSTORAGE_USE_GZIP
1010 : if (config->log == NULL && config->gzlog == NULL) {
1011 : #else
1012 92 : if (config->log == NULL) {
1013 : #endif
1014 : /* Sync the wrap id and working file name before opening log file */
1015 6 : if (config->wrap_id < newest_file_info->wrap_id) {
1016 2 : config->wrap_id = newest_file_info->wrap_id;
1017 2 : if (config->working_file_name) {
1018 1 : free(config->working_file_name);
1019 1 : config->working_file_name = NULL;
1020 : }
1021 2 : config->working_file_name = strdup(newest_file_info->newest_file);
1022 : }
1023 :
1024 : /* open a new log file */
1025 6 : ret = dlt_logstorage_open_log_file(config, file_config, dev_path, log_msg_size, true, false);
1026 : } else { /* already open, check size and create a new file if needed */
1027 86 : ret = fstat(config->fd, &s);
1028 :
1029 86 : if (ret == 0) {
1030 : /* Check if adding new data do not exceed max file size
1031 : *
1032 : * This is inaccurate for gz compressed files but as long as log
1033 : * messages aren't gigantic it should be negligeble
1034 : *
1035 : * Also check if wrap id needs to be updated */
1036 86 : if ((s.st_size + log_msg_size > (int)config->file_size)
1037 79 : || (strcmp(config->working_file_name, newest_file_info->newest_file) != 0)
1038 79 : || (config->wrap_id < newest_file_info->wrap_id)) {
1039 : /* Sync only if on_msg */
1040 7 : if ((config->sync == DLT_LOGSTORAGE_SYNC_ON_MSG) || (config->sync == DLT_LOGSTORAGE_SYNC_UNSET)) {
1041 : #ifdef DLT_LOGSTORAGE_USE_GZIP
1042 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
1043 : if (fsync(config->fd) != 0) {
1044 : if (errno != ENOSYS) {
1045 : dlt_vlog(LOG_ERR, "%s: failed to sync gzip log file\n", __func__);
1046 : }
1047 : }
1048 : } else
1049 : #endif
1050 : {
1051 7 : if (fsync(fileno(config->log)) != 0) {
1052 0 : if (errno != ENOSYS) {
1053 0 : dlt_vlog(LOG_ERR, "%s: failed to sync log file\n", __func__);
1054 : }
1055 : }
1056 : }
1057 : }
1058 :
1059 0 : dlt_logstorage_close_file(config);
1060 :
1061 : /* Sync the wrap id and working file name before opening log file */
1062 7 : if (config->wrap_id <= newest_file_info->wrap_id) {
1063 7 : config->wrap_id = newest_file_info->wrap_id;
1064 7 : if (config->working_file_name) {
1065 7 : free(config->working_file_name);
1066 7 : config->working_file_name = NULL;
1067 : }
1068 7 : config->working_file_name = strdup(newest_file_info->newest_file);
1069 : }
1070 :
1071 7 : ret = dlt_logstorage_open_log_file(config, file_config, dev_path, log_msg_size, true, false);
1072 : } else { /*everything is prepared */
1073 : ret = 0;
1074 : }
1075 : } else {
1076 0 : dlt_vlog(LOG_ERR, "%s: stat() failed.\n", __func__);
1077 : ret = -1;
1078 : }
1079 : }
1080 :
1081 : return ret;
1082 : }
1083 :
1084 : /**
1085 : * dlt_logstorage_write_on_msg
1086 : *
1087 : * Write the log message.
1088 : *
1089 : * @param config DltLogStorageFilterConfig
1090 : * @param file_config DltLogStorageUserConfig
1091 : * @param dev_path Path to device
1092 : * @param data1 header
1093 : * @param size1 header size
1094 : * @param data2 storage header
1095 : * @param size2 storage header size
1096 : * @param data3 payload
1097 : * @param size3 payload size
1098 : * @return 0 on success, -1 on error
1099 : */
1100 89 : int dlt_logstorage_write_on_msg(
1101 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, unsigned char* data1,
1102 : int size1, unsigned char* data2, int size2, unsigned char* data3, int size3)
1103 : {
1104 : int ret;
1105 :
1106 89 : if ((config == NULL) || (data1 == NULL) || (data2 == NULL) || (data3 == NULL) || (file_config == NULL)
1107 88 : || (dev_path == NULL)) {
1108 : return -1;
1109 : }
1110 :
1111 88 : ret = dlt_logstorage_write_to_log(data1, 1, (size_t)size1, config);
1112 :
1113 88 : if (ret != size1)
1114 0 : dlt_log(LOG_WARNING, "Wrote less data than specified\n");
1115 :
1116 88 : ret = dlt_logstorage_write_to_log(data2, 1, (size_t)size2, config);
1117 88 : if (ret != size2)
1118 0 : dlt_log(LOG_WARNING, "Wrote less data than specified\n");
1119 :
1120 88 : ret = dlt_logstorage_write_to_log(data3, 1, (size_t)size3, config);
1121 88 : if (ret != size3)
1122 0 : dlt_log(LOG_WARNING, "Wrote less data than specified\n");
1123 :
1124 : #ifdef DLT_LOGSTORAGE_USE_GZIP
1125 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
1126 : gzerror(config->gzlog, &ret);
1127 : return ret;
1128 : } else {
1129 : return ferror(config->log);
1130 : }
1131 : #else
1132 88 : return ferror(config->log);
1133 : #endif
1134 : }
1135 :
1136 : /**
1137 : * dlt_logstorage_sync_on_msg
1138 : *
1139 : * sync data to disk.
1140 : *
1141 : * @param config DltLogStorageFilterConfig
1142 : * @param file_config User configurations for log file
1143 : * @param dev_path Storage device path
1144 : * @param status Strategy flag
1145 : * @return 0 on success, -1 on error
1146 : */
1147 102 : int dlt_logstorage_sync_on_msg(
1148 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, int status)
1149 : {
1150 : (void)file_config; /* satisfy compiler */
1151 : (void)dev_path;
1152 :
1153 102 : if (config == NULL)
1154 : return -1;
1155 :
1156 101 : if (status == DLT_LOGSTORAGE_SYNC_ON_MSG) { /* sync on every message */
1157 88 : if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON) {
1158 : #ifdef DLT_LOGSTORAGE_USE_GZIP
1159 : if (gzflush(config->gzlog, Z_SYNC_FLUSH) != 0)
1160 : dlt_vlog(LOG_ERR, "%s: failed to gzflush log file\n", __func__);
1161 : #endif
1162 : } else {
1163 88 : if (fflush(config->log) != 0)
1164 0 : dlt_vlog(LOG_ERR, "%s: failed to flush log file\n", __func__);
1165 : }
1166 : }
1167 :
1168 : return 0;
1169 : }
1170 :
1171 : /**
1172 : * dlt_logstorage_prepare_msg_cache
1173 : *
1174 : * Prepare the log file for a certain filer. If log file not open or log
1175 : * files max size reached, open a new file.
1176 : * Create a memory area to cache data.
1177 : *
1178 : * @param config DltLogStorageFilterConfig
1179 : * @param file_config User configurations for log file
1180 : * @param dev_path Storage device path
1181 : * @param log_msg_size Size of log message
1182 : * @param newest_file_info Info of newest files for corresponding filename
1183 : * @return 0 on success, -1 on error
1184 : */
1185 271 : int dlt_logstorage_prepare_msg_cache(
1186 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, int log_msg_size,
1187 : DltNewestFileName* newest_file_info)
1188 : {
1189 271 : if ((config == NULL) || (file_config == NULL) || (dev_path == NULL) || (newest_file_info == NULL))
1190 : return -1;
1191 :
1192 : /* check if newest file info is available
1193 : * + working file name is NULL => update directly to newest file
1194 : * + working file name is not NULL: check if
1195 : * ++ wrap_ids are different from each other or
1196 : * ++ newest file name <> working file name
1197 : */
1198 270 : if (newest_file_info->newest_file) {
1199 144 : if (config->working_file_name
1200 143 : && ((config->wrap_id != newest_file_info->wrap_id)
1201 143 : || (strcmp(newest_file_info->newest_file, config->working_file_name) != 0))) {
1202 0 : free(config->working_file_name);
1203 0 : config->working_file_name = NULL;
1204 : }
1205 144 : if (config->working_file_name == NULL) {
1206 1 : config->working_file_name = strdup(newest_file_info->newest_file);
1207 1 : config->wrap_id = newest_file_info->wrap_id;
1208 : }
1209 : }
1210 :
1211 : /* Combinations allowed: on Daemon_Exit with on Demand,File_Size with Daemon_Exit
1212 : * File_Size with on Demand, Specific_Size with Daemon_Exit,Specific_Size with on Demand
1213 : * Combination not allowed : File_Size with Specific_Size
1214 : */
1215 : /* check for combinations of specific_size and file_size strategy */
1216 270 : if ((DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0)
1217 70 : && ((DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE)) > 0)) {
1218 0 : dlt_log(LOG_WARNING, "wrong combination of sync strategies \n");
1219 0 : return -1;
1220 : }
1221 :
1222 : (void)log_msg_size; /* satisfy compiler */
1223 :
1224 : /* check specific size is smaller than file size */
1225 270 : if ((DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0)
1226 70 : && (config->specific_size > config->file_size)) {
1227 0 : dlt_log(
1228 : LOG_ERR,
1229 : "Cache size is larger than file size. "
1230 : "Cannot prepare log file for ON_SPECIFIC_SIZE sync\n");
1231 0 : return -1;
1232 : }
1233 :
1234 270 : if (config->cache == NULL) {
1235 : unsigned int cache_size = 0;
1236 :
1237 : /* check for sync_specific_size strategy */
1238 11 : if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0) {
1239 2 : cache_size = config->specific_size;
1240 : } else /* other cache strategies */
1241 : {
1242 9 : cache_size = config->file_size;
1243 : }
1244 :
1245 : /* check total logstorage cache size */
1246 11 : if ((g_logstorage_cache_size + cache_size + sizeof(DltLogStorageCacheFooter)) > g_logstorage_cache_max) {
1247 0 : dlt_vlog(
1248 : LOG_ERR, "%s: Max size of Logstorage Cache already used. (ApId=[%s] CtId=[%s]) \n", __func__,
1249 : config->apids, config->ctids);
1250 0 : return -1;
1251 : } else {
1252 11 : dlt_vlog(
1253 : LOG_DEBUG, "%s: Logstorage total: %d , requested cache size: %d, max: %d (ApId=[%s] CtId=[%s])\n",
1254 : __func__, g_logstorage_cache_size, cache_size, g_logstorage_cache_max, config->apids, config->ctids);
1255 : }
1256 :
1257 : /* create cache */
1258 11 : config->cache = calloc(1, cache_size + sizeof(DltLogStorageCacheFooter));
1259 :
1260 11 : if (config->cache == NULL) {
1261 0 : dlt_log(LOG_CRIT, "Cannot allocate memory for filter ring buffer\n");
1262 : } else {
1263 : /* update current used cache size */
1264 11 : g_logstorage_cache_size += (unsigned int)(cache_size + sizeof(DltLogStorageCacheFooter));
1265 : }
1266 : }
1267 :
1268 : return 0;
1269 : }
1270 :
1271 : /**
1272 : * dlt_logstorage_write_msg_cache
1273 : *
1274 : * Write the log message.
1275 : *
1276 : * @param config DltLogStorageFilterConfig
1277 : * @param file_config User configurations for log file
1278 : * @param dev_path Storage device path
1279 : * @param data1 header
1280 : * @param size1 header size
1281 : * @param data2 storage header
1282 : * @param size2 storage header size
1283 : * @param data3 payload
1284 : * @param size3 payload size
1285 : * @return 0 on success, -1 on error
1286 : */
1287 271 : int dlt_logstorage_write_msg_cache(
1288 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, unsigned char* data1,
1289 : int size1, unsigned char* data2, int size2, unsigned char* data3, int size3)
1290 : {
1291 : DltLogStorageCacheFooter* footer = NULL;
1292 : int msg_size;
1293 : int remain_cache_size;
1294 : uint8_t* curr_write_addr = NULL;
1295 : int ret = 0;
1296 : unsigned int cache_size;
1297 :
1298 271 : if ((config == NULL) || (data1 == NULL) || (size1 < 0) || (data2 == NULL) || (size2 < 0) || (data3 == NULL)
1299 270 : || (size3 < 0) || (config->cache == NULL) || (file_config == NULL) || (dev_path == NULL)) {
1300 : return -1;
1301 : }
1302 :
1303 270 : if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0) {
1304 70 : cache_size = config->specific_size;
1305 : } else {
1306 200 : cache_size = config->file_size;
1307 : }
1308 :
1309 270 : footer = (DltLogStorageCacheFooter*)((uint8_t*)config->cache + cache_size);
1310 270 : msg_size = size1 + size2 + size3;
1311 270 : remain_cache_size = (int)(cache_size - footer->offset);
1312 :
1313 270 : if (msg_size <= remain_cache_size) /* add at current position */
1314 : {
1315 235 : curr_write_addr = (uint8_t*)config->cache + footer->offset;
1316 235 : footer->offset += (unsigned int)msg_size;
1317 235 : if (footer->wrap_around_cnt < 1) {
1318 213 : footer->end_sync_offset = footer->offset;
1319 : }
1320 :
1321 : /* write data to cache */
1322 235 : memcpy(curr_write_addr, data1, (size_t)size1);
1323 235 : curr_write_addr += size1;
1324 235 : memcpy(curr_write_addr, data2, (size_t)size2);
1325 235 : curr_write_addr += size2;
1326 235 : memcpy(curr_write_addr, data3, (size_t)size3);
1327 : }
1328 :
1329 : /*
1330 : * In case the msg_size is equal to remaining cache size,
1331 : * the message is still written in cache.
1332 : * Then whole cache data is synchronized to file.
1333 : */
1334 270 : if (msg_size >= remain_cache_size) {
1335 : /*check for message size exceeds cache size for specific_size strategy */
1336 35 : if ((unsigned int)msg_size > cache_size) {
1337 0 : dlt_log(LOG_WARNING, "Message is larger than cache. Discard.\n");
1338 0 : return -1;
1339 : }
1340 :
1341 : /*sync to file for specific_size or file_size */
1342 35 : if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE) > 0) {
1343 10 : ret = config->dlt_logstorage_sync(config, file_config, dev_path, DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE);
1344 10 : if (ret != 0) {
1345 0 : dlt_log(LOG_ERR, "dlt_logstorage_sync: Unable to sync.\n");
1346 0 : return -1;
1347 : }
1348 25 : } else if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0) {
1349 22 : ret = config->dlt_logstorage_sync(config, file_config, dev_path, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE);
1350 22 : if (ret != 0) {
1351 0 : dlt_log(LOG_ERR, "dlt_logstorage_sync: Unable to sync.\n");
1352 0 : return -1;
1353 : }
1354 3 : } else if (
1355 3 : (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_DEMAND) > 0)
1356 3 : || (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT) > 0)) {
1357 3 : footer->wrap_around_cnt += 1;
1358 : }
1359 :
1360 35 : if (msg_size > remain_cache_size) {
1361 : /* start writing from beginning */
1362 35 : footer->end_sync_offset = footer->offset;
1363 35 : curr_write_addr = config->cache;
1364 35 : footer->offset = (unsigned int)msg_size;
1365 :
1366 : /* write data to cache */
1367 35 : memcpy(curr_write_addr, data1, (size_t)size1);
1368 35 : curr_write_addr += size1;
1369 35 : memcpy(curr_write_addr, data2, (size_t)size2);
1370 35 : curr_write_addr += size2;
1371 35 : memcpy(curr_write_addr, data3, (size_t)size3);
1372 : }
1373 : }
1374 :
1375 :
1376 : return 0;
1377 : }
1378 :
1379 : /**
1380 : * dlt_logstorage_sync_msg_cache
1381 : *
1382 : * sync data to disk.
1383 : *
1384 : * @param config DltLogStorageFilterConfig
1385 : * @param file_config User configurations for log file
1386 : * @param dev_path Storage device path
1387 : * @param status Strategy flag
1388 : * @return 0 on success, -1 on error
1389 : */
1390 321 : int dlt_logstorage_sync_msg_cache(
1391 : DltLogStorageFilterConfig* config, DltLogStorageUserConfig* file_config, char* dev_path, int status)
1392 : {
1393 : unsigned int cache_size;
1394 :
1395 : DltLogStorageCacheFooter* footer = NULL;
1396 :
1397 321 : if ((config == NULL) || (file_config == NULL) || (dev_path == NULL)) {
1398 : return -1;
1399 : }
1400 :
1401 : /* sync only, if given strategy is set */
1402 320 : if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, status) > 0) {
1403 39 : if (config->cache == NULL) {
1404 0 : dlt_log(LOG_ERR, "Cannot copy cache to file. Cache is NULL\n");
1405 0 : return -1;
1406 : }
1407 :
1408 39 : if (DLT_OFFLINE_LOGSTORAGE_IS_STRATEGY_SET(config->sync, DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) > 0) {
1409 22 : cache_size = config->specific_size;
1410 : } else {
1411 17 : cache_size = config->file_size;
1412 : }
1413 :
1414 39 : footer = (DltLogStorageCacheFooter*)((uint8_t*)config->cache + cache_size);
1415 :
1416 : /* sync cache data to file */
1417 39 : if (footer->wrap_around_cnt < 1) {
1418 : /* Sync whole cache */
1419 37 : dlt_logstorage_sync_to_file(
1420 : config, file_config, dev_path, footer, footer->last_sync_offset, footer->offset);
1421 :
1422 2 : } else if ((footer->wrap_around_cnt == 1) && (footer->offset < footer->last_sync_offset)) {
1423 : /* sync (1) footer->last_sync_offset to footer->end_sync_offset,
1424 : * and (2) footer->last_sync_offset (= 0) to footer->offset */
1425 0 : dlt_logstorage_sync_to_file(
1426 : config, file_config, dev_path, footer, footer->last_sync_offset, footer->end_sync_offset);
1427 0 : footer->last_sync_offset = 0;
1428 0 : dlt_logstorage_sync_to_file(
1429 : config, file_config, dev_path, footer, footer->last_sync_offset, footer->offset);
1430 : } else {
1431 : /* sync (1) footer->offset + index to footer->end_sync_offset,
1432 : * and (2) footer->last_sync_offset (= 0) to footer->offset */
1433 2 : dlt_logstorage_sync_to_file(config, file_config, dev_path, footer, footer->offset, footer->end_sync_offset);
1434 2 : footer->last_sync_offset = 0;
1435 2 : dlt_logstorage_sync_to_file(
1436 : config, file_config, dev_path, footer, footer->last_sync_offset, footer->offset);
1437 : }
1438 :
1439 : /* Initialize cache if needed */
1440 39 : if ((status == DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE) || (status == DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE)) {
1441 : /* clean ring buffer and reset footer information */
1442 32 : memset(config->cache, 0, cache_size + sizeof(DltLogStorageCacheFooter));
1443 : }
1444 :
1445 32 : if (status == DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE) {
1446 : /* Close log file */
1447 0 : dlt_logstorage_close_file(config);
1448 10 : config->current_write_file_offset = 0;
1449 : }
1450 : }
1451 : return 0;
1452 : }
|