LCOV - code coverage report
Current view: top level - offlinelogstorage - dlt_offline_logstorage_behavior.c (source / functions) Coverage Total Hit
Test: dlt_final_coverage.info Lines: 83.3 % 490 408
Test Date: 2025-03-25 20:53:42 Functions: 100.0 % 20 20

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

Generated by: LCOV version 2.0-1