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

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

Generated by: LCOV version 2.0-1