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

Generated by: LCOV version 1.14