summaryrefslogtreecommitdiff
path: root/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
diff options
context:
space:
mode:
authorChristoph Lipka <clipka@jp.adit-jv.com>2015-10-26 14:57:00 +0900
committerLutz Helwing <lutz_helwing@mentor.com>2015-11-24 09:48:42 +0100
commitd73717a4f6b243d40388bb1d3bb9db7421d7b9b0 (patch)
tree091f25b5f38257f611733e4757b762a036b12d83 /src/offlinelogstorage/dlt_offline_logstorage_behavior.c
parent5574d46a4083d783a915688e0e05593b9558497b (diff)
downloadDLT-daemon-d73717a4f6b243d40388bb1d3bb9db7421d7b9b0.tar.gz
DltLogstorage: Logstorage Cache
When using DltLogstorage on internal storage device, it is needed to reduce writing to internal storage device as much as possible. This patch introduces sync strategies to Logstorage to provide that functionality. The ON_MSG strategy is the default sync strategy that flushes every written log message to the storage device (fflush). The ON_DAEMON_EXIT strategy only flushes data to disk when the daemon exits. The strategy can be defined per filter in the dlt_logstorage.conf configuration file by adding SyncBehavior=<Strategy> to a configuration. Signed-off-by: Christoph Lipka <clipka@jp.adit-jv.com>
Diffstat (limited to 'src/offlinelogstorage/dlt_offline_logstorage_behavior.c')
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage_behavior.c868
1 files changed, 868 insertions, 0 deletions
diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
new file mode 100644
index 0000000..77823ee
--- /dev/null
+++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
@@ -0,0 +1,868 @@
+/**
+ * @licence app begin@
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * DLT offline log storage functionality source file.
+ *
+ * \copyright
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with
+ * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *
+ * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015
+ * \author Syed Hameed <shameed@jp.adit-jv.com> ADIT 2015
+ *
+ * \file: dlt_offline_logstorage_behavior.c
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+#include <syslog.h>
+#include <limits.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "dlt_offline_logstorage.h"
+#include "dlt_offline_logstorage_behavior.h"
+
+/**
+ * dlt_logstorage_log_file_name
+ *
+ * Create log file name in the form configured by the user
+ * <filename><delimiter><index><delimiter><timestamp>.dlt
+ *
+ * filename: given in configuration file
+ * delimiter: Punctuation characters (configured in dlt.conf)
+ * timestamp: yyyy-mm-dd-hh-mm-ss (enabled/disabled in dlt.conf)
+ * index: Index len depends on wrap around value in dlt.conf
+ * ex: wrap around = 99, index will 01..99
+ *
+ * @param log_file_name contains complete logfile name
+ * @param file_config User configurations for log file
+ * @param name file name given in configuration file
+ * @param idx continous index of log files
+ * @ return None
+ */
+void dlt_logstorage_log_file_name(char *log_file_name,
+ DltLogStorageUserConfig *file_config,
+ char *name,
+ int idx)
+{
+ if (log_file_name == NULL || file_config == NULL)
+ {
+ return;
+ }
+
+ char file_index[10] = {'\0'};
+
+ // create log file name
+ memset(log_file_name, 0, DLT_MOUNT_PATH_MAX * sizeof(char));
+ strcat(log_file_name, name);
+ strncat(log_file_name, &file_config->logfile_delimiter, 1);
+
+ snprintf(file_index, 10, "%d",idx);
+ if (file_config->logfile_maxcounter != UINT_MAX)
+ {
+ /* Setup 0's to be appended in file index until max index len*/
+ unsigned int digit_idx = 0;
+ unsigned int i = 0;
+ snprintf(file_index, 10, "%d",idx);
+ digit_idx = strlen(file_index);
+ for(i=0; i<(file_config->logfile_counteridxlen - digit_idx); i++)
+ {
+ strcat(log_file_name, "0");
+ }
+ }
+
+ strcat(log_file_name, file_index);
+
+ /* Add time stamp if user has configured */
+ if (file_config->logfile_timestamp)
+ {
+ char stamp[DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1] = {0};
+ time_t t = time(NULL);
+ struct tm *tm_info = localtime(&t);
+ sprintf(stamp,
+ "%c%04d%02d%02d-%02d%02d%02d",
+ file_config->logfile_delimiter,
+ 1900 + tm_info->tm_year,
+ 1 + tm_info->tm_mon,
+ tm_info->tm_mday,
+ tm_info->tm_hour,
+ tm_info->tm_min,
+ tm_info->tm_sec);
+ strcat(log_file_name, stamp);
+ }
+
+ strcat(log_file_name, ".dlt");
+}
+
+/**
+ * dlt_logstorage_sort_file_name
+ *
+ * Sort the filenames with index based ascending order (bubble sort)
+ *
+ * @param head Log filename list
+ * @ return None
+ */
+void dlt_logstorage_sort_file_name(DltLogStorageFileList **head)
+{
+ int done = 0;
+
+ if (head == NULL || *head == NULL || (*head)->next == NULL)
+ {
+ return;
+ }
+
+ while (!done)
+ {
+ /* "source" of the pointer to the current node in the list struct */
+ DltLogStorageFileList **pv = head;
+ DltLogStorageFileList *nd = *head; /* local iterator pointer */
+ DltLogStorageFileList *nx = (*head)->next; /* local next pointer */
+
+ done = 1;
+
+ while (nx)
+ {
+ if (nd->idx > nx->idx)
+ {
+ nd->next = nx->next;
+ nx->next = nd;
+ *pv = nx;
+
+ done = 0;
+ }
+ pv = &nd->next;
+ nd = nx;
+ nx = nx->next;
+ }
+ }
+}
+
+/**
+ * dlt_logstorage_rearrange_file_name
+ *
+ * Rearrange the filenames in the order of latest and oldest
+ *
+ * @param head Log filename list
+ * @ return None
+ */
+void dlt_logstorage_rearrange_file_name(DltLogStorageFileList **head)
+{
+ DltLogStorageFileList *n_prev = NULL;
+ DltLogStorageFileList *tail = NULL;
+ DltLogStorageFileList *wrap_pre = NULL;
+ DltLogStorageFileList *wrap_post = NULL;
+ DltLogStorageFileList *n = NULL;
+
+ if (head == NULL || *head == NULL || (*head)->next == NULL)
+ {
+ return;
+ }
+
+ for (n = *head; n != NULL; n = n->next)
+ {
+ if (n && n_prev)
+ {
+ if ((n->idx - n_prev->idx) != 1)
+ {
+ wrap_post = n;
+ wrap_pre = n_prev;
+ }
+ }
+ n_prev = n;
+ }
+ tail = n_prev;
+
+ if (wrap_post && wrap_pre)
+ {
+ wrap_pre->next = NULL;
+ tail->next = *head;
+ *head = wrap_post;
+ }
+}
+
+/**
+ * dlt_logstorage_get_idx_of_log_file
+ *
+ * Extract index of log file name passed as input argument
+ *
+ * @param file file name to extract the index from
+ * @param file_config User configurations for log file
+ * @return index on success, -1 if no index is found
+ */
+unsigned int dlt_logstorage_get_idx_of_log_file(
+ DltLogStorageUserConfig *file_config,
+ char *file)
+{
+ unsigned int idx = -1;
+ char *endptr;
+ char *filename;
+ unsigned int filename_len = 0 ;
+ unsigned int fileindex_len = 0;
+
+ if (file_config == NULL || file == NULL)
+ {
+ return -1;
+ }
+
+ /* Calculate actual file name length */
+ filename=strchr(file, file_config->logfile_delimiter);
+ filename_len = strlen(file) - strlen(filename);
+
+ /* index is retrived from file name */
+ if(file_config->logfile_timestamp)
+ {
+ fileindex_len = strlen(file) -
+ (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
+ DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN +
+ filename_len + 1);
+
+ idx = (int) strtol(&file[strlen(file) -
+ (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
+ fileindex_len +
+ DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN)],
+ &endptr,
+ 10);
+ }
+ else
+ {
+ fileindex_len = strlen(file) -
+ (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
+ filename_len + 1);
+
+ idx = (int) strtol(&file[strlen(file)-
+ (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN
+ +fileindex_len)], &endptr, 10);
+ }
+
+ if (endptr == file || idx == 0)
+ {
+ dlt_log(LOG_ERR,
+ "Unable to calculate index from log file name. Reset to 001.\n");
+ }
+
+ return idx;
+}
+
+/**
+ * dlt_logstorage_storage_dir_info
+ *
+ * Read file names of storage directory.
+ * Update the file list, arrange it in order of latest and oldest
+ *
+ * @param file_config User configurations for log file
+ * @param path Path to storage directory
+ * @param config DltLogStorageConfigData
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config,
+ char *path,
+ DltLogStorageConfigData *config)
+{
+ int i = 0;
+ int cnt = 0;
+ int ret = 0;
+ struct dirent **files = {0};
+ unsigned int current_idx = 0;
+
+ if (config == NULL ||
+ file_config == NULL ||
+ path == NULL ||
+ config->file_name == NULL)
+ {
+ return -1;
+ }
+
+ cnt = scandir(path, &files, 0, alphasort);
+ if (cnt < 0)
+ {
+ dlt_log(LOG_ERR,
+ "dlt_logstorage_storage_dir_info: Failed to scan directory\n");
+ return -1;
+ }
+
+ for (i = 0; i < cnt; i++)
+ {
+ int len = 0;
+ len = strlen(config->file_name);
+ if ((strncmp(files[i]->d_name,
+ config->file_name,
+ len) == 0) &&
+ (files[i]->d_name[len] == file_config->logfile_delimiter))
+ {
+ DltLogStorageFileList **tmp = NULL;
+ current_idx = dlt_logstorage_get_idx_of_log_file(file_config,
+ files[i]->d_name);
+
+ if(config->records == NULL)
+ {
+ config->records = malloc(sizeof(DltLogStorageFileList));
+ if (config->records == NULL)
+ {
+ ret = -1;
+ dlt_log(LOG_ERR,
+ "Memory allocation failed\n");
+ break;
+ }
+ tmp = &config->records;
+ }
+ else
+ {
+ tmp = &config->records;
+ while(*(tmp) != NULL)
+ {
+ tmp = &(*tmp)->next;
+ }
+ *tmp = malloc(sizeof(DltLogStorageFileList));
+ if (*tmp == NULL)
+ {
+ ret = -1;
+ dlt_log(LOG_ERR,
+ "Memory allocation failed\n");
+ break;
+ }
+ }
+ (*tmp)->name = strdup(files[i]->d_name);
+ (*tmp)->idx = current_idx;
+ (*tmp)->next = NULL;
+ }
+ }
+
+ if (ret == 0)
+ {
+ dlt_logstorage_sort_file_name(&config->records);
+ dlt_logstorage_rearrange_file_name(&config->records);
+ }
+
+ /* free scandir result */
+ for (i = 0; i < cnt; i++)
+ {
+ free(files[i]);
+ }
+ free(files);
+
+ return ret;
+}
+
+/**
+ * dlt_logstorage_open_log_file
+ *
+ * Open a log file. Check storage directory for already created files and open
+ * the oldest if there is enough space to store at least msg_size.
+ * Otherwise create a new file, but take configured max number of files into
+ * account and remove the oldest file if needed.
+ *
+ * @param config DltLogStorageConfigData
+ * @param file_config User configurations for log file
+ * @param dev_path Storage device path
+ * @param msg_size Size of incoming message
+ * @return 0 on succes, -1 on error
+ */
+int dlt_logstorage_open_log_file(DltLogStorageConfigData *config,
+ DltLogStorageUserConfig *file_config,
+ char *dev_path,
+ int msg_size)
+{
+ int ret = 0;
+ char absolute_file_path[DLT_MOUNT_PATH_MAX + 1] = {'\0'};
+ char storage_path[DLT_OFFLINE_LOGSTORAGE_CONFIG_DIR_PATH_LEN] = {'\0'};
+ unsigned int num_log_files = 0;
+ struct stat s;
+ DltLogStorageFileList **tmp = NULL;
+ DltLogStorageFileList **newest = NULL;
+ char file_name[DLT_MOUNT_PATH_MAX + 1] = {'\0'};
+
+ if (config == NULL)
+ {
+ return -1;
+ }
+
+ sprintf(storage_path, "%s/", dev_path);
+
+ /* check if there are already files stored */
+ if (config->records == NULL)
+ {
+ if (dlt_logstorage_storage_dir_info(file_config, storage_path, config)
+ != 0)
+ return -1;
+ }
+
+ /* obtain locations of newest, current file names, file count */
+ tmp = &config->records;
+ while(*(tmp) != NULL)
+ {
+ num_log_files += 1;
+ if((*tmp)->next == NULL)
+ newest = tmp;
+
+ tmp = &(*tmp)->next;
+ }
+
+ /* need new file*/
+ if (num_log_files == 0)
+ {
+ dlt_logstorage_log_file_name(file_name,
+ file_config,
+ config->file_name,
+ 1);
+
+ /* concatenate path and file and open absolute path */
+ strcat(absolute_file_path, storage_path);
+ strcat(absolute_file_path, file_name);
+ config->log = fopen(absolute_file_path, "a+");
+
+ /* Add file to file list */
+ *tmp = malloc(sizeof(DltLogStorageFileList));
+ if (*tmp == NULL)
+ {
+ dlt_log(LOG_ERR,
+ "Memory allocation for file name failed\n");
+ return -1;
+ }
+ (*tmp)->name = strdup(file_name);
+ (*tmp)->idx = 1;
+ (*tmp)->next = NULL;
+ }
+ else /* newest file available*/
+ {
+ strcat(absolute_file_path, storage_path);
+ strcat(absolute_file_path, (*newest)->name);
+
+ ret = stat(absolute_file_path, &s);
+
+ /* if size is enough, open it */
+ if (ret == 0 && s.st_size + msg_size < (int)config->file_size)
+ {
+ config->log = fopen(absolute_file_path, "a+");
+ }
+ else /* no space in file or file stats cannot be read */
+ {
+ unsigned int idx = 0;
+
+ /* get index of newest log file */
+ idx = dlt_logstorage_get_idx_of_log_file(file_config,
+ (*newest)->name);
+ idx += 1;
+
+ /* wrap around if max index is reached or an error occurred
+ * while calculating index from file name */
+ if (idx > file_config->logfile_maxcounter || idx == 0)
+ {
+ idx = 1;
+ }
+
+ dlt_logstorage_log_file_name(file_name,
+ file_config,
+ config->file_name,
+ idx);
+
+ /* concatenate path and file and open absolute path */
+ memset(absolute_file_path,
+ 0,
+ sizeof(absolute_file_path)/sizeof(char));
+ strcat(absolute_file_path, storage_path);
+ strcat(absolute_file_path, file_name);
+ config->log = fopen(absolute_file_path, "a+");
+
+ /* Add file to file list */
+ *tmp = malloc(sizeof(DltLogStorageFileList));
+ if (*tmp == NULL)
+ {
+ dlt_log(LOG_ERR,
+ "Memory allocation for file name failed\n");
+ return -1;
+ }
+
+ (*tmp)->name = strdup(file_name);
+ (*tmp)->idx = idx;
+ (*tmp)->next = NULL;
+
+ num_log_files += 1;
+
+ /* check if number of log files exceeds configured max value */
+ if (num_log_files > config->num_files)
+ {
+ /* delete oldest */
+ DltLogStorageFileList **head = &config->records;
+ DltLogStorageFileList *n = *head;
+ memset(absolute_file_path,
+ 0,
+ sizeof(absolute_file_path)/sizeof(char));
+ strcat(absolute_file_path, storage_path);
+ strcat(absolute_file_path, (*head)->name);
+ remove(absolute_file_path);
+ free((*head)->name);
+ *head = n->next;
+ n->next = NULL;
+ free(n);
+ }
+ }
+ }
+
+ if (config->log == NULL)
+ {
+ dlt_log(LOG_ERR,
+ "dlt_logstorage_create_log_file: Unable to open log file.\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * dlt_logstorage_prepare_on_msg
+ *
+ * Prepare the log file for a certain filer. If log file not open or log
+ * files max size reached, open a new file.
+ *
+ * @param config DltLogStorageConfigData
+ * @param file_config User configurations for log file
+ * @param dev_path Storage device path
+ * @param log_msg_size Size of log message
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_prepare_on_msg(DltLogStorageConfigData *config,
+ DltLogStorageUserConfig *file_config,
+ char *dev_path,
+ int log_msg_size)
+{
+ int ret = 0;
+ struct stat s;
+
+ if (config == NULL || file_config == NULL || dev_path == NULL)
+ {
+ return -1;
+ }
+
+ if (config->log == NULL) /* open a new log file */
+ {
+ ret = dlt_logstorage_open_log_file(config,
+ file_config,
+ dev_path,
+ log_msg_size);
+ }
+ else /* already open, check size and create a new file if needed */
+ {
+ ret = fstat(fileno(config->log), &s);
+ if (ret == 0) {
+ /* check if adding new data do not exceed max file size */
+ if (s.st_size + log_msg_size >= (int)config->file_size)
+ {
+ fclose(config->log);
+ config->log = NULL;
+ ret = dlt_logstorage_open_log_file(config,
+ file_config,
+ dev_path,
+ log_msg_size);
+ }
+ else /*everything is prepared */
+ {
+ ret = 0;
+ }
+ }
+ else
+ {
+ dlt_log(LOG_ERR,
+ "dlt_logstorage_prepare_log_file: stat() failed.\n");
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+/**
+ * dlt_logstorage_write_on_msg
+ *
+ * Write the log message.
+ *
+ * @param config DltLogStorageConfigData
+ * @param data1 header
+ * @param size1 header size
+ * @param data2 storage header
+ * @param size2 storage header size
+ * @param data3 payload
+ * @param size3 payload size
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_write_on_msg(DltLogStorageConfigData *config,
+ unsigned char *data1,
+ int size1,
+ unsigned char *data2,
+ int size2,
+ unsigned char *data3,
+ int size3)
+{
+ int ret;
+
+ if (config == NULL || data1 == NULL || data2 == NULL || data3 == NULL)
+ {
+ return -1;
+ }
+
+ ret = fwrite(data1, 1, size1, config->log);
+ if (ret != size1)
+ {
+ dlt_log(LOG_WARNING, "Wrote less data than specified\n");
+ }
+ ret = fwrite(data2, 1, size2, config->log);
+ if (ret != size2)
+ {
+ dlt_log(LOG_WARNING, "Wrote less data than specified\n");
+ }
+ ret = fwrite(data3, 1, size3, config->log);
+ if (ret != size3)
+ {
+ dlt_log(LOG_WARNING, "Wrote less data than specified\n");
+ }
+
+ return ferror(config->log);
+}
+
+/**
+ * dlt_logstorage_sync_on_msg
+ *
+ * sync data to disk.
+ *
+ * @param config DltLogStorageConfigData
+ * @param status Strategy flag
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_sync_on_msg(DltLogStorageConfigData *config, int status)
+{
+ int ret;
+
+ if (config == NULL)
+ {
+ return -1;
+ }
+
+ if (status == DLT_LOGSTORAGE_SYNC_ON_MSG) /* sync on every message */
+ {
+ ret = fflush(config->log);
+
+ if (ret != 0)
+ {
+ dlt_log(LOG_ERR, "fflush failed\n");
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dlt_logstorage_prepare_on_daemon_exit
+ *
+ * Prepare the log file for a certain filer. If log file not open or log
+ * files max size reached, open a new file.
+ * Create a memory area to cache data.
+ *
+ * @param config DltLogStorageConfigData
+ * @param file_config User configurations for log file
+ * @param dev_path Storage device path
+ * @param log_msg_size Size of log message
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_prepare_on_daemon_exit(DltLogStorageConfigData *config,
+ DltLogStorageUserConfig *file_config,
+ char *dev_path,
+ int log_msg_size)
+{
+ if (config == NULL || file_config == NULL || dev_path == NULL)
+ {
+ return -1;
+ }
+
+ log_msg_size = log_msg_size; /* satisfy compiler */
+
+ /* open log file */
+ if (config->cache == NULL)
+ {
+ /* get always a new file */
+ if (dlt_logstorage_prepare_on_msg(config,
+ file_config,
+ dev_path,
+ config->file_size) != 0)
+ {
+ dlt_log(LOG_ERR,
+ "Cannot prepare log file for ON_DAEMON_EXIT sync\n");
+ return -1;
+ }
+
+ /* check total logstorage cache size */
+ if ((g_logstorage_cache_size +
+ config->file_size +
+ sizeof(DltLogStorageCacheFooter)) >
+ g_logstorage_cache_max)
+ {
+ dlt_log(LOG_ERR, "Max size of Logstorage Cache already used.");
+ return -1;
+ }
+
+ config->cache = calloc(1,
+ config->file_size +
+ sizeof(DltLogStorageCacheFooter));
+
+ /* update current used cache size */
+ g_logstorage_cache_size = config->file_size +
+ sizeof(DltLogStorageCacheFooter);
+
+ if (config->cache == NULL)
+ {
+ dlt_log(LOG_CRIT,
+ "Cannot allocate memory for filter ring buffer\n");
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dlt_logstorage_write_on_daemon_exit
+ *
+ * Write the log message.
+ *
+ * @param config DltLogStorageConfigData
+ * @param data1 header
+ * @param size1 header size
+ * @param data2 storage header
+ * @param size2 storage header size
+ * @param data3 payload
+ * @param size3 payload size
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_write_on_daemon_exit(DltLogStorageConfigData *config,
+ unsigned char *data1,
+ int size1,
+ unsigned char *data2,
+ int size2,
+ unsigned char *data3,
+ int size3)
+{
+ DltLogStorageCacheFooter *footer = NULL;
+ int msg_size;
+ int remain_cache_size;
+ void *curr_write_addr = NULL;
+
+ if (config == NULL || data1 == NULL || size1 < 0 || data2 == NULL ||
+ size2 < 0 || data3 == NULL || size3 < 0 || config->cache == NULL)
+ {
+ return -1;
+ }
+
+ footer = (DltLogStorageCacheFooter *)(config->cache + config->file_size);
+ if (footer == NULL)
+ {
+ dlt_log(LOG_ERR, "Cannot retrieve cache footer. Address is NULL\n");
+ return -1;
+ }
+
+ msg_size = size1 + size2 + size3;
+ remain_cache_size = config->file_size - footer->offset;
+
+ if (msg_size < remain_cache_size) /* add at current position */
+ {
+ curr_write_addr = (void *)(config->cache + footer->offset);
+ footer->offset += msg_size;
+ }
+ else if (msg_size > remain_cache_size)
+ {
+ if ((unsigned int) msg_size > config->file_size)
+ {
+ dlt_log(LOG_WARNING, "Message is larger than cache. Discard.\n");
+ return -1;
+ }
+
+ /* start writing from beginning */
+ curr_write_addr = config->cache;
+ footer->offset = msg_size;
+ footer->wrap_around_cnt += 1;
+ }
+ else /* message just fits into cache */
+ {
+ curr_write_addr = (void *)(config->cache + footer->offset);
+ footer->offset = 0;
+ footer->wrap_around_cnt += 1;
+ }
+
+ /* write data to cache */
+ memcpy(curr_write_addr, data1, size1);
+ curr_write_addr += size1;
+ memcpy(curr_write_addr, data2, size2);
+ curr_write_addr += size2;
+ memcpy(curr_write_addr, data3, size3);
+
+ return 0;
+}
+
+/**
+ * dlt_logstorage_sync_on_daemon_exit
+ *
+ * sync data to disk.
+ *
+ * @param config DltLogStorageConfigData
+ * @param status Strategy flag
+ * @return 0 on success, -1 on error
+ */
+int dlt_logstorage_sync_on_daemon_exit(DltLogStorageConfigData *config,
+ int status)
+{
+ int ret = 0;
+ DltLogStorageCacheFooter *footer = NULL;
+
+ if (config == NULL)
+ {
+ return -1;
+ }
+
+ if (status == config->sync) /* only sync on exit */
+ {
+ if (config->log == NULL || config->cache == NULL)
+ {
+ dlt_log(LOG_ERR,
+ "Cannot copy cache to file. One of both is NULL\n");
+ return -1;
+ }
+
+ /* TODO: write only what is needed */
+ /* write ring buffer into file */
+ footer = (DltLogStorageCacheFooter *)(config->cache +
+ config->file_size);
+
+ if (footer == NULL)
+ {
+ dlt_log(LOG_ERR, "Cannot retrieve cache information\n");
+ return -1;
+ }
+
+ /* TODO: check if really the whole cache need to be written */
+ /* write cache to file */
+ ret = fwrite(config->cache, config->file_size, 1, config->log);
+
+ if (ret <= 0)
+ {
+ if (ferror(config->log) != 0)
+ {
+ dlt_log(LOG_CRIT, "Failed to write cache into log file\n");
+ }
+ }
+ else
+ {
+ /* force sync */
+ if (fsync(fileno(config->log)) != 0)
+ {
+ dlt_log(LOG_ERR, "Failed to sync log file\n");
+ }
+ }
+ }
+
+ return ret;
+}