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