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