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