From 7a5536825034feb89998811a9fe857cd7605b93b Mon Sep 17 00:00:00 2001 From: Haris Okanovic Date: Tue, 14 Nov 2023 08:49:11 -0600 Subject: [PATCH] Add ECUSoftwareVersionFileField option to dlt.conf (#554) Modify dlt_daemon_local_ecu_version_init() to read a single field from KEY=VALUE (or quoted KEY="VALUE") style files, so that dlt-daemon can report an OS version number parsed from /etc/os-release file. For example, get_software_version would return "22.04.3 LTS" under the following configuration: $ cat /etc/os-release PRETTY_NAME="Ubuntu 22.04.3 LTS" NAME="Ubuntu" VERSION="22.04.3 LTS" VERSION_CODENAME=jammy $ cat /etc/dlt.conf PathToECUSoftwareVersion = /etc/os-release ECUSoftwareVersionFileField = VERSION Signed-off-by: Haris Okanovic Co-authored-by: Haris Okanovic --- src/daemon/dlt-daemon.c | 173 ++++++++++++++++++++++++++++------------ src/daemon/dlt-daemon.h | 1 + src/daemon/dlt.conf | 3 + 3 files changed, 127 insertions(+), 50 deletions(-) diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c index 8c4bdb8e..78d5d261 100644 --- a/src/daemon/dlt-daemon.c +++ b/src/daemon/dlt-daemon.c @@ -389,6 +389,7 @@ int option_file_parser(DltDaemonLocal *daemon_local) daemon_local->daemonFifoSize = 0; daemon_local->flags.sendECUSoftwareVersion = 0; memset(daemon_local->flags.pathToECUSoftwareVersion, 0, sizeof(daemon_local->flags.pathToECUSoftwareVersion)); + memset(daemon_local->flags.ecuSoftwareVersionFileField, 0, sizeof(daemon_local->flags.ecuSoftwareVersionFileField)); daemon_local->flags.sendTimezone = 0; daemon_local->flags.offlineLogstorageMaxDevices = 0; daemon_local->flags.offlineLogstorageDirPath[0] = 0; @@ -632,6 +633,13 @@ int option_file_parser(DltDaemonLocal *daemon_local) - 1] = 0; /*printf("Option: %s=%s\n",token,value); */ } + else if (strcmp(token, "ECUSoftwareVersionFileField") == 0) { + strncpy(daemon_local->flags.ecuSoftwareVersionFileField, value, + sizeof(daemon_local->flags.ecuSoftwareVersionFileField) - 1); + daemon_local->flags.ecuSoftwareVersionFileField[sizeof(daemon_local->flags.ecuSoftwareVersionFileField) + - 1] = 0; + /*printf("Option: %s=%s\n",token,value); */ + } else if (strcmp(token, "SendTimezone") == 0) { daemon_local->flags.sendTimezone = atoi(value); @@ -1906,78 +1914,143 @@ int dlt_daemon_local_connection_init(DltDaemon *daemon, return 0; } -int dlt_daemon_local_ecu_version_init(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose) +static char* file_read_everything(FILE* const file, const size_t sizeLimit) { - char *version = NULL; - FILE *f = NULL; - - PRINT_FUNCTION_VERBOSE(verbose); - - /* By default, version string is null. */ - daemon->ECUVersionString = NULL; - - /* Open the file. Bail out if error occurs */ - f = fopen(daemon_local->flags.pathToECUSoftwareVersion, "r"); - - if (f == NULL) { - /* Error level notice, because this might be deliberate choice */ - dlt_log(LOG_NOTICE, "Failed to open ECU Software version file.\n"); - return -1; + if (!file) { + return NULL; } /* Get the file size. Bail out if stat fails. */ - int fd = fileno(f); - struct stat s_buf; - + const int fd = fileno(file); + struct stat s_buf = {0}; if (fstat(fd, &s_buf) < 0) { - dlt_log(LOG_WARNING, "Failed to stat ECU Software version file.\n"); - fclose(f); + dlt_log(LOG_WARNING, "failed to stat file size\n"); + fclose(file); return -1; } - /* Bail out if file is too large. Use DLT_DAEMON_TEXTBUFSIZE max. - * Reserve one byte for trailing '\0' */ - off_t size = s_buf.st_size; + /* Size limit includes NULL terminator. */ + const off_t size = s_buf.st_size; + if (size < 0 || size >= sizeLimit) { + dlt_log(LOG_WARNING, "file size invalid\n"); + fclose(file); + return NULL; + } - if (size >= DLT_DAEMON_TEXTBUFSIZE) { - dlt_log(LOG_WARNING, "Too large file for ECU version.\n"); - fclose(f); - return -1; + char* const string = malloc((size_t)size + 1); + if (!string) { + dlt_log(LOG_WARNING, "failed to allocate string for file contents\n"); + fclose(file); + return NULL; } - /* Allocate permanent buffer for version info */ - version = malloc((size_t) (size + 1)); + off_t offset = 0; + while (!feof(file)) { + offset += (off_t)fread(string + offset, 1, (size_t)size, file); - if (version == 0) { - dlt_log(LOG_WARNING, "Cannot allocate memory for ECU version.\n"); - fclose(f); - return -1; + if (ferror(file)) { + dlt_log(LOG_WARNING, "failed to read file\n"); + free(string); + fclose(file); + return NULL; + } + + if (offset > size) { + dlt_log(LOG_WARNING, "file too long for buffer\n"); + free(string); + fclose(file); + return NULL; + } } - off_t offset = 0; + string[offset] = '\0'; /* append null termination at end of string */ - while (!feof(f)) { - offset += (off_t) fread(version + offset, 1, (size_t) size, f); + return string; +} - if (ferror(f)) { - dlt_log(LOG_WARNING, "Failed to read ECU Software version file.\n"); - free(version); - fclose(f); - return -1; +static char* file_read_field(FILE* const file, const char* const fieldName) +{ + if (!file) { + return NULL; + } + + const char* const kDelimiters = "\r\n\"\'="; + const size_t fieldNameLen = strlen(fieldName); + + char* result = NULL; + + char* buffer = NULL; + ssize_t bufferSize = 0; + + while (true) { + ssize_t lineSize = getline(&buffer, &bufferSize, file); + if (lineSize < 0 || !buffer) { + /* end of file */ + break; } - if (offset > size) { - dlt_log(LOG_WARNING, "Too long file for ECU Software version info.\n"); - free(version); - fclose(f); - return -1; + char* line = buffer; + + /* trim trailing delimiters */ + while (lineSize >= 1 && strchr(kDelimiters, line[lineSize - 1]) != NULL) { + line[lineSize - 1] = '\0'; + --lineSize; + } + + /* check fieldName */ + if ( strncmp(line, fieldName, fieldNameLen) == 0 + && lineSize >= (fieldNameLen + 1) + && strchr(kDelimiters, line[fieldNameLen]) != NULL + ) { + /* trim fieldName */ + line += fieldNameLen; + + /* trim delimiter */ + ++line; + + /* trim leading delimiters */ + while (*line != '\0' && strchr(kDelimiters, *line) != NULL) { + ++line; + --lineSize; + } + + result = strdup(line); + break; } } - version[offset] = '\0';/*append null termination at end of version string */ - daemon->ECUVersionString = version; + free(buffer); + + return result; +} + +int dlt_daemon_local_ecu_version_init(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose) +{ + FILE *f = NULL; + + PRINT_FUNCTION_VERBOSE(verbose); + + /* By default, version string is null. */ + daemon->ECUVersionString = NULL; + + /* Open the file. Bail out if error occurs */ + f = fopen(daemon_local->flags.pathToECUSoftwareVersion, "r"); + + if (f == NULL) { + /* Error level notice, because this might be deliberate choice */ + dlt_log(LOG_NOTICE, "Failed to open ECU Software version file.\n"); + return -1; + } + + if (daemon_local->flags.ecuSoftwareVersionFileField[0] != '\0') { + daemon->ECUVersionString = file_read_field(f, daemon_local->flags.ecuSoftwareVersionFileField); + } else { + daemon->ECUVersionString = file_read_everything(f, DLT_DAEMON_TEXTBUFSIZE); + } + fclose(f); - return 0; + + return (daemon->ECUVersionString != NULL) ? 0 : -1; } void dlt_daemon_local_cleanup(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose) diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h index d4962244..a734802f 100644 --- a/src/daemon/dlt-daemon.h +++ b/src/daemon/dlt-daemon.h @@ -116,6 +116,7 @@ typedef struct int loggingFileMaxSize; /**< (int) Maximum size in bytes of all logging files (Default: 1000000) */ int sendECUSoftwareVersion; /**< (Boolean) Send ECU software version perdiodically */ char pathToECUSoftwareVersion[DLT_DAEMON_FLAG_MAX]; /**< (String: Filename) The file from which to read the ECU version from. */ + char ecuSoftwareVersionFileField[DLT_DAEMON_FLAG_MAX]; /**< Reads a specific VALUE from a FIELD=VALUE ECU version file. */ int sendTimezone; /**< (Boolean) Send Timezone perdiodically */ int offlineLogstorageMaxDevices; /**< (int) Maximum devices to be used as offline logstorage devices */ char offlineLogstorageDirPath[DLT_MOUNT_PATH_MAX]; /**< (String: Directory) DIR path to store offline logs */ diff --git a/src/daemon/dlt.conf b/src/daemon/dlt.conf index 6035de30..c5be1695 100644 --- a/src/daemon/dlt.conf +++ b/src/daemon/dlt.conf @@ -172,6 +172,9 @@ ControlSocketPath = /tmp/dlt-ctrl.sock # Absolute path to file storing version info - otherwise DLT version is used # PathToECUSoftwareVersion = +# Line prefix to read from software version file. Reads entire file if unset. +# ECUSoftwareVersionFileField = VERSION + ######################################################################## # Timezone info # ########################################################################