LCOV - code coverage report
Current view: top level - offlinelogstorage - dlt_offline_logstorage_behavior.c (source / functions) Hit Total Coverage
Test: dlt_final_coverage.info Lines: 404 484 83.5 %
Date: 2024-10-22 04:07:23 Functions: 20 20 100.0 %

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

Generated by: LCOV version 1.14