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