diff options
-rw-r--r-- | src/daemon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/daemon/dlt-daemon.c | 29 | ||||
-rw-r--r-- | src/daemon/dlt-daemon.h | 1 | ||||
-rw-r--r-- | src/daemon/dlt.conf | 3 | ||||
-rw-r--r-- | src/daemon/dlt_daemon_offline_logstorage.c | 32 | ||||
-rw-r--r-- | src/daemon/dlt_daemon_offline_logstorage.h | 19 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage.c | 630 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage.h | 57 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage_behavior.c | 868 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage_behavior.h | 91 |
10 files changed, 1224 insertions, 508 deletions
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index f665a4d..128dbe8 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -20,7 +20,7 @@ if(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD) message( STATUS "Added ${systemd_SRCS} to dlt-daemon") endif(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD) -set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_connection.c dlt_daemon_event_handler.c dlt_daemon_socket.c dlt_daemon_unix_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_config_file_parser.c) +set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_connection.c dlt_daemon_event_handler.c dlt_daemon_socket.c dlt_daemon_unix_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_config_file_parser.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage_behavior.c) add_executable(dlt-daemon ${dlt_daemon_SRCS} ${systemd_SRCS}) target_link_libraries(dlt-daemon rt ${CMAKE_THREAD_LIBS_INIT}) diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c index 61aca56..02e42ec 100644 --- a/src/daemon/dlt-daemon.c +++ b/src/daemon/dlt-daemon.c @@ -84,6 +84,8 @@ static int dlt_daemon_log_internal(DltDaemon *daemon, DltDaemonLocal *daemon_loc static uint32_t watchdog_trigger_interval; // watchdog trigger interval in [s] #endif +/* used in main event loop and signal handler */ +int g_exit = 0; /** * Print usage information of tool. @@ -238,6 +240,9 @@ int option_file_parser(DltDaemonLocal *daemon_local) daemon_local->flags.offlineLogstorageDelimiter = '_'; daemon_local->flags.offlineLogstorageMaxCounter = UINT_MAX; daemon_local->flags.offlineLogstorageMaxCounterIdx = 0; + daemon_local->flags.offlineLogstorageCacheSize = 30000; /* 30MB */ + dlt_daemon_logstorage_set_logstorage_cache_size( + daemon_local->flags.offlineLogstorageCacheSize); strncpy(daemon_local->flags.ctrlSockPath, DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH, sizeof(daemon_local->flags.ctrlSockPath) - 1); @@ -459,6 +464,13 @@ int option_file_parser(DltDaemonLocal *daemon_local) daemon_local->flags.offlineLogstorageMaxCounter = atoi(value); daemon_local->flags.offlineLogstorageMaxCounterIdx = strlen(value); } + else if(strcmp(token, "OfflineLogstorageCacheSize") == 0) + { + daemon_local->flags.offlineLogstorageCacheSize = + (unsigned int)atoi(value); + dlt_daemon_logstorage_set_logstorage_cache_size( + daemon_local->flags.offlineLogstorageCacheSize); + } else if(strcmp(token,"ControlSocketPath") == 0) { memset( @@ -499,7 +511,7 @@ int main(int argc, char* argv[]) char version[DLT_DAEMON_TEXTBUFSIZE]; DltDaemonLocal daemon_local; DltDaemon daemon; - int back; + int back = 0; /* Command line option handling */ if ((back = option_handling(&daemon_local,argc,argv))<0) @@ -637,7 +649,7 @@ int main(int argc, char* argv[]) dlt_daemon_log_internal(&daemon, &daemon_local, "Daemon launched. Starting to output traces...", daemon_local.flags.vflag); /* Even handling loop. */ - while (back >= 0) + while ((back >= 0) && (g_exit >= 0)) { back = dlt_daemon_handle_event(&daemon_local.pEvent, &daemon, @@ -647,7 +659,13 @@ int main(int argc, char* argv[]) dlt_daemon_log_internal(&daemon, &daemon_local, "Exiting Daemon...", daemon_local.flags.vflag); - dlt_daemon_local_cleanup(&daemon, &daemon_local, daemon_local.flags.vflag); + /* disconnect all logstorage devices */ + dlt_daemon_logstorage_cleanup(&daemon, + &daemon_local, + daemon_local.flags.vflag); + + +// dlt_daemon_local_cleanup(&daemon, &daemon_local, daemon_local.flags.vflag); dlt_log(LOG_NOTICE, "Leaving DLT daemon\n"); @@ -1167,9 +1185,8 @@ void dlt_daemon_signal_handler(int sig) tmp[PATH_MAX] = 0; unlink(tmp); - - /* Terminate program */ - exit(0); + /* stop event loop */ + g_exit = -1; break; } default: diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h index 503a98f..02a55b3 100644 --- a/src/daemon/dlt-daemon.h +++ b/src/daemon/dlt-daemon.h @@ -118,6 +118,7 @@ typedef struct char offlineLogstorageDelimiter; /**< (char) Append delimeter character in offline logstorage filename */ unsigned int offlineLogstorageMaxCounter; /**< (int) Maximum offline logstorage file counter index until wraparound */ unsigned int offlineLogstorageMaxCounterIdx; /**< (int) String len of offlineLogstorageMaxCounter*/ + unsigned int offlineLogstorageCacheSize; /**< Max cache size offline logstorage cache */ char userPipesDir[NAME_MAX + 1]; /**< (String: Directory) directory where dltpipes reside (Default: /tmp/dltpipes) */ char daemonFifoName[NAME_MAX + 1]; /**< (String: Filename) name of local fifo (Default: /tmp/dlt) */ unsigned int port; /**< port number */ diff --git a/src/daemon/dlt.conf b/src/daemon/dlt.conf index 72377e5..5deec60 100644 --- a/src/daemon/dlt.conf +++ b/src/daemon/dlt.conf @@ -145,3 +145,6 @@ ControlSocketPath = /tmp/dlt-ctrl.sock # Wrap around value for log file count in file name (Default: UINT_MAX) # OfflineLogstorageMaxCounter = 999 + +# Maximal used memory for Logstorage Cache in KB (Default: 30000 KB) +# OfflineLogstorageCacheSize = 30000
\ No newline at end of file diff --git a/src/daemon/dlt_daemon_offline_logstorage.c b/src/daemon/dlt_daemon_offline_logstorage.c index bc8817c..66f9ec8 100644 --- a/src/daemon/dlt_daemon_offline_logstorage.c +++ b/src/daemon/dlt_daemon_offline_logstorage.c @@ -565,3 +565,35 @@ int dlt_daemon_logstorage_setup_internal_storage(DltDaemon *daemon, char *path, return ret; } + +void dlt_daemon_logstorage_set_logstorage_cache_size(unsigned int size) +{ + /* store given [KB] size in [Bytes] */ + g_logstorage_cache_max = size * 1000; +} + +int dlt_daemon_logstorage_cleanup(DltDaemon *daemon, + DltDaemonLocal *daemon_local, + int verbose) +{ + int i = 0; + + PRINT_FUNCTION_VERBOSE(verbose); + + if (daemon == NULL || daemon_local == NULL) + { + return -1; + } + + for (i = 0; i < daemon_local->flags.offlineLogstorageMaxDevices; i++) + { + /* call disconnect on all currently connected devices */ + if (daemon->storage_handle[i].connection_type == + DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) + { + dlt_logstorage_device_disconnected(&daemon->storage_handle[i]); + } + } + + return 0; +} diff --git a/src/daemon/dlt_daemon_offline_logstorage.h b/src/daemon/dlt_daemon_offline_logstorage.h index 621bd59..cb7698a 100644 --- a/src/daemon/dlt_daemon_offline_logstorage.h +++ b/src/daemon/dlt_daemon_offline_logstorage.h @@ -126,4 +126,23 @@ void dlt_daemon_logstorage_write(DltDaemon *daemon, DltDaemonFlags user_config, * @param verbose If set to true verbose information is printed out */ int dlt_daemon_logstorage_setup_internal_storage(DltDaemon *daemon, char *path, int verbose); + +/** + * Set max size of logstorage cache. Stored internally in bytes + * + * @param size Size of logstorage cache [in KB] + */ +void dlt_daemon_logstorage_set_logstorage_cache_size(unsigned int size); + +/** + * Cleanup dlt logstorage + * + * @param daemon Pointer to Dlt Daemon structure + * @param daemon_local Pointer to Dlt Daemon Local structure + * @param verbose If set to true verbose information is printed out + */ +int dlt_daemon_logstorage_cleanup(DltDaemon *daemon, + DltDaemonLocal *daemon_local, + int verbose); + #endif /* DLT_DAEMON_OFFLINE_LOGSTORAGE_H */ diff --git a/src/offlinelogstorage/dlt_offline_logstorage.c b/src/offlinelogstorage/dlt_offline_logstorage.c index 682fe55..d1efbb5 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.c +++ b/src/offlinelogstorage/dlt_offline_logstorage.c @@ -32,6 +32,7 @@ #include <time.h> #include "dlt_offline_logstorage.h" +#include "dlt_offline_logstorage_behavior.h" #include "dlt_config_file_parser.h" @@ -312,6 +313,41 @@ int dlt_logstorage_read_number(unsigned int *number, char *value) return 0; } +/** + * dlt_logstorage_set_sync_strategy + * + * Evaluate sync strategy. The sync strategy is an optional filter + * configuration parameter. + * If the given value cannot be associated with a sync strategy, the default + * sync strategy will be assigned. + * + * @param file_name int to store the sync strategy + * @param value string given in config file + * @return 0 on success, -1 on error + */ +int dlt_logstorage_set_sync_strategy(int *strategy, char *value) +{ + if (value == NULL || strategy == NULL) + { + return -1; + } + + if (strncasecmp(value, "ON_MSG", strlen(value)) == 0) + { + *strategy = DLT_LOGSTORAGE_SYNC_ON_MSG; + } + else if (strncasecmp(value, "ON_DAEMON_EXIT", strlen(value)) == 0) + { + *strategy = DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT; + } + else + { + dlt_log(LOG_WARNING, "Unknown sync strategy. Set default ON_MSG\n"); + *strategy = DLT_LOGSTORAGE_SYNC_ON_MSG; + } + + return 0; +} /** * dlt_logstorage_create_keys @@ -518,10 +554,23 @@ void dlt_logstorage_free(DltLogStorage *handle) for(i=0; i<handle->num_filter_keys; i++) { + /* sync data if necessary */ + /* ignore return value */ + handle->config_data[i].data.dlt_logstorage_sync( + &(handle->config_data[i].data), + DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT); + free(handle->config_data[i].data.file_name); if (handle->config_data[i].data.log != NULL) - fclose(handle->config_data[i].data.log); + { + fclose(handle->config_data[i].data.log); + } + + if (handle->config_data[i].data.cache != NULL) + { + free(handle->config_data[i].data.cache); + } DltLogStorageFileList *n = handle->config_data[i].data.records; while(n) @@ -624,6 +673,8 @@ int dlt_logstorage_prepare_table(DltLogStorage *handle, char *appid, char *ctxid memcpy(&p_node->data, tmp_data, sizeof(DltLogStorageConfigData)); p_node->data.file_name = strdup(tmp_data->file_name); p_node->data.records = NULL; + p_node->data.log = NULL; + p_node->data.cache = NULL; if(dlt_logstorage_hash_add(p_node->key, &p_node->data, &(handle->config_htab)) != 0) { @@ -703,6 +754,14 @@ int dlt_logstorage_validate_filter_value(char *filter_key, char *filter_value, if (ret == 0) ret = DLT_OFFLINE_LOGSTORAGE_NUM_INIT; } + else if (strncmp(filter_key, "SyncBehavior", strlen ("SyncBehavior")) == 0) + { + ret = dlt_logstorage_set_sync_strategy(&(tmp_data->sync), filter_value); + if (ret == 0) + { + return DLT_OFFLINE_LOGSTORAGE_SYNC_BEHAVIOR; + } + } else { /* Invalid filter key */ @@ -754,6 +813,29 @@ int dlt_logstorage_validate_filter_name(char *name) return -1; } +void dlt_logstorage_filter_set_strategy(DltLogStorageConfigData *config, + int strategy) +{ + if (config == NULL) + { + return; + } + + switch(strategy) + { + case DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT: + config->dlt_logstorage_prepare = &dlt_logstorage_prepare_on_daemon_exit; + config->dlt_logstorage_write = &dlt_logstorage_write_on_daemon_exit; + config->dlt_logstorage_sync = &dlt_logstorage_sync_on_daemon_exit; + break; + case DLT_LOGSTORAGE_SYNC_ON_MSG: /* ON_MSG is the default strategy */ + default: + config->dlt_logstorage_prepare = &dlt_logstorage_prepare_on_msg; + config->dlt_logstorage_write = &dlt_logstorage_write_on_msg; + config->dlt_logstorage_sync = &dlt_logstorage_sync_on_msg; + } +} + /** * dlt_logstorage_store_filters * @@ -783,7 +865,8 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) "LogLevel", "File", "FileSize", - "NOFiles" + "NOFiles", + "SyncBehavior" }; config_file = dlt_config_file_init(config_file_name); @@ -805,6 +888,7 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) int j = 0; int ret = -1; memset(&tmp_data, 0, sizeof(DltLogStorageConfigData)); + for (i = 0; i < num_filters; i++) { if (tmp_data.file_name != NULL) @@ -841,7 +925,9 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) { /* Get filter value for filter keys */ ret = dlt_config_file_get_value(config_file, filter_name, filter_key[j], filter_value); - if (ret != 0) + if (ret != 0 && + strncmp(filter_key[j], "SyncBehavior", strlen(filter_key[j])) + != 0) { is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; dlt_log(LOG_ERR, "dlt_logstorage_store_filters Error : Reading filter value failed\n"); @@ -849,20 +935,35 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) } /* Validate filter value */ - ret = dlt_logstorage_validate_filter_value(filter_key[j], filter_value, &appid, &ctxid, &tmp_data); - if ((ret != -1) && DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(is_filter_set)) + if (ret == 0) { - is_filter_set |= ret; + ret = dlt_logstorage_validate_filter_value(filter_key[j], filter_value, &appid, &ctxid, &tmp_data); + if ((ret != -1) && DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(is_filter_set)) + { + is_filter_set |= ret; + } + else + { + is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; + break; + } } else { - is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; - break; + dlt_log(LOG_INFO, + "Sync strategy not given. Use default ON_MSG\n"); + /* set default sync strategy */ + tmp_data.sync = DLT_LOGSTORAGE_SYNC_ON_MSG; } } + /* If all items of the filter is populated store them */ if (DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(is_filter_set)) { + /* depending on the specified strategy set function pointers for + * prepare, write and sync */ + dlt_logstorage_filter_set_strategy(&tmp_data, tmp_data.sync); + ret = dlt_logstorage_prepare_table(handle, appid, ctxid, &tmp_data); if (ret != 0) { @@ -1088,469 +1189,6 @@ DltLogStorageConfigData **dlt_logstorage_filter(DltLogStorage *handle, char *app } /** - * dlt_logstorage_log_file_name - * - * Create log file name in the form configured by the user - * <filename><delimeter><index><delimeter><timestamp>.dlt - * - * filename: given in configuration file - * delimeter: 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) -{ - char file_index[10] = {0}; - - // create log file name - memset(log_file_name, 0, PATH_MAX * sizeof(char)); - strcat(log_file_name, name); - strcat(log_file_name, &file_config.logfile_delimiter); - - sprintf(file_index,"%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; - sprintf(file_index,"%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)->next == NULL) - return; - - while (!done) - { - DltLogStorageFileList **pv = head; // "source" of the pointer to the current node in the list struct - 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)->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; - - /* 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 index 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 (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: Unable to scan storage 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 failure while preparing file list \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 failure while preparing file list \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[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[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 failure while adding file name to file list \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 occured - * 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 failure while adding file name to file list \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_log_file - * - * 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_log_file(DltLogStorageConfigData *config, - DltLogStorageUserConfig file_config, - char *dev_path, int log_msg_size) -{ - int ret = 0; - struct stat s; - - if (config == 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: Unable to determine file stats.\n"); - ret = -1; - } - } - return ret; -} - -/** * dlt_logstorage_write * * Write a message to one or more configured log files, based on filter configuration. @@ -1582,7 +1220,8 @@ int dlt_logstorage_write(DltLogStorage *handle, DltLogStorageUserConfig file_con return 0; } - /* check if log message need to be stored in a certain device based on filter config */ + /* check if log message need to be stored in a certain device based on + * filter configuration */ config = dlt_logstorage_filter(handle, appid, ctxid, log_level, &num); if (config != NULL) @@ -1593,39 +1232,48 @@ int dlt_logstorage_write(DltLogStorage *handle, DltLogStorageUserConfig file_con if(config[i] != NULL) { /* prepare logfile (create and/or open)*/ - ret = dlt_logstorage_prepare_log_file(config[i], file_config, - handle->device_mount_point, - size1 + size2 + size3); + ret = config[i]->dlt_logstorage_prepare(config[i], + &file_config, + handle->device_mount_point, + size1 + size2 + size3); if (ret == 0) /* log data (write) */ { - fwrite(data1, 1, size1, config[i]->log); - fwrite(data2, 1, size2, config[i]->log); - fwrite(data3, 1, size3, config[i]->log); - ret = ferror(config[i]->log); - - if (ret != 0) + ret = config[i]->dlt_logstorage_write(config[i], + data1, + size1, + data2, + size2, + data3, + size3); + + if (ret == 0) { - handle->write_errors += 1; - if (handle->write_errors >= DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS) + /* flush to be sure log is stored on device */ + ret = config[i]->dlt_logstorage_sync(config[i], + DLT_LOGSTORAGE_SYNC_ON_MSG); + if (ret != 0) { - err = -1; + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to sync.\n"); } - - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to write log to file.\n"); } else { - /* flush to be sure log is stored on device */ - ret = fflush(config[i]->log); - if (ret != 0) + handle->write_errors += 1; + if (handle->write_errors >= + DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS) { - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to flush log to file.\n"); + err = -1; } + + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to write.\n"); } } else { - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to prepare log file.\n"); + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to prepare.\n"); } } i++; diff --git a/src/offlinelogstorage/dlt_offline_logstorage.h b/src/offlinelogstorage/dlt_offline_logstorage.h index 80a75e8..01427a1 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.h +++ b/src/offlinelogstorage/dlt_offline_logstorage.h @@ -81,16 +81,18 @@ DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + 1) #define DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT 0 -#define DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT (1<<6) -#define DLT_OFFLINE_LOGSTORAGE_APP_INIT (1<<5) -#define DLT_OFFLINE_LOGSTORAGE_CTX_INIT (1<<4) -#define DLT_OFFLINE_LOGSTORAGE_LOG_LVL_INIT (1<<3) -#define DLT_OFFLINE_LOGSTORAGE_NAME_INIT (1<<2) -#define DLT_OFFLINE_LOGSTORAGE_SIZE_INIT (1<<1) +#define DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT (1<<7) +#define DLT_OFFLINE_LOGSTORAGE_APP_INIT (1<<6) +#define DLT_OFFLINE_LOGSTORAGE_CTX_INIT (1<<5) +#define DLT_OFFLINE_LOGSTORAGE_LOG_LVL_INIT (1<<4) +#define DLT_OFFLINE_LOGSTORAGE_NAME_INIT (1<<3) +#define DLT_OFFLINE_LOGSTORAGE_SIZE_INIT (1<<2) +#define DLT_OFFLINE_LOGSTORAGE_SYNC_BEHAVIOR (1<<1) #define DLT_OFFLINE_LOGSTORAGE_NUM_INIT 1 -#define DLT_OFFLINE_LOGSTORAGE_FILTER_INIT 0x7F +/* Sync behavior is optional */ +#define DLT_OFFLINE_LOGSTORAGE_FILTER_INIT 0xFD -#define DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(A) ((A) == DLT_OFFLINE_LOGSTORAGE_FILTER_INIT) +#define DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(A) ((A) >= DLT_OFFLINE_LOGSTORAGE_FILTER_INIT) #define DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(A) ((A) & DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT) @@ -105,10 +107,26 @@ #define DLT_OFFLINE_LOGSTORAGE_MIN(A, B) ((A) < (B) ? (A) : (B)) #define DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS 5 -#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_NUM 6 +#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_NUM 7 #define DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION "FILTER" +/* Offline Logstorage sync strategies */ +#define DLT_LOGSTORAGE_SYNC_ON_MSG 0x00 /* default, on message sync */ +#define DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT 0x01 /* sync on daemon exit */ + + +/* logstorage max cache */ +unsigned int g_logstorage_cache_max; +/* current logstorage cache size */ +unsigned int g_logstorage_cache_size; + +typedef struct +{ + int offset; /* current write offset */ + unsigned int wrap_around_cnt; /* wrap around counter */ +}DltLogStorageCacheFooter; + typedef struct { /* File name user configurations */ @@ -126,14 +144,33 @@ typedef struct DltLogStorageFileList struct DltLogStorageFileList *next; }DltLogStorageFileList; -typedef struct +typedef struct DltLogStorageConfigData DltLogStorageConfigData; + +typedef struct DltLogStorageConfigData { /* filter section */ int log_level; /* Log level number configured for filter */ char *file_name; /* File name for log storage configured for filter */ unsigned int file_size; /* MAX File size of storage file configured for filter */ unsigned int num_files; /* MAX number of storage files configured for filters */ + int sync; /* Sync strategy */ + /* callback function for filter configurations */ + int (*dlt_logstorage_prepare)(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); + int (*dlt_logstorage_write)(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + /* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ + int (*dlt_logstorage_sync)(DltLogStorageConfigData *config, int status); FILE *log; /* current open log file */ + void *cache; /* log data cache */ DltLogStorageFileList *records; /* File name list */ }DltLogStorageConfigData; 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; +} diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.h b/src/offlinelogstorage/dlt_offline_logstorage_behavior.h new file mode 100644 index 0000000..16394be --- /dev/null +++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.h @@ -0,0 +1,91 @@ +/** + * @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 header 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 + * + * \file: dlt_offline_logstorage_behavior.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt_offline_logstorage_behavior.h ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** ** +** PURPOSE : ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** cl Christoph Lipka ADIT ** +*******************************************************************************/ + + +#ifndef DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ +#define DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ + +/* ON_MSG behavior */ +int dlt_logstorage_prepare_on_msg(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); +int dlt_logstorage_write_on_msg(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + +/* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ +int dlt_logstorage_sync_on_msg(DltLogStorageConfigData *config, int status); + +/* ON_DAEMON_EXIT behavior */ +int dlt_logstorage_prepare_on_daemon_exit(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); + +int dlt_logstorage_write_on_daemon_exit(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + +/* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ +int dlt_logstorage_sync_on_daemon_exit(DltLogStorageConfigData *config, + int status); + +#endif /* DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ */ |