LCOV - code coverage report
Current view: top level - offlinelogstorage - dlt_offline_logstorage_behavior.c (source / functions) Hit Total Coverage
Test: dlt_final_coverage.info Lines: 405 487 83.2 %
Date: 2024-11-20 10:17:27 Functions: 20 20 100.0 %

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

Generated by: LCOV version 1.14