diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/dlt_common.c | 156 | ||||
-rw-r--r-- | src/shared/dlt_multiple_files.c | 499 | ||||
-rw-r--r-- | src/shared/dlt_offline_trace.c | 397 |
3 files changed, 661 insertions, 391 deletions
diff --git a/src/shared/dlt_common.c b/src/shared/dlt_common.c index 97766f7..cbbe99a 100644 --- a/src/shared/dlt_common.c +++ b/src/shared/dlt_common.c @@ -31,6 +31,7 @@ #include <time.h> /* for localtime_r(), strftime() */ #include <limits.h> /* for NAME_MAX */ #include <inttypes.h> /* for PRI formatting macro */ +#include <libgen.h> /* dirname */ #include <stdarg.h> #include <err.h> @@ -41,6 +42,7 @@ #include "dlt_user_shared.h" #include "dlt_common.h" #include "dlt_common_cfg.h" +#include "dlt_multiple_files.h" #include "dlt_version.h" @@ -84,6 +86,17 @@ static bool print_with_attributes = false; int logging_mode = DLT_LOG_TO_STDERR; FILE *logging_handle = NULL; +//use ohandle as an indicator that multiple files logging is active +MultipleFilesRingBuffer multiple_files_ring_buffer = { + .directory={0}, + .filename={0}, + .fileSize=0, + .maxSize=0, + .filenameTimestampBased=false, + .filenameBase={0}, + .filenameExt={0}, + .ohandle=-1}; + char *message_type[] = { "log", "app_trace", "nw_trace", "control", "", "", "", "" }; char *log_info[] = { "", "fatal", "error", "warn", "info", "debug", "verbose", "", "", "", "", "", "", "", "", "" }; char *trace_type[] = { "", "variable", "func_in", "func_out", "state", "vfb", "", "", "", "", "", "", "", "", "", "" }; @@ -1816,34 +1829,114 @@ void dlt_print_with_attributes(bool state) DltReturnValue dlt_log_init(int mode) { + return dlt_log_init_multiple_logfiles_support((DltLoggingMode)mode, false, 0, 0); +} + +DltReturnValue dlt_log_init_multiple_logfiles_support(const DltLoggingMode mode, const bool enable_multiple_logfiles, + const int logging_file_size, const int logging_files_max_size) +{ if ((mode < DLT_LOG_TO_CONSOLE) || (mode > DLT_LOG_DROPPED)) { - dlt_user_printf("Wrong parameter for mode: %d\n", mode); + dlt_vlog(LOG_WARNING, "Wrong parameter for mode: %d\n", mode); return DLT_RETURN_WRONG_PARAMETER; } logging_mode = mode; - if (logging_mode == DLT_LOG_TO_FILE) { - /* internal logging to file */ - logging_handle = fopen(logging_filename, "a"); + if (logging_mode != DLT_LOG_TO_FILE) { + return DLT_RETURN_OK; + } - if (logging_handle == NULL) { - dlt_user_printf("Internal log file %s cannot be opened!\n", logging_filename); - return DLT_RETURN_ERROR; + if (enable_multiple_logfiles) { + dlt_user_printf("configure dlt logging using file limits\n"); + int result = dlt_log_init_multiple_logfiles(logging_file_size, logging_files_max_size); + if (result == DLT_RETURN_OK) { + return DLT_RETURN_OK; } + dlt_user_printf("dlt logging for limits fails with error code=%d, use logging without limits as fallback\n", result); + return dlt_log_init_single_logfile(); + } else { + dlt_user_printf("configure dlt logging without file limits\n"); + return dlt_log_init_single_logfile(); } +} +DltReturnValue dlt_log_init_single_logfile() +{ + /* internal logging to file */ + errno = 0; + logging_handle = fopen(logging_filename, "a"); + + if (logging_handle == NULL) { + dlt_user_printf("Internal log file %s cannot be opened, error: %s\n", logging_filename, strerror(errno)); + return DLT_RETURN_ERROR; + } return DLT_RETURN_OK; } +DltReturnValue dlt_log_init_multiple_logfiles(const int logging_file_size, const int logging_files_max_size) +{ + char path_logging_filename[PATH_MAX + 1]; + strncpy(path_logging_filename, logging_filename, PATH_MAX); + path_logging_filename[PATH_MAX] = 0; + + const char *directory = dirname(path_logging_filename); + if (directory[0]) { + char basename_logging_filename[NAME_MAX + 1]; + strncpy(basename_logging_filename, logging_filename, NAME_MAX); + basename_logging_filename[NAME_MAX] = 0; + + const char *file_name = basename(basename_logging_filename); + char filename_base[NAME_MAX]; + if (!dlt_extract_base_name_without_ext(file_name, filename_base, sizeof(filename_base))) return DLT_RETURN_ERROR; + + const char *filename_ext = get_filename_ext(file_name); + if (!filename_ext) return DLT_RETURN_ERROR; + + DltReturnValue result = multiple_files_buffer_init( + &multiple_files_ring_buffer, + directory, + logging_file_size, + logging_files_max_size, + false, + true, + filename_base, + filename_ext); + + return result; + } + + return DLT_RETURN_ERROR; +} + void dlt_log_free(void) { - if (logging_mode == DLT_LOG_TO_FILE && logging_handle) + if (logging_mode == DLT_LOG_TO_FILE) { + if (dlt_is_log_in_multiple_files_active()) { + dlt_log_free_multiple_logfiles(); + } else { + dlt_log_free_single_logfile(); + } + } +} + +void dlt_log_free_single_logfile() +{ + if (logging_handle) fclose(logging_handle); } +void dlt_log_free_multiple_logfiles() +{ + if (DLT_RETURN_ERROR == multiple_files_buffer_free(&multiple_files_ring_buffer)) return; + + // reset indicator of multiple files usage + multiple_files_ring_buffer.ohandle = -1; +} + int dlt_user_printf(const char *format, ...) { + if (format == NULL) return -1; + va_list args; va_start(args, format); @@ -1922,9 +2015,13 @@ DltReturnValue dlt_log(int prio, char *s) #endif break; case DLT_LOG_TO_FILE: - /* log to file */ - if (logging_handle) { + + if (dlt_is_log_in_multiple_files_active()) { + dlt_log_multiple_files_write(sFormatString, (unsigned int)sTimeSpec.tv_sec, + (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s); + } + else if (logging_handle) { fprintf(logging_handle, sFormatString, (unsigned int)sTimeSpec.tv_sec, (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s); fflush(logging_handle); @@ -4308,3 +4405,42 @@ int dlt_execute_command(char *filename, char *command, ...) free(args); return ret; } + +char *get_filename_ext(const char *filename) +{ + if (filename == NULL) { + fprintf(stderr, "ERROR: %s: invalid arguments\n", __FUNCTION__); + return NULL; + } + + char *dot = strrchr(filename, '.'); + return (!dot || dot == filename) ? NULL : dot; +} + +bool dlt_extract_base_name_without_ext(const char* const abs_file_name, char* base_name, long base_name_len) { + if (abs_file_name == NULL || base_name == NULL) return false; + + const char* last_separator = strrchr(abs_file_name, '.'); + if (!last_separator) return false; + long length = last_separator - abs_file_name; + length = length > base_name_len ? base_name_len : length; + + strncpy(base_name, abs_file_name, length); + base_name[length] = '\0'; + return true; +} + +void dlt_log_multiple_files_write(const char* format, ...) +{ + char output_string[2048] = { 0 }; + va_list args; + va_start (args, format); + vsnprintf(output_string, 2047, format, args); + va_end (args); + multiple_files_buffer_write(&multiple_files_ring_buffer, (unsigned char*)output_string, strlen(output_string)); +} + +bool dlt_is_log_in_multiple_files_active() +{ + return multiple_files_ring_buffer.ohandle > -1; +} diff --git a/src/shared/dlt_multiple_files.c b/src/shared/dlt_multiple_files.c new file mode 100644 index 0000000..754fd1e --- /dev/null +++ b/src/shared/dlt_multiple_files.c @@ -0,0 +1,499 @@ +/* + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2022, Daimler TSS GmbH + * + * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License (MPL), 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/. + * + * For further information see https://www.covesa.global/. + */ + +/*! + * \author + * Oleg Tropmann <oleg.tropmann@daimler.com> + * Daniel Weber <daniel.w.weber@daimler.com> + * + * \copyright Copyright © 2022 Daimler TSS GmbH. \n + * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. + * + * \file dlt_daemon_log.c + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> +#include <syslog.h> +#include <errno.h> +#include <stdarg.h> + +#include <dlt_multiple_files.h> +#include "dlt_common.h" + +unsigned int multiple_files_buffer_storage_dir_info(const char *path, const char *file_name, + char *newest, char *oldest) +{ + int i = 0; + unsigned int num_log_files = 0; + struct dirent **files = { 0 }; + char *tmp_old = NULL; + char *tmp_new = NULL; + + if ((path == NULL) || (file_name == NULL) || (newest == NULL) || (oldest == NULL)) { + fprintf(stderr, "multiple_files_buffer_storage_dir_info: Invalid parameter(s)"); + return 0; + } + + const int file_cnt = scandir(path, &files, NULL, alphasort); + if (file_cnt <= 0) return 0; + + for (i = 0; i < file_cnt; i++) { + int len = 0; + len = strlen(file_name); + + if ((strncmp(files[i]->d_name, file_name, len) == 0) && + (files[i]->d_name[len] == MULTIPLE_FILES_FILENAME_INDEX_DELIM[0])) { + num_log_files++; + + if ((tmp_old == NULL) || (strlen(tmp_old) >= strlen(files[i]->d_name))) { + if (tmp_old == NULL) { + tmp_old = files[i]->d_name; + } else if (strlen(tmp_old) > strlen(files[i]->d_name)) { + /* when file name is smaller, it is older */ + tmp_old = files[i]->d_name; + } else if (strcmp(tmp_old, files[i]->d_name) > 0) { + /* filename length is equal, do a string compare */ + tmp_old = files[i]->d_name; + } + } + + if ((tmp_new == NULL) || (strlen(tmp_new) <= strlen(files[i]->d_name))) { + if (tmp_new == NULL) { + tmp_new = files[i]->d_name; + } else if (strlen(tmp_new) < strlen(files[i]->d_name)) { + /* when file name is longer, it is younger */ + tmp_new = files[i]->d_name; + } else if (strcmp(tmp_new, files[i]->d_name) < 0) { + tmp_new = files[i]->d_name; + } + } + } + } + + if (num_log_files > 0) { + if ((tmp_old != NULL) && (strlen(tmp_old) < NAME_MAX)) { + strncpy(oldest, tmp_old, NAME_MAX); + oldest[NAME_MAX] = '\0'; + } else if ((tmp_old != NULL) && (strlen(tmp_old) >= NAME_MAX)) { + printf("length mismatch of file %s\n", tmp_old); + } + + if ((tmp_new != NULL) && (strlen(tmp_new) < NAME_MAX)) { + strncpy(newest, tmp_new, NAME_MAX); + oldest[NAME_MAX] = '\0'; + } else if ((tmp_new != NULL) && (strlen(tmp_new) >= NAME_MAX)) { + printf("length mismatch of file %s\n", tmp_new); + } + } + + /* free scandir result */ + for (i = 0; i < file_cnt; i++) free(files[i]); + + free(files); + + return num_log_files; +} + +void multiple_files_buffer_file_name(MultipleFilesRingBuffer *files_buffer, const size_t length, const unsigned int idx) +{ + char file_index[11]; /* UINT_MAX = 4294967295 -> 10 digits */ + snprintf(file_index, sizeof(file_index), "%010u", idx); + + /* create log file name */ + char* file_name = files_buffer->filename; + memset(file_name, 0, length * sizeof(char)); + + const size_t size = length - strlen(file_name) - 1; + strncat(file_name, files_buffer->filenameBase, size); + strncat(file_name, MULTIPLE_FILES_FILENAME_INDEX_DELIM, size); + strncat(file_name, file_index, size); + strncat(file_name, files_buffer->filenameExt, size); +} + +unsigned int multiple_files_buffer_get_idx_of_log_file(char *file) +{ + if ((file == NULL) || (file[0] == '\0')) return 0; + + const char d[2] = MULTIPLE_FILES_FILENAME_INDEX_DELIM; + char *token; + + token = strtok(file, d); + /* we are interested in 2. token because of log file name */ + token = strtok(NULL, d); + + return token != NULL ? strtol(token, NULL, 10) : 0; +} + +DltReturnValue multiple_files_buffer_create_new_file(MultipleFilesRingBuffer *files_buffer) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return DLT_RETURN_ERROR; + } + + time_t t; + struct tm tmp; + char file_path[PATH_MAX + 1]; + unsigned int idx = 0; + int ret = 0; + + /* set filename */ + if (files_buffer->filenameTimestampBased) { + /* timestamp format: "yyyymmdd_hhmmss" */ + char timestamp[16]; + t = time(NULL); + tzset(); + localtime_r(&t, &tmp); + + strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", &tmp); + + ret = snprintf(files_buffer->filename, sizeof(files_buffer->filename), "%s%s%s%s", + files_buffer->filenameBase, + MULTIPLE_FILES_FILENAME_TIMESTAMP_DELIM, timestamp, + files_buffer->filenameExt); + + if ((ret < 0) || ((size_t)ret >= (int)sizeof(files_buffer->filename))) { + fprintf(stderr, "filename cannot be concatenated\n"); + return DLT_RETURN_ERROR; + } + + ret = snprintf(file_path, sizeof(file_path), "%s/%s", + files_buffer->directory, files_buffer->filename); + + if ((ret < 0) || ((size_t)ret >= (int)sizeof(file_path))) { + fprintf(stderr, "file path cannot be concatenated\n"); + return DLT_RETURN_ERROR; + } + } + else { + char newest[NAME_MAX + 1] = { 0 }; + char oldest[NAME_MAX + 1] = { 0 }; + /* targeting newest file, ignoring number of files in dir returned */ + if (0 == multiple_files_buffer_storage_dir_info(files_buffer->directory, + files_buffer->filenameBase, + newest, + oldest)) { + printf("No multiple files found\n"); + } + + idx = multiple_files_buffer_get_idx_of_log_file(newest) + 1; + + multiple_files_buffer_file_name(files_buffer, sizeof(files_buffer->filename), idx); + ret = snprintf(file_path, sizeof(file_path), "%s/%s", + files_buffer->directory, files_buffer->filename); + + if ((ret < 0) || (ret >= NAME_MAX)) { + fprintf(stderr, "filename cannot be concatenated\n"); + return DLT_RETURN_ERROR; + } + } + + /* open DLT output file */ + errno = 0; + files_buffer->ohandle = open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | + S_IRGRP | S_IROTH); /* mode: wb */ + + if (files_buffer->ohandle == -1) { + /* file cannot be opened */ + fprintf(stderr, "file %s cannot be created, error: %s\n", file_path, strerror(errno)); + return DLT_RETURN_ERROR; + } + + return DLT_RETURN_OK; +} + +ssize_t multiple_files_buffer_get_total_size(const MultipleFilesRingBuffer *files_buffer) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return -1; + } + + struct dirent *dp; + char filename[PATH_MAX + 1]; + ssize_t size = 0; + struct stat status; + + /* go through all dlt files in directory */ + DIR *dir = opendir(files_buffer->directory); + if (!dir) { + fprintf(stderr, "directory %s cannot be opened, error=%s\n", files_buffer->directory, strerror(errno)); + return -1; + } + + while ((dp = readdir(dir)) != NULL) { + // consider files matching with a specific base name and a particular extension + if (strstr(dp->d_name, files_buffer->filenameBase) && strstr(dp->d_name, files_buffer->filenameExt)) { + int res = snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name); + + /* if the total length of the string is greater than the buffer, silently forget it. */ + /* snprintf: a return value of size or more means that the output was truncated */ + /* if an output error is encountered, a negative value is returned. */ + if (((unsigned int)res < sizeof(filename)) && (res > 0)) { + errno = 0; + if (0 == stat(filename, &status)) + size += status.st_size; + else + fprintf(stderr, "file %s cannot be stat-ed, error=%s\n", filename, strerror(errno)); + } + } + } + + closedir(dir); + + /* return size */ + return size; +} + +int multiple_files_buffer_delete_oldest_file(MultipleFilesRingBuffer *files_buffer) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return -1; /* ERROR */ + } + + struct dirent *dp; + char filename[PATH_MAX + 1]; + char filename_oldest[PATH_MAX + 1]; + unsigned long size_oldest = 0; + struct stat status; + time_t time_oldest = 0; + int index_oldest = INT_MAX; + + filename[0] = 0; + filename_oldest[0] = 0; + + /* go through all dlt files in directory */ + DIR *dir = opendir(files_buffer->directory); + + if(!dir) + return -1; + + while ((dp = readdir(dir)) != NULL) { + if (strstr(dp->d_name, files_buffer->filenameBase) && strstr(dp->d_name, files_buffer->filenameExt)) { + int res = snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name); + + /* if the total length of the string is greater than the buffer, silently forget it. */ + /* snprintf: a return value of size or more means that the output was truncated */ + /* if an output error is encountered, a negative value is returned. */ + if (((unsigned int) res >= sizeof(filename)) || (res <= 0)) { + printf("Filename for delete oldest too long. Skip file.\n"); + continue; + } + + if (files_buffer->filenameTimestampBased) { + errno = 0; + if (0 == stat(filename, &status)) { + if ((time_oldest == 0) || (status.st_mtime < time_oldest)) { + time_oldest = status.st_mtime; + size_oldest = status.st_size; + strncpy(filename_oldest, filename, PATH_MAX); + filename_oldest[PATH_MAX] = 0; + } + } else { + printf("Old file %s cannot be stat-ed, error=%s\n", filename, strerror(errno)); + } + } else { + //index based + const int index = multiple_files_buffer_get_idx_of_log_file(filename); + if (index < index_oldest) { + index_oldest = index; + snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name); + strncpy(filename_oldest, filename, PATH_MAX); + filename_oldest[PATH_MAX] = 0; + } + } + } + } + + closedir(dir); + + /* delete file */ + if (filename_oldest[0]) { + if (remove(filename_oldest)) { + fprintf(stderr, "Remove file %s failed! error=%s\n", filename_oldest, strerror(errno)); + return -1; /* ERROR */ + } + } else { + fprintf(stderr, "No file to be removed!\n"); + return -1; /* ERROR */ + } + + /* return size of deleted file*/ + return size_oldest; +} + +DltReturnValue multiple_files_buffer_check_size(MultipleFilesRingBuffer *files_buffer) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return DLT_RETURN_ERROR; + } + + struct stat status; + + /* check for existence of buffer files directory */ + errno = 0; + if (stat(files_buffer->directory, &status) == -1) { + fprintf(stderr, "Buffer files directory: %s doesn't exist, error=%s\n", files_buffer->directory, strerror(errno)); + return DLT_RETURN_ERROR; + } + /* check for accessibility of buffer files directory */ + else if (access(files_buffer->directory, W_OK) != 0) { + fprintf(stderr, "Buffer files directory: %s doesn't have the write access \n", files_buffer->directory); + return DLT_RETURN_ERROR; + } + + ssize_t total_size = 0; + /* check size of complete buffer file */ + while ((total_size = multiple_files_buffer_get_total_size(files_buffer)) > (files_buffer->maxSize - files_buffer->fileSize)) { + /* remove the oldest files as long as new file will not fit in completely into complete multiple files buffer */ + if (multiple_files_buffer_delete_oldest_file(files_buffer) < 0) return DLT_RETURN_ERROR; + } + + return total_size == -1 ? DLT_RETURN_ERROR : DLT_RETURN_OK; +} + +DltReturnValue multiple_files_buffer_open_file_for_append(MultipleFilesRingBuffer *files_buffer) { + if (files_buffer == NULL || files_buffer->filenameTimestampBased) return DLT_RETURN_ERROR; + + char newest[NAME_MAX + 1] = {0}; + char oldest[NAME_MAX + 1] = {0}; + /* targeting the newest file, ignoring number of files in dir returned */ + + if (0 == multiple_files_buffer_storage_dir_info(files_buffer->directory, + files_buffer->filenameBase, newest, oldest) ) { + // no file for appending found. Create a new one + printf("No multiple files for appending found. Create a new one\n"); + return multiple_files_buffer_create_new_file(files_buffer); + } + + char file_path[PATH_MAX + 1]; + int ret = snprintf(file_path, sizeof(file_path), "%s/%s", + files_buffer->directory, newest); + + if ((ret < 0) || (ret >= NAME_MAX)) { + fprintf(stderr, "filename cannot be concatenated\n"); + return DLT_RETURN_ERROR; + } + + /* open DLT output file */ + errno = 0; + files_buffer->ohandle = open(file_path, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR | + S_IRGRP | S_IROTH); /* mode: wb */ + + return files_buffer->ohandle == -1 ? DLT_RETURN_ERROR : DLT_RETURN_OK; +} + +DltReturnValue multiple_files_buffer_init(MultipleFilesRingBuffer *files_buffer, + const char *directory, + const int file_size, + const int max_size, + const bool filename_timestamp_based, + const bool append, + const char *filename_base, + const char *filename_ext) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return DLT_RETURN_ERROR; + } + + /* init parameters */ + strncpy(files_buffer->directory, directory, NAME_MAX); + files_buffer->directory[NAME_MAX] = 0; + files_buffer->fileSize = file_size; + files_buffer->maxSize = max_size; + files_buffer->filenameTimestampBased = filename_timestamp_based; + strncpy(files_buffer->filenameBase, filename_base, NAME_MAX); + files_buffer->filenameBase[NAME_MAX] = 0; + strncpy(files_buffer->filenameExt, filename_ext, NAME_MAX); + files_buffer->filenameExt[NAME_MAX] = 0; + + if (DLT_RETURN_ERROR == multiple_files_buffer_check_size(files_buffer)) return DLT_RETURN_ERROR; + + return (!files_buffer->filenameTimestampBased && append) + ? multiple_files_buffer_open_file_for_append(files_buffer) + : multiple_files_buffer_create_new_file(files_buffer); +} + +void multiple_files_buffer_rotate_file(MultipleFilesRingBuffer *files_buffer, const int size) +{ + /* check file size here */ + if ((lseek(files_buffer->ohandle, 0, SEEK_CUR) + size) < files_buffer->fileSize) return; + + /* close old file */ + close(files_buffer->ohandle); + files_buffer->ohandle = -1; + + /* check complete files size, remove old logs if needed */ + if (DLT_RETURN_ERROR == multiple_files_buffer_check_size(files_buffer)) return; + + /* create new file */ + multiple_files_buffer_create_new_file(files_buffer); +} + +DltReturnValue multiple_files_buffer_write_chunk(const MultipleFilesRingBuffer *files_buffer, + const unsigned char *data, + const int size) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return DLT_RETURN_ERROR; + } + + if (data && (files_buffer->ohandle >= 0)) { + if (write(files_buffer->ohandle, data, size) != size) { + fprintf(stderr, "file write failed!\n"); + return DLT_RETURN_ERROR; + } + } + return DLT_RETURN_OK; +} + +DltReturnValue multiple_files_buffer_write(MultipleFilesRingBuffer *files_buffer, + const unsigned char *data, + const int size) +{ + if (files_buffer->ohandle < 0) return DLT_RETURN_ERROR; + + multiple_files_buffer_rotate_file(files_buffer, size); + + /* write data into log file */ + return multiple_files_buffer_write_chunk(files_buffer, data, size); +} + +DltReturnValue multiple_files_buffer_free(const MultipleFilesRingBuffer *files_buffer) +{ + if (files_buffer == NULL) { + fprintf(stderr, "multiple files buffer not set\n"); + return DLT_RETURN_ERROR; + } + + if (files_buffer->ohandle < 0) return DLT_RETURN_ERROR; + + /* close last used log file */ + close(files_buffer->ohandle); + + return DLT_RETURN_OK; +} diff --git a/src/shared/dlt_offline_trace.c b/src/shared/dlt_offline_trace.c index 2b1e0df..b8b9a85 100644 --- a/src/shared/dlt_offline_trace.c +++ b/src/shared/dlt_offline_trace.c @@ -61,393 +61,28 @@ #include <unistd.h> #include <dirent.h> #include <syslog.h> +#include <errno.h> #include <dlt_offline_trace.h> -#include "dlt_common.h" - -unsigned int dlt_offline_trace_storage_dir_info(char *path, char *file_name, char *newest, char *oldest) -{ - int i = 0; - unsigned int num = 0; - int cnt = 0; - struct dirent **files = { 0 }; - char *tmp_old = NULL; - char *tmp_new = NULL; - - if ((path == NULL) || (file_name == NULL) || (newest == NULL) || (oldest == NULL)) { - printf("dlt_offline_trace_storage_dir_info: Invalid parameter(s)"); - return 0; - } - - cnt = scandir(path, &files, NULL, alphasort); - - if (cnt < 0) - return 0; - - for (i = 0; i < cnt; i++) { - int len = 0; - len = strlen(file_name); - - if ((strncmp(files[i]->d_name, file_name, len) == 0) && - (files[i]->d_name[len] == DLT_OFFLINETRACE_FILENAME_INDEX_DELI[0])) { - num++; - - if ((tmp_old == NULL) || (strlen(tmp_old) >= strlen(files[i]->d_name))) { - if (tmp_old == NULL) - tmp_old = files[i]->d_name; - /* when file name is smaller, it is older */ - else if (strlen(tmp_old) > strlen(files[i]->d_name)) - tmp_old = files[i]->d_name; - else /* filename is equal, do a string compare */ - if (strcmp(tmp_old, files[i]->d_name) > 0) - tmp_old = files[i]->d_name; - } - - if ((tmp_new == NULL) || (strlen(tmp_new) <= strlen(files[i]->d_name))) { - if (tmp_new == NULL) - tmp_new = files[i]->d_name; - /* when file name is longer, it is younger */ - else if (strlen(tmp_new) < strlen(files[i]->d_name)) - tmp_new = files[i]->d_name; - else if (strcmp(tmp_new, files[i]->d_name) < 0) - tmp_new = files[i]->d_name; - } - } - } - - if (num > 0) { - if ((tmp_old != NULL) && (strlen(tmp_old) < NAME_MAX)) { - strncpy(oldest, tmp_old, NAME_MAX); - oldest[NAME_MAX] = '\0'; - } - - if ((tmp_new != NULL) && (strlen(tmp_old) < NAME_MAX)) { - strncpy(newest, tmp_new, NAME_MAX); - oldest[NAME_MAX] = '\0'; - } - } - - /* free scandir result */ - for (i = 0; i < cnt; i++) - free(files[i]); - - free(files); - - return num; -} - -void dlt_offline_trace_file_name(char *log_file_name, size_t length, - char *name, unsigned int idx) -{ - char file_index[11]; /* UINT_MAX = 4294967295 -> 10 digits */ - snprintf(file_index, sizeof(file_index), "%010u", idx); - - /* create log file name */ - memset(log_file_name, 0, length * sizeof(char)); - strncat(log_file_name, name, length - strlen(log_file_name) - 1); - strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_INDEX_DELI, - length - strlen(log_file_name) - 1); - strncat(log_file_name, file_index, length - strlen(log_file_name) - 1); - strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_EXT, - length - strlen(log_file_name) - 1); -} - -unsigned int dlt_offline_trace_get_idx_of_log_file(char *file) -{ - const char d[2] = DLT_OFFLINETRACE_FILENAME_INDEX_DELI; - char *token; - unsigned int idx = 0; - - if (file[0] == '\0') - return 0; - - token = strtok(file, d); - /* we are interested in 2. token because of log file name */ - token = strtok(NULL, d); - - if (token != NULL) - idx = strtol(token, NULL, 10); - else - idx = 0; - - return idx; -} - - -DltReturnValue dlt_offline_trace_create_new_file(DltOfflineTrace *trace) -{ - time_t t; - struct tm tmp; - char file_path[PATH_MAX + 1]; - unsigned int idx = 0; - int ret = 0; - - /* set filename */ - if (trace->filenameTimestampBased) { - /* timestamp format: "yyyymmdd_hhmmss" */ - char timestamp[16]; - t = time(NULL); - tzset(); - localtime_r(&t, &tmp); - - strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", &tmp); - - ret = snprintf(trace->filename, sizeof(trace->filename), "%s%s%s%s", - DLT_OFFLINETRACE_FILENAME_BASE, - DLT_OFFLINETRACE_FILENAME_TIMESTAMP_DELI, timestamp, - DLT_OFFLINETRACE_FILENAME_EXT); - - if ((ret < 0) || ((size_t)ret >= (int)sizeof(trace->filename))) { - printf("dlt_offlinetrace filename cannot be concatenated\n"); - return DLT_RETURN_ERROR; - } - - ret = snprintf(file_path, sizeof(file_path), "%s/%s", - trace->directory, trace->filename); - - if ((ret < 0) || ((size_t)ret >= (int)sizeof(file_path))) { - printf("dlt_offlinetrace file path cannot be concatenated\n"); - return DLT_RETURN_ERROR; - } - } - else { - char newest[NAME_MAX + 1] = { 0 }; - char oldest[NAME_MAX + 1] = { 0 }; - /* targeting newest file, ignoring number of files in dir returned */ - dlt_offline_trace_storage_dir_info(trace->directory, - DLT_OFFLINETRACE_FILENAME_BASE, newest, oldest); - idx = dlt_offline_trace_get_idx_of_log_file(newest) + 1; - - dlt_offline_trace_file_name(trace->filename, sizeof(trace->filename), - DLT_OFFLINETRACE_FILENAME_BASE, idx); - ret = snprintf(file_path, sizeof(file_path), "%s/%s", - trace->directory, trace->filename); - - if ((ret < 0) || (ret >= NAME_MAX)) { - printf("filename cannot be concatenated\n"); - return DLT_RETURN_ERROR; - } - } - - /* open DLT output file */ - trace->ohandle = open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | - S_IRGRP | S_IROTH); /* mode: wb */ - - if (trace->ohandle == -1) { - /* trace file cannot be opened */ - printf("Offline trace file %s cannot be created\n", file_path); - return DLT_RETURN_ERROR; - } /* if */ - - return DLT_RETURN_OK; /* OK */ -} - -ssize_t dlt_offline_trace_get_total_size(DltOfflineTrace *trace) -{ - struct dirent *dp; - char filename[PATH_MAX + 1]; - ssize_t size = 0; - struct stat status; - - /* go through all dlt files in directory */ - DIR *dir = opendir(trace->directory); - - if (!dir) - return -1; - - while ((dp = readdir(dir)) != NULL) - if (strstr(dp->d_name, DLT_OFFLINETRACE_FILENAME_BASE)) { - int res = snprintf(filename, sizeof(filename), "%s/%s", trace->directory, dp->d_name); - - /* if the total length of the string is greater than the buffer, silently forget it. */ - /* snprintf: a return value of size or more means that the output was truncated */ - /* if an output error is encountered, a negative value is returned. */ - if (((unsigned int)res < sizeof(filename)) && (res > 0)) { - if (0 == stat(filename, &status)) - size += status.st_size; - else - printf("Offline trace file %s cannot be stat-ed", filename); - } - - /*else */ - /*{ */ - /* dlt_log(3, "dlt_offline_trace_get_total_size: long filename ignored"); */ - /*} */ - } - - closedir(dir); - - /* return size */ - return size; -} - -int dlt_offline_trace_delete_oldest_file(DltOfflineTrace *trace) -{ - struct dirent *dp; - char filename[PATH_MAX + 1]; - char filename_oldest[PATH_MAX + 1]; - unsigned long size_oldest = 0; - struct stat status; - time_t time_oldest = 0; - - filename[0] = 0; - filename_oldest[0] = 0; - - /* go through all dlt files in directory */ - DIR *dir = opendir(trace->directory); - - if(!dir) - return -1; - - while ((dp = readdir(dir)) != NULL) - if (strstr(dp->d_name, DLT_OFFLINETRACE_FILENAME_BASE)) { - int res = snprintf(filename, sizeof(filename), "%s/%s", trace->directory, dp->d_name); - - /* if the total length of the string is greater than the buffer, silently forget it. */ - /* snprintf: a return value of size or more means that the output was truncated */ - /* if an output error is encountered, a negative value is returned. */ - if (((unsigned int)res < sizeof(filename)) && (res > 0)) { - if (0 == stat(filename, &status)) { - if ((time_oldest == 0) || (status.st_mtime < time_oldest)) { - time_oldest = status.st_mtime; - size_oldest = status.st_size; - strncpy(filename_oldest, filename, PATH_MAX); - filename_oldest[PATH_MAX] = 0; - } - } - else { - printf("Old offline trace file %s cannot be stat-ed", filename); - } - } - } - - closedir(dir); - - /* delete file */ - if (filename_oldest[0]) { - if (remove(filename_oldest)) { - printf("Remove file %s failed!\n", filename_oldest); - return -1; /* ERROR */ - } - } - else { - printf("No file to be removed!\n"); - return -1; /* ERROR */ - } - - /* return size of deleted file*/ - return size_oldest; -} - -DltReturnValue dlt_offline_trace_check_size(DltOfflineTrace *trace) -{ - - struct stat status; - - /* check for existence of offline trace directory */ - if (stat(trace->directory, &status) == -1) { - dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't exist \n", trace->directory); - return DLT_RETURN_ERROR; - } - - /* check for accesibilty of offline trace directory */ - else if (access(trace->directory, W_OK) != 0) - { - dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't have the write access \n", trace->directory); - return DLT_RETURN_ERROR; - } - - ssize_t s = 0; - - /* check size of complete offline trace */ - while ((s = dlt_offline_trace_get_total_size(trace)) > (trace->maxSize - trace->fileSize)) - /* remove oldest files as long as new file will not fit in completely into complete offline trace */ - if (dlt_offline_trace_delete_oldest_file(trace) < 0) - return DLT_RETURN_ERROR; - - if (s == -1) - return DLT_RETURN_ERROR; - - return DLT_RETURN_OK; /* OK */ -} - -DltReturnValue dlt_offline_trace_init(DltOfflineTrace *trace, - const char *directory, - int fileSize, - int maxSize, - int filenameTimestampBased) -{ - - /* init parameters */ - strncpy(trace->directory, directory, NAME_MAX); - trace->directory[NAME_MAX] = 0; - trace->fileSize = fileSize; - trace->maxSize = maxSize; - trace->filenameTimestampBased = filenameTimestampBased; - /* check complete offlien trace size, remove old logs if needed */ - dlt_offline_trace_check_size(trace); - - return dlt_offline_trace_create_new_file(trace); -} - -DltReturnValue dlt_offline_trace_write(DltOfflineTrace *trace, - unsigned char *data1, - int size1, - unsigned char *data2, - int size2, - unsigned char *data3, - int size3) +#include <dlt_multiple_files.h> + +DltReturnValue dlt_offline_trace_write(MultipleFilesRingBuffer *trace, + const unsigned char *data1, + const int size1, + const unsigned char *data2, + const int size2, + const unsigned char *data3, + const int size3) { - if (trace->ohandle < 0) - return DLT_RETURN_ERROR; - - /* check file size here */ - if ((lseek(trace->ohandle, 0, SEEK_CUR) + size1 + size2 + size3) >= trace->fileSize) { - /* close old file */ - close(trace->ohandle); - trace->ohandle = -1; - - /* check complete offline trace size, remove old logs if needed */ - dlt_offline_trace_check_size(trace); + if (trace->ohandle < 0) return DLT_RETURN_ERROR; - /* create new file */ - dlt_offline_trace_create_new_file(trace); - } + multiple_files_buffer_rotate_file(trace, size1 + size2 + size3); /* write data into log file */ - if (data1 && (trace->ohandle >= 0)) { - if (write(trace->ohandle, data1, size1) != size1) { - printf("Offline trace write failed!\n"); - return DLT_RETURN_ERROR; - } - } - - if (data2 && (trace->ohandle >= 0)) { - if (write(trace->ohandle, data2, size2) != size2) { - printf("Offline trace write failed!\n"); - return DLT_RETURN_ERROR; - } - } - - if (data3 && (trace->ohandle >= 0)) { - if (write(trace->ohandle, data3, size3) != size3) { - printf("Offline trace write failed!\n"); - return DLT_RETURN_ERROR; - } - } - - return DLT_RETURN_OK; /* OK */ -} - -DltReturnValue dlt_offline_trace_free(DltOfflineTrace *trace) -{ - - if (trace->ohandle < 0) - return DLT_RETURN_ERROR; - - /* close last used log file */ - close(trace->ohandle); + if (multiple_files_buffer_write_chunk(trace, data1, size1) != DLT_RETURN_OK) return DLT_RETURN_ERROR; + if (multiple_files_buffer_write_chunk(trace, data2, size2) != DLT_RETURN_OK) return DLT_RETURN_ERROR; + if (multiple_files_buffer_write_chunk(trace, data3, size3) != DLT_RETURN_OK) return DLT_RETURN_ERROR; - return DLT_RETURN_OK; /* OK */ + return DLT_RETURN_OK; } |