/** * Copyright (C) 2013 - 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 Syed Hameed ADIT 2013 - 2015 * \author Christoph Lipka ADIT 2015 * * \file: dlt_offline_logstorage.c * For further information see http://www.genivi.org/. */ #include #include #include #include #include #include #include #include #include #include #include #include "dlt_offline_logstorage.h" #include "dlt_offline_logstorage_internal.h" #include "dlt_offline_logstorage_behavior.h" #include "dlt_config_file_parser.h" #define DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR 1 #define DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR 2 #define DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE 3 #define GENERAL_BASE_NAME "General" DLT_STATIC void dlt_logstorage_filter_config_free(DltLogStorageFilterConfig *data) { DltLogStorageFileList *n = NULL; DltLogStorageFileList *n1 = NULL; free(data->apids); data->apids = NULL; free(data->ctids); data->ctids = NULL; free(data->file_name); data->file_name = NULL; if (data->ecuid != NULL) { free(data->ecuid); data->ecuid = NULL; } if (data->log != NULL) fclose(data->log); if (data->cache != NULL) { free(data->cache); data->cache = NULL; } n = data->records; while (n) { n1 = n; n = n->next; free(n1->name); n1->name = NULL; free(n1); n1 = NULL; } } /** * dlt_logstorage_list_destroy * * Destroy Filter configurations list. * * @param list List of the filter configurations will be destroyed. * @param uconfig User configurations for log file * @param dev_path Path to the device * @param reason Reason for the destroying of Filter configurations list * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_list_destroy(DltLogStorageFilterList **list, DltLogStorageUserConfig *uconfig, char *dev_path, int reason) { DltLogStorageFilterList *tmp = NULL; while (*(list) != NULL) { tmp = *list; *list = (*list)->next; if (tmp->key_list != NULL) { free(tmp->key_list); tmp->key_list = NULL; } if (tmp->data != NULL) { /* sync data if necessary */ /* ignore return value */ tmp->data->dlt_logstorage_sync(tmp->data, uconfig, dev_path, reason); dlt_logstorage_filter_config_free(tmp->data); free(tmp->data); tmp->data = NULL; } free(tmp); tmp = NULL; } return 0; } DLT_STATIC int dlt_logstorage_list_add_config(DltLogStorageFilterConfig *data, DltLogStorageFilterConfig **listdata) { if (*(listdata) == NULL) return -1; (*listdata)->apids = NULL; (*listdata)->ctids = NULL; (*listdata)->file_name = NULL; (*listdata)->ecuid = NULL; (*listdata)->records = NULL; (*listdata)->log = NULL; (*listdata)->cache = NULL; /* copy the data to list */ memcpy(*listdata, data, sizeof(DltLogStorageFilterConfig)); if (data->apids != NULL) (*listdata)->apids = strdup(data->apids); if (data->ctids != NULL) (*listdata)->ctids = strdup(data->ctids); if (data->file_name != NULL) (*listdata)->file_name = strdup(data->file_name); if (data->ecuid != NULL) (*listdata)->ecuid = strdup(data->ecuid); return 0; } /** * dlt_logstorage_list_add * * Add Filter configurations to the list. * * @param keys Keys will be added to the list. * @param num_keys Number of keys * @param data Filter configurations data will be added to the list. * @param list List of the filter configurations * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_list_add(char *keys, int num_keys, DltLogStorageFilterConfig *data, DltLogStorageFilterList **list) { DltLogStorageFilterList *tmp = NULL; while (*(list) != NULL) { list = &(*list)->next; } tmp = calloc(1, sizeof(DltLogStorageFilterList)); if (tmp == NULL) return -1; tmp->key_list = (char *)calloc( (num_keys * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN), sizeof(char)); if (tmp->key_list == NULL) { free(tmp); tmp = NULL; return -1; } memcpy(tmp->key_list, keys, num_keys * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN); tmp->num_keys = num_keys; tmp->next = NULL; tmp->data = calloc(1, sizeof(DltLogStorageFilterConfig)); if (tmp->data == NULL) { free(tmp->key_list); tmp->key_list = NULL; free(tmp); tmp = NULL; return -1; } if (dlt_logstorage_list_add_config(data, &(tmp->data)) != 0) { free(tmp->key_list); tmp->key_list = NULL; free(tmp->data); tmp->data = NULL; free(tmp); tmp = NULL; return -1; } *list = tmp; return 0; } /** * dlt_logstorage_list_find * * Find all Filter configurations corresponding with key provided. * * @param key Key to find the filter configurations * @param list List of the filter configurations * @param config Filter configurations corresponding with the key. * @return Number of the filter configuration found. */ DLT_STATIC int dlt_logstorage_list_find(char *key, DltLogStorageFilterList **list, DltLogStorageFilterConfig **config) { int i = 0; int num = 0; while (*(list) != NULL) { for (i = 0; i < (*list)->num_keys; i++) { if (strncmp(((*list)->key_list + (i * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN)), key, DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN) == 0) { config[num] = (*list)->data; num++; break; } } list = &(*list)->next; } return num; } /* Configuration file parsing helper functions */ DLT_STATIC int dlt_logstorage_count_ids(const char *str) { if (str == NULL) return -1; /* delimiter is: "," */ const char *p = str; int i = 0; int num = 1; while (p[i] != 0) { if (p[i] == ',') num++; i++; } return num; } /** * dlt_logstorage_free * * Free all allocated memory used in log storage handle * * @param handle DLT Logstorage handle * @param reason Reason for freeing the device * */ void dlt_logstorage_free(DltLogStorage *handle, int reason) { if (handle == NULL) { dlt_vlog(LOG_ERR, "%s failed: handle is NULL\n", __func__); return; } dlt_logstorage_list_destroy(&(handle->config_list), &handle->uconfig, handle->device_mount_point, reason); } /** * dlt_logstorage_read_list_of_names * * Evaluate app and ctx names given in config file and create a list of names * acceptable by DLT Daemon. When using SET_APPLICATION_NAME and SET_CONTEXT_NAME * there is no constraint that these names have max 4 characters. Internally, * these names are cutted down to max 4 chars. To have create valid keys, the * internal representation of these names has to be considered. * Therefore, a given configuration of "AppLogName = App1,Application2,A3" will * be stored as "App1,Appl,A3". * * @param names to store the list of names * @param value string given in config file * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_read_list_of_names(char **names, char *value) { int i = 0; int y = 0; int len = 0; char *tok; int num = 1; if ((names == NULL) || (value == NULL)) return -1; /* free, alloce'd memory to store new apid/ctid */ if (*names != NULL) { free(*names); *names = NULL; } len = strlen(value); if (len == 0) return -1; /* count number of delimiters to get actual number off names */ num = dlt_logstorage_count_ids(value); /* need to alloc space for 5 chars, 4 for the name and "," and "\0" */ *names = (char *)calloc(num * 5, sizeof(char)); if (*names == NULL) return -1; tok = strtok(value, ","); i = 1; while (tok != NULL) { len = strlen(tok); len = DLT_OFFLINE_LOGSTORAGE_MIN(len, 4); strncpy((*names + y), tok, len); if ((num > 1) && (i < num)) strncpy((*names + y + len), ",", 2); y += len + 1; i++; tok = strtok(NULL, ","); } return 0; } /** * dlt_logstorage_read_number * * Evaluate file size and number of files given in config file and set file size * The file number is checked by converting a string to an unsigned integer * width 0 > result < UINT_MAX (excludes 0!) * Non-digit characters including spaces and out of boundary will lead to an * error -1. * * @param number Number to be read * @param value string given in config file * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_read_number(unsigned int *number, char *value) { int i = 0; int len = 0; unsigned long size = 0; if (value == NULL) return -1; *number = 0; len = strlen(value); /* check if string consists of digits only */ for (i = 0; i < len; i++) if (!isdigit(value[i])) { dlt_log(LOG_ERR, "Invalid, is not a number \n"); return -1; } size = strtoul(value, NULL, 10); if ((size == 0) || (size > UINT_MAX)) { dlt_log(LOG_ERR, "Invalid, is not a number \n"); return -1; } *number = (unsigned int)size; return 0; } /** * dlt_logstorage_get_keys_list * * Obtain key list and number of keys for id list passed * after splitting it between seperator (,) * * @param ids ID's * @param sep Seperator * @param list Prepared key list is stored here * @param numids Number of keys in the list is stored here * @return: 0 on success, error on failure* */ DLT_STATIC int dlt_logstorage_get_keys_list(char *ids, char *sep, char **list, int *numids) { char *token = NULL; char *tmp_token = NULL; char *ids_local = NULL; *numids = 0; /* Duplicate the ids passed for using in strtok_r() */ ids_local = strdup(ids); if (ids_local == NULL) return -1; token = strtok_r(ids_local, sep, &tmp_token); if (token == NULL) { free(ids_local); return -1; } *list = (char *)calloc(DLT_OFFLINE_LOGSTORAGE_MAXIDS * (DLT_ID_SIZE + 1), sizeof(char)); if (*(list) == NULL) { free(ids_local); return -1; } while (token != NULL) { /* If it reached the max then other ids are ignored */ if (*numids >= DLT_OFFLINE_LOGSTORAGE_MAXIDS) { free(ids_local); return 0; } strncpy(((*list) + ((*numids) * (DLT_ID_SIZE + 1))), token, DLT_ID_SIZE); *numids = *numids + 1; token = strtok_r(NULL, sep, &tmp_token); } free(ids_local); return 0; } /** * dlt_logstorage_create_keys_only_ctid * * Prepares keys with context ID alone, will use ecuid if provided * (ecuid\:\:ctid) or (\:\:ctid) * * @param ecuid ECU ID * @param ctid Context ID * @param key Prepared key stored here * @return None */ DLT_STATIC void dlt_logstorage_create_keys_only_ctid(char *ecuid, char *ctid, char *key) { char curr_str[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 }; int curr_len = 0; if (ecuid != NULL) { strncpy(curr_str, ecuid, strlen(ecuid)); strncat(curr_str, "::", 2); } else { strncpy(curr_str, "::", 2); } curr_len = strlen(ctid); strncat(curr_str, ctid, curr_len); curr_len = strlen(curr_str); strncpy(key, curr_str, curr_len); } /** * dlt_logstorage_create_keys_only_apid * * Prepares keys with application ID alone, will use ecuid if provided * (ecuid:apid::) or (:apid::) * * @param ecuid ECU ID * @param apid Application ID * @param key Prepared key stored here * @return None */ DLT_STATIC void dlt_logstorage_create_keys_only_apid(char *ecuid, char *apid, char *key) { char curr_str[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 }; int curr_len = 0; if (ecuid != NULL) { strncpy(curr_str, ecuid, strlen(ecuid)); strncat(curr_str, ":", 1); } else { strncpy(curr_str, ":", 1); } curr_len = strlen(apid); strncat(curr_str, apid, curr_len); strncat(curr_str, ":", 1); curr_len = strlen(curr_str); strncpy(key, curr_str, curr_len); } /** * dlt_logstorage_create_keys_multi * * Prepares keys with apid, ctid (ecuid:apid:ctid), will use ecuid if is provided * (ecuid:apid:ctid) or (:apid:ctid) * * @param ecuid ECU ID * @param apid Application ID * @param ctid Context ID * @param key Prepared key stored here * @return None */ DLT_STATIC void dlt_logstorage_create_keys_multi(char *ecuid, char *apid, char *ctid, char *key) { char curr_str[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 }; int curr_len = 0; if (ecuid != NULL) { strncpy(curr_str, ecuid, strlen(ecuid)); strncat(curr_str, ":", 1); } else { strncpy(curr_str, ":", 1); } curr_len = strlen(apid); strncat(curr_str, apid, curr_len); strncat(curr_str, ":", 1); curr_len = strlen(ctid); strncat(curr_str, ctid, curr_len); curr_len = strlen(curr_str); strncpy(key, curr_str, curr_len); } /** * dlt_logstorage_create_keys_only_ecu * * Prepares keys with only ecuid (ecuid::) * * @param ecuid ECU ID * @param key Prepared key stored here * @return None */ DLT_STATIC void dlt_logstorage_create_keys_only_ecu(char *ecuid, char *key) { char curr_str[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 }; strncpy(curr_str, ecuid, strlen(ecuid)); strncat(curr_str, "::", 2); strncpy(key, curr_str, strlen(curr_str)); } /** * dlt_logstorage_create_keys * * Create keys for hash table * * From each section [filter] in offline logstorage configuration file, we * receive application and context id strings. * Application and context id can consist of * - a 4char long name * - a comma separated list of ids * - a wildcard: .* * * Not allowed is the combination of application id and context id set to * wildcard. This will be rejected. * * If lists given for application and/or context id, all possible combinations * are returned as keys in a form "[apid][ctid], e.g. "APP1\:CTX1". * If wildcards are used, the non-wildcard value becomes the key, e.g. "APP1\:" * or "\:CTX2". * * @param[in] apids string given from filter configuration * @param[in] ctids string given from filter configuration * @param[in] ecuid string given from filter configuration * @param[out] keys keys to fill into hash table * @param[out] num_keys number of keys * @return: 0 on success, error on failure* */ DLT_STATIC int dlt_logstorage_create_keys(char *apids, char *ctids, char *ecuid, char **keys, int *num_keys) { int i, j; int num_apids = 0; int num_ctids = 0; char *apid_list = NULL; char *ctid_list = NULL; char *curr_apid = NULL; char *curr_ctid = NULL; char curr_key[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 }; int num_currkey = 0; /* Handle ecuid alone case here */ if ((apids == NULL) && (ctids == NULL) && (ecuid != NULL)) { dlt_logstorage_create_keys_only_ecu(ecuid, curr_key); *(num_keys) = 1; *(keys) = (char *)calloc(*num_keys * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN, sizeof(char)); if (*(keys) == NULL) return -1; strncpy(*keys, curr_key, strlen(curr_key)); return 0; } if ((apids == NULL) || (ctids == NULL)) { dlt_log(LOG_ERR, "Required inputs (apid and ctid) are NULL\n"); return -1; } /* obtain key list and number of keys for application ids */ if (dlt_logstorage_get_keys_list(apids, ",", &apid_list, &num_apids) != 0) { dlt_log(LOG_ERR, "Failed to obtain apid, check configuration file \n"); return -1; } /* obtain key list and number of keys for context ids */ if (dlt_logstorage_get_keys_list(ctids, ",", &ctid_list, &num_ctids) != 0) { dlt_log(LOG_ERR, "Failed to obtain ctid, check configuration file \n"); free(apid_list); return -1; } *(num_keys) = num_apids * num_ctids; /* allocate memory for needed number of keys */ *(keys) = (char *)calloc(*num_keys * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN, sizeof(char)); if (*(keys) == NULL) { free(apid_list); free(ctid_list); return -1; } /* store all combinations of apid ctid in keys */ for (i = 0; i < num_apids; i++) { curr_apid = apid_list + (i * (DLT_ID_SIZE + 1)); for (j = 0; j < num_ctids; j++) { curr_ctid = ctid_list + (j * (DLT_ID_SIZE + 1)); if (strncmp(curr_apid, ".*", 2) == 0) /* only context id matters */ dlt_logstorage_create_keys_only_ctid(ecuid, curr_ctid, curr_key); else if (strncmp(curr_ctid, ".*", 2) == 0) /* only app id matters*/ dlt_logstorage_create_keys_only_apid(ecuid, curr_apid, curr_key); else /* key is combination of all */ dlt_logstorage_create_keys_multi(ecuid, curr_apid, curr_ctid, curr_key); strncpy((*keys + (num_currkey * DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN)), curr_key, strlen(curr_key)); num_currkey += 1; memset(&curr_key[0], 0, sizeof(curr_key)); } } free(apid_list); free(ctid_list); return 0; } /** * dlt_logstorage_prepare_table * * Prepares hash table with keys and data * * @param handle DLT Logstorage handle * @param data Holds all other configuration values * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_prepare_table(DltLogStorage *handle, DltLogStorageFilterConfig *data) { int ret = 0; int num_keys = 0; char *keys = NULL; if ((handle == NULL) || (data == NULL)) { dlt_vlog(LOG_ERR, "Invalid parameters in %s\n", __func__); return -1; } ret = dlt_logstorage_create_keys(data->apids, data->ctids, data->ecuid, &keys, &num_keys); if (ret != 0) { dlt_log(LOG_ERR, "Not able to create keys for hash table\n"); return -1; } /* hash_add */ if (dlt_logstorage_list_add(keys, num_keys, data, &(handle->config_list)) != 0) { dlt_log(LOG_ERR, "Adding to hash table failed, returning failure\n"); dlt_logstorage_free(handle, DLT_LOGSTORAGE_SYNC_ON_ERROR); free(keys); keys = NULL; return -1; } free(keys); keys = NULL; return 0; } /** * dlt_logstorage_validate_filter_name * * Validates if the provided filter name is as required [FILTER] * * @param name Filter name * @return 0 on success, -1 on error * */ DLT_STATIC int dlt_logstorage_validate_filter_name(char *name) { int len = 0; int idx = 0; int config_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION); int storage_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_STORAGE_SECTION); int control_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_CONTROL_SECTION); if (name == NULL) return -1; len = strlen(name); /* Check if section header is of format "FILTER" followed by a number */ if (strncmp(name, DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION, config_sec_len) == 0) { for (idx = config_sec_len; idx < len - 1; idx++) if (!isdigit(name[idx])) return -1; return 0; } /* Check if section header is of format "FILTER" followed by a number */ else if (strncmp(name, DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_STORAGE_SECTION, storage_sec_len) == 0) { for (idx = storage_sec_len; idx < len - 1; idx++) if (!isdigit(name[idx])) return -1; return 0; } /* Check if section header is of format "FILTER" followed by a number */ else if (strncmp(name, DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_CONTROL_SECTION, control_sec_len) == 0) { for (idx = control_sec_len; idx < len - 1; idx++) if (!isdigit(name[idx])) return -1; return 0; } else { return -1; } } DLT_STATIC void dlt_logstorage_filter_set_strategy(DltLogStorageFilterConfig *config, int strategy) { if (config == NULL) return; /* file based */ if ((strategy == DLT_LOGSTORAGE_SYNC_ON_MSG) || (strategy == DLT_LOGSTORAGE_SYNC_UNSET)) { 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; } else { /* cache based */ config->dlt_logstorage_prepare = &dlt_logstorage_prepare_msg_cache; config->dlt_logstorage_write = &dlt_logstorage_write_msg_cache; config->dlt_logstorage_sync = &dlt_logstorage_sync_msg_cache; } } DLT_STATIC int dlt_logstorage_check_apids(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) { dlt_log(LOG_ERR, "Not able to create keys for hash table\n"); return -1; } return dlt_logstorage_read_list_of_names(&config->apids, value); } DLT_STATIC int dlt_logstorage_check_ctids(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; return dlt_logstorage_read_list_of_names(&config->ctids, value); } DLT_STATIC int dlt_logstorage_check_loglevel(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; if (value == NULL) { config->log_level = 0; return -1; } if (strcmp(value, "DLT_LOG_FATAL") == 0) { config->log_level = 1; } else if (strcmp(value, "DLT_LOG_ERROR") == 0) { config->log_level = 2; } else if (strcmp(value, "DLT_LOG_WARN") == 0) { config->log_level = 3; } else if (strcmp(value, "DLT_LOG_INFO") == 0) { config->log_level = 4; } else if (strcmp(value, "DLT_LOG_DEBUG") == 0) { config->log_level = 5; } else if (strcmp(value, "DLT_LOG_VERBOSE") == 0) { config->log_level = 6; } else { config->log_level = -1; dlt_log(LOG_ERR, "Invalid log level \n"); return -1; } return 0; } DLT_STATIC int dlt_logstorage_check_reset_loglevel(DltLogStorageFilterConfig *config, char *value) { if (config == NULL) return -1; if (value == NULL) { config->reset_log_level = 0; return -1; } if (strcmp(value, "DLT_LOG_OFF") == 0) { config->reset_log_level = DLT_LOG_OFF; } else if (strcmp(value, "DLT_LOG_FATAL") == 0) { config->reset_log_level = DLT_LOG_FATAL; } else if (strcmp(value, "DLT_LOG_ERROR") == 0) { config->reset_log_level = DLT_LOG_ERROR; } else if (strcmp(value, "DLT_LOG_WARN") == 0) { config->reset_log_level = DLT_LOG_WARN; } else if (strcmp(value, "DLT_LOG_INFO") == 0) { config->reset_log_level = DLT_LOG_INFO; } else if (strcmp(value, "DLT_LOG_DEBUG") == 0) { config->reset_log_level = DLT_LOG_DEBUG; } else if (strcmp(value, "DLT_LOG_VERBOSE") == 0) { config->reset_log_level = DLT_LOG_VERBOSE; } else { config->reset_log_level = -1; dlt_log(LOG_ERR, "Invalid log level \n"); return -1; } return 0; } DLT_STATIC int dlt_logstorage_check_filename(DltLogStorageFilterConfig *config, char *value) { int len; if ((value == NULL) || (strcmp(value, "") == 0)) return -1; if (config->file_name != NULL) { free(config->file_name); config->file_name = NULL; } len = strlen(value); /* do not allow the user to change directory by adding a relative path */ if (strstr(value, "..") == NULL) { config->file_name = calloc((len + 1), sizeof(char)); if (config->file_name == NULL) { dlt_log(LOG_ERR, "Cannot allocate memory for filename\n"); return -1; } strncpy(config->file_name, value, len); } else { dlt_log(LOG_ERR, "Invalid filename, paths not accepted due to security issues\n"); return -1; } return 0; } DLT_STATIC int dlt_logstorage_check_filesize(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; return dlt_logstorage_read_number(&config->file_size, value); } DLT_STATIC int dlt_logstorage_check_nofiles(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; return dlt_logstorage_read_number(&config->num_files, value); } DLT_STATIC int dlt_logstorage_check_specificsize(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; return dlt_logstorage_read_number(&config->specific_size, value); } /** * dlt_logstorage_check_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 config DltLogStorageFilterConfig * @param value string given in config file * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_check_sync_strategy(DltLogStorageFilterConfig *config, char *value) { if ((config == NULL) || (value == NULL)) return -1; if (strcasestr(value, "ON_MSG") != NULL) { config->sync = DLT_LOGSTORAGE_SYNC_ON_MSG; dlt_log(LOG_DEBUG, "ON_MSG found, ignore other if added\n"); } else { /* ON_MSG not set, combination of cache based strategies possible */ if (strcasestr(value, "ON_DAEMON_EXIT") != NULL) config->sync |= DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT; if (strcasestr(value, "ON_DEMAND") != NULL) config->sync |= DLT_LOGSTORAGE_SYNC_ON_DEMAND; if (strcasestr(value, "ON_DEVICE_DISCONNECT") != NULL) config->sync |= DLT_LOGSTORAGE_SYNC_ON_DEVICE_DISCONNECT; if (strcasestr(value, "ON_SPECIFIC_SIZE") != NULL) config->sync |= DLT_LOGSTORAGE_SYNC_ON_SPECIFIC_SIZE; if (strcasestr(value, "ON_FILE_SIZE") != NULL) config->sync |= DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE; if (config->sync == 0) { dlt_log(LOG_WARNING, "Unknown sync strategies. Set default ON_MSG\n"); config->sync = DLT_LOGSTORAGE_SYNC_ON_MSG; return 1; } } return 0; } /** * dlt_logstorage_check_ecuid * * Evaluate if ECU idenfifier given in config file * * @param config DltLogStorageFilterConfig * @param value string given in config file * @return 0 on success, -1 on error */ DLT_STATIC int dlt_logstorage_check_ecuid(DltLogStorageFilterConfig *config, char *value) { int len; if ((config == NULL) || (value == NULL) || (value[0] == '\0')) return -1; if (config->ecuid != NULL) { free(config->ecuid); config->ecuid = NULL; } len = strlen(value); config->ecuid = calloc((len + 1), sizeof(char)); if (config->ecuid == NULL) return -1; strncpy(config->ecuid, value, len); return 0; } DLT_STATIC DltLogstorageFilterConf filter_cfg_entries[DLT_LOGSTORAGE_FILTER_CONF_COUNT] = { [DLT_LOGSTORAGE_FILTER_CONF_LOGAPPNAME] = { .key = "LogAppName", .func = dlt_logstorage_check_apids, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_CONTEXTNAME] = { .key = "ContextName", .func = dlt_logstorage_check_ctids, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_LOGLEVEL] = { .key = "LogLevel", .func = dlt_logstorage_check_loglevel, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_RESET_LOGLEVEL] = { .key = NULL, .func = dlt_logstorage_check_reset_loglevel, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_FILE] = { .key = "File", .func = dlt_logstorage_check_filename, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_FILESIZE] = { .key = "FileSize", .func = dlt_logstorage_check_filesize, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_NOFILES] = { .key = "NOFiles", .func = dlt_logstorage_check_nofiles, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_SYNCBEHAVIOR] = { .key = "SyncBehavior", .func = dlt_logstorage_check_sync_strategy, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_ECUID] = { .key = "EcuID", .func = dlt_logstorage_check_ecuid, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_SPECIFIC_SIZE] = { .key = "SpecificSize", .func = dlt_logstorage_check_specificsize, .is_opt = 1 } }; /* */ DLT_STATIC DltLogstorageFilterConf filter_nonverbose_storage_entries[DLT_LOGSTORAGE_FILTER_CONF_COUNT] = { [DLT_LOGSTORAGE_FILTER_CONF_LOGAPPNAME] = { .key = NULL, .func = dlt_logstorage_check_apids, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_CONTEXTNAME] = { .key = NULL, .func = dlt_logstorage_check_ctids, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_LOGLEVEL] = { .key = NULL, .func = dlt_logstorage_check_loglevel, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_RESET_LOGLEVEL] = { .key = NULL, .func = NULL, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_FILE] = { .key = "File", .func = dlt_logstorage_check_filename, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_FILESIZE] = { .key = "FileSize", .func = dlt_logstorage_check_filesize, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_NOFILES] = { .key = "NOFiles", .func = dlt_logstorage_check_nofiles, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_SYNCBEHAVIOR] = { .key = NULL, .func = dlt_logstorage_check_sync_strategy, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_ECUID] = { .key = "EcuID", .func = dlt_logstorage_check_ecuid, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_SPECIFIC_SIZE] = { .key = NULL, .func = dlt_logstorage_check_specificsize, .is_opt = 1 } }; DLT_STATIC DltLogstorageFilterConf filter_nonverbose_control_entries[DLT_LOGSTORAGE_FILTER_CONF_COUNT] = { [DLT_LOGSTORAGE_FILTER_CONF_LOGAPPNAME] = { .key = "LogAppName", .func = dlt_logstorage_check_apids, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_CONTEXTNAME] = { .key = "ContextName", .func = dlt_logstorage_check_ctids, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_LOGLEVEL] = { .key = "LogLevel", .func = dlt_logstorage_check_loglevel, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_RESET_LOGLEVEL] = { .key = "ResetLogLevel", .func = dlt_logstorage_check_reset_loglevel, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_FILE] = { .key = NULL, .func = dlt_logstorage_check_filename, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_FILESIZE] = { .key = NULL, .func = dlt_logstorage_check_filesize, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_NOFILES] = { .key = NULL, .func = dlt_logstorage_check_nofiles, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_SYNCBEHAVIOR] = { .key = NULL, .func = dlt_logstorage_check_sync_strategy, .is_opt = 1 }, [DLT_LOGSTORAGE_FILTER_CONF_ECUID] = { .key = "EcuID", .func = dlt_logstorage_check_ecuid, .is_opt = 0 }, [DLT_LOGSTORAGE_FILTER_CONF_SPECIFIC_SIZE] = { .key = NULL, .func = dlt_logstorage_check_specificsize, .is_opt = 1 } }; /** * Check filter configuration parameter is valid. * * @param config DltLogStorageFilterConfig * @param ctype DltLogstorageFilterConfType * @param value specified property value from configuration file * @return 0 on success, -1 otherwise */ DLT_STATIC int dlt_logstorage_check_param(DltLogStorageFilterConfig *config, DltLogstorageFilterConfType ctype, char *value) { if ((config == NULL) || (value == NULL)) return -1; if (ctype < DLT_LOGSTORAGE_FILTER_CONF_COUNT) return filter_cfg_entries[ctype].func(config, value); return -1; } DLT_STATIC int dlt_logstorage_get_filter_value(DltConfigFile *config_file, char *sec_name, int index, char *value) { int ret = 0; int config_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION); int storage_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_STORAGE_SECTION); int control_sec_len = strlen(DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_CONTROL_SECTION); if ((config_file == NULL) || (sec_name == NULL)) return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; /* Branch based on section name, no complete string compare needed */ if (strncmp(sec_name, DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION, config_sec_len) == 0) { if (filter_cfg_entries[index].key != NULL) { ret = dlt_config_file_get_value(config_file, sec_name, filter_cfg_entries[index].key, value); if ((ret != 0) && (filter_cfg_entries[index].is_opt == 0)) { dlt_vlog(LOG_WARNING, "Invalid configuration in section: %s -> %s : %s\n", sec_name, filter_cfg_entries[index].key, value); return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; } if ((ret != 0) && (filter_cfg_entries[index].is_opt == 1)) { dlt_vlog(LOG_DEBUG, "Optional parameter %s not specified\n", filter_cfg_entries[index].key); return DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE; } } else { return DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE; } } else if (strncmp(sec_name, DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_STORAGE_SECTION, storage_sec_len) == 0) { if (filter_nonverbose_storage_entries[index].key != NULL) { if (dlt_config_file_get_value(config_file, sec_name, filter_nonverbose_storage_entries[index].key, value) != 0) { dlt_vlog(LOG_WARNING, "Invalid configuration in section: %s -> %s : %s\n", sec_name, filter_nonverbose_storage_entries[index].key, value); return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; } } else { return DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE; } } else if ((strncmp(sec_name, DLT_OFFLINE_LOGSTORAGE_NONVERBOSE_CONTROL_SECTION, control_sec_len) == 0)) { if (filter_nonverbose_control_entries[index].key != NULL) { if (dlt_config_file_get_value(config_file, sec_name, filter_nonverbose_control_entries[index].key, value) != 0) { dlt_vlog(LOG_WARNING, "Invalid configuration in section: %s -> %s : %s\n", sec_name, filter_nonverbose_control_entries[index].key, value); return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; } } else { return DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE; } } else { dlt_log(LOG_ERR, "Error: Section name not valid \n"); return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; } return 0; } DLT_STATIC int dlt_logstorage_setup_table(DltLogStorage *handle, DltLogStorageFilterConfig *tmp_data) { int ret = 0; /* 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, tmp_data); if (ret != 0) { dlt_vlog(LOG_ERR, "%s Error: Storing filter values failed\n", __func__); ret = DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR; } return ret; } /*Return : * DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR - On filter properties or value is not valid * DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR - On error while storing in hash table */ DLT_STATIC int dlt_daemon_offline_setup_filter_properties(DltLogStorage *handle, DltConfigFile *config_file, char *sec_name) { DltLogStorageFilterConfig tmp_data; char value[DLT_CONFIG_FILE_ENTRY_MAX_LEN + 1] = { '\0' }; int i = 0; int ret = 0; if ((handle == NULL) || (config_file == NULL) || (sec_name == NULL)) return DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR; memset(&tmp_data, 0, sizeof(DltLogStorageFilterConfig)); tmp_data.apids = NULL; tmp_data.ctids = NULL; tmp_data.file_name = NULL; tmp_data.ecuid = NULL; tmp_data.log_level = DLT_LOG_VERBOSE; tmp_data.reset_log_level = DLT_LOG_OFF; tmp_data.records = NULL; tmp_data.log = NULL; tmp_data.cache = NULL; for (i = 0; i < DLT_LOGSTORAGE_FILTER_CONF_COUNT; i++) { ret = dlt_logstorage_get_filter_value(config_file, sec_name, i, value); if (ret == DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR) return ret; if (ret == DLT_OFFLINE_LOGSTORAGE_FILTER_CONTINUE) continue; /* check value and store temporary */ ret = dlt_logstorage_check_param(&tmp_data, i, value); if (ret != 0) { if (tmp_data.apids != NULL) { free(tmp_data.apids); tmp_data.apids = NULL; } if (tmp_data.ctids != NULL) { free(tmp_data.ctids); tmp_data.ctids = NULL; } if (tmp_data.file_name != NULL) { free(tmp_data.file_name); tmp_data.file_name = NULL; } if (tmp_data.ecuid != NULL) { free(tmp_data.ecuid); tmp_data.ecuid = NULL; } return DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR; } } /* filter configuration is valid */ ret = dlt_logstorage_setup_table(handle, &tmp_data); if (ret != 0) { dlt_vlog(LOG_ERR, "%s Error: Storing filter values failed\n", __func__); ret = DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR; } else { /* move to next free filter configuration, if no error occurred */ handle->num_configs += 1; } /* free tmp_data */ dlt_logstorage_filter_config_free(&tmp_data); return ret; } /** * dlt_logstorage_store_filters * * This function reads the filter keys and values * and stores them into the hash map * * @param handle DLT Logstorage handle * @param config_file_name Configuration file name * @return 0 on success, -1 on error, 1 on warning * */ DLT_STATIC int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) { DltConfigFile *config = NULL; int sec = 0; int num_sec = 0; int ret = 0; /* we have to make sure that this function returns success if atleast one * filter configuration is valid and stored */ int valid = -1; if (config_file_name == NULL) { dlt_vlog(LOG_ERR, "%s unexpected parameter received\n", __func__); return -1; } config = dlt_config_file_init(config_file_name); if (config == NULL) { dlt_log(LOG_CRIT, "Failed to open filter configuration file\n"); return -1; } dlt_config_file_get_num_sections(config, &num_sec); for (sec = 0; sec < num_sec; sec++) { char sec_name[DLT_CONFIG_FILE_ENTRY_MAX_LEN + 1]; if (dlt_config_file_get_section_name(config, sec, sec_name) == -1) { dlt_log(LOG_CRIT, "Failed to read section name\n"); dlt_config_file_release(config); return -1; } if (strstr(sec_name, GENERAL_BASE_NAME) != NULL) { dlt_log(LOG_CRIT, "General configuration not supported \n"); continue; } else if (dlt_logstorage_validate_filter_name(sec_name) == 0) { ret = dlt_daemon_offline_setup_filter_properties(handle, config, sec_name); if (ret == DLT_OFFLINE_LOGSTORAGE_STORE_FILTER_ERROR) { break; } else if (ret == DLT_OFFLINE_LOGSTORAGE_FILTER_ERROR) { valid = 1; dlt_vlog(LOG_WARNING, "%s filter configuration is invalid \n", sec_name); /* Continue reading next filter section */ continue; } else /* Filter properties read and stored successfuly */ if (valid != 1) valid = 0; } else { /* unknown section */ dlt_vlog(LOG_WARNING, "Unknown section: %s", sec_name); } } dlt_config_file_release(config); return valid; } /** * dlt_logstorage_load_config * * Read dlt_logstorage.conf file and setup filters in hash table * Hash table key consists of "APID:CTID", e.g "APP1:CTX1". If * wildcards used for application id or context id, the hash table * key consists of none wildcard value, e.g. apid=.*, cxid=CTX1 * results in "CTX1". * * Combination of two wildcards is not allowed. * * @param handle DLT Logstorage handle * @return 0 on success, -1 on error, 1 on warning */ DLT_STATIC int dlt_logstorage_load_config(DltLogStorage *handle) { char config_file_name[PATH_MAX] = {0}; int ret = 0; /* Check if handle is NULL or already initialized or already configured */ if ((handle == NULL) || (handle->connection_type != DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED)) return -1; /* Check if this device config was already setup */ if (handle->config_status == DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE) { dlt_vlog(LOG_ERR, "%s: Device already configured. Send disconnect first.\n", __func__); return -1; } if (snprintf(config_file_name, PATH_MAX, "%s/%s", handle->device_mount_point, DLT_OFFLINE_LOGSTORAGE_CONFIG_FILE_NAME) < 0) { dlt_log(LOG_ERR, "Creating configuration file path string failed\n"); return -1; } config_file_name[PATH_MAX - 1] = 0; ret = dlt_logstorage_store_filters(handle, config_file_name); if (ret == 1) { handle->config_status = DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE; return 1; } else if (ret != 0) { dlt_log(LOG_ERR, "dlt_logstorage_load_config Error : Storing filters failed\n"); return -1; } handle->config_status = DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE; return 0; } /** * dlt_logstorage_device_connected * * Initializes DLT Offline Logstorage with respect to device status * * @param handle DLT Logstorage handle * @param mount_point Device mount path * @return 0 on success, -1 on error, 1 on warning */ int dlt_logstorage_device_connected(DltLogStorage *handle, char *mount_point) { if ((handle == NULL) || (mount_point == NULL)) { dlt_log(LOG_ERR, "Handle error \n"); return -1; } if (handle->connection_type == DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) { dlt_log(LOG_WARNING, "Device already connected. Send disconnect, connect request\n"); dlt_logstorage_device_disconnected( handle, DLT_LOGSTORAGE_SYNC_ON_DEVICE_DISCONNECT); } strncpy(handle->device_mount_point, mount_point, DLT_MOUNT_PATH_MAX); handle->device_mount_point[DLT_MOUNT_PATH_MAX] = 0; handle->connection_type = DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED; handle->config_status = 0; handle->write_errors = 0; handle->num_configs = 0; /* Setup logstorage with config file settings */ return dlt_logstorage_load_config(handle); } /** * dlt_logstorage_device_disconnected * * De-Initializes DLT Offline Logstorage with respect to device status * * @param handle DLT Logstorage handle * @param reason Reason for disconnect * @return 0 on success, -1 on error * */ int dlt_logstorage_device_disconnected(DltLogStorage *handle, int reason) { if (handle == NULL) return -1; /* If configuration loading was done, free it */ if (handle->config_status == DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE) dlt_logstorage_free(handle, reason); /* Reset all device status */ memset(handle->device_mount_point, 0, sizeof(char) * (DLT_MOUNT_PATH_MAX + 1)); handle->connection_type = DLT_OFFLINE_LOGSTORAGE_DEVICE_DISCONNECTED; handle->config_status = 0; handle->write_errors = 0; handle->num_configs = 0; return 0; } /** * dlt_logstorage_get_loglevel_by_key * * Obtain the log level for the provided key * This function can be used to obtain log level when the actual * key stored in the Hash map is availble with the caller * * @param handle DltLogstorage handle * @param key key to search for in Hash MAP * @return log level on success:, -1 on error */ int dlt_logstorage_get_loglevel_by_key(DltLogStorage *handle, char *key) { DltLogStorageFilterConfig *config[DLT_CONFIG_FILE_SECTIONS_MAX] = { 0 }; int num_configs = 0; int i = 0; int log_level = 0; /* Check if handle is NULL,already initialized or already configured */ if ((handle == NULL) || (key == NULL) || (handle->connection_type != DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) || (handle->config_status != DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE)) return -1; num_configs = dlt_logstorage_list_find(key, &(handle->config_list), config); if (num_configs == 0) { dlt_vlog(LOG_WARNING, "Configuration for key [%s] not found!\n", key); return -1; } else if (num_configs == 1) { if (config[0] != NULL) { log_level = config[0]->log_level; } } else { /** * Multiple configurations found, raise a warning to the user and go * for the more verbose one. */ dlt_vlog(LOG_WARNING, "Multiple configuration for key [%s] found," " return the highest log level!\n", key); for (i = 0; i < num_configs; i++) { if ((config[i] != NULL) && (config[i]->log_level > log_level)) { log_level = config[i]->log_level; } } } return log_level; } /** * dlt_logstorage_get_config * * Obtain the configuration data of all filters for provided apid and ctid * * @param handle DltLogStorage handle * @param config [out] Pointer to array of filter configurations * @param apid application id * @param ctid context id * @param ecuid ecu id * @return number of configurations found */ int dlt_logstorage_get_config(DltLogStorage *handle, DltLogStorageFilterConfig **config, char *apid, char *ctid, char *ecuid) { DltLogStorageFilterConfig **cur_config_ptr = NULL; char key[DLT_CONFIG_FILE_SECTIONS_MAX][DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN] = { { '\0' }, { '\0' }, { '\0' } }; int i = 0; int apid_len = 0; int ctid_len = 0; int ecuid_len = 0; int num_configs = 0; int num = 0; /* Check if handle is NULL,already initialized or already configured */ if ((handle == NULL) || (config == NULL) || (handle->connection_type != DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) || (handle->config_status != DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE) || (ecuid == NULL)) return 0; /* Prepare possible keys with * Possible combinations are * ecu:: * ecu:apid:ctid * :apid:ctid * ecu::ctid * ecu:apid: * ::ctid * :apid: */ ecuid_len = strlen(ecuid); if (ecuid_len > DLT_ID_SIZE) ecuid_len = DLT_ID_SIZE; if ((apid == NULL) && (ctid == NULL)) { /* ecu:: */ strncpy(key[0], ecuid, ecuid_len); strncat(key[0], ":", 1); strncat(key[0], ":", 1); num_configs = dlt_logstorage_list_find(key[0], &(handle->config_list), config); return num_configs; } apid_len = strlen(apid); if (apid_len > DLT_ID_SIZE) apid_len = DLT_ID_SIZE; ctid_len = strlen(ctid); if (ctid_len > DLT_ID_SIZE) ctid_len = DLT_ID_SIZE; /* :apid: */ strncpy(key[0], ":", 1); strncat(key[0], apid, apid_len); strncat(key[0], ":", 1); /* ::ctid */ strncpy(key[1], ":", 1); strncat(key[1], ":", 1); strncat(key[1], ctid, ctid_len); /* :apid:ctid */ strncpy(key[2], ":", 1); strncat(key[2], apid, apid_len); strncat(key[2], ":", 1); strncat(key[2], ctid, ctid_len); /* ecu:apid:ctid */ strncpy(key[3], ecuid, ecuid_len); strncat(key[3], ":", 1); strncat(key[3], apid, apid_len); strncat(key[3], ":", 1); strncat(key[3], ctid, ctid_len); /* ecu:apid: */ strncpy(key[4], ecuid, ecuid_len); strncat(key[4], ":", 1); strncat(key[4], apid, apid_len); strncat(key[4], ":", 1); /* ecu::ctid */ strncpy(key[5], ecuid, ecuid_len); strncat(key[5], ":", 1); strncat(key[5], ":", 1); strncat(key[5], ctid, ctid_len); /* ecu:: */ strncpy(key[6], ecuid, ecuid_len); strncat(key[6], ":", 1); strncat(key[6], ":", 1); /* Search the list three times with keys as -apid: , :ctid and apid:ctid */ for (i = 0; i < DLT_OFFLINE_LOGSTORAGE_MAX_POSSIBLE_KEYS; i++) { cur_config_ptr = &config[num_configs]; num = dlt_logstorage_list_find(key[i], &(handle->config_list), cur_config_ptr); num_configs += num; /* If all filter configurations matched, stop and return */ if (num_configs == handle->num_configs) { break; } } return num_configs; } /** * dlt_logstorage_filter * * Check if log message need to be stored in a certain device based on filter * config * - get all DltLogStorageFilterConfig from hash table possible by given * apid/ctid (apid:, :ctid, apid:ctid * - for each found structure, compare message log level with configured one * * @param handle DltLogStorage handle * @param config Pointer to array of filter configurations * @param apid application id * @param ctid context id * @param log_level Log level of message * @param ecuid EcuID given in the message * @return number of found configurations */ DLT_STATIC int dlt_logstorage_filter(DltLogStorage *handle, DltLogStorageFilterConfig **config, char *apid, char *ctid, char *ecuid, int log_level) { int i = 0; int num = 0; if ((handle == NULL) || (config == NULL) || (ecuid == NULL)) return -1; /* filter on names: find DltLogStorageFilterConfig structures */ num = dlt_logstorage_get_config(handle, config, apid, ctid, ecuid); if (num == 0) { dlt_log(LOG_DEBUG, "No valid filter configuration found\n"); return 0; } for (i = 0 ; i < num ; i++) { if (config[i] == NULL) continue; /* filter on log level */ if (log_level > config[i]->log_level) { config[i] = NULL; continue; } /* filter on ECU id only if EcuID is set */ if (config[i]->ecuid != NULL) { if (strncmp(ecuid, config[i]->ecuid, DLT_ID_SIZE) != 0) config[i] = NULL; } } return num; } /** * dlt_logstorage_write * * Write a message to one or more configured log files, based on filter * configuration. * * @param handle DltLogStorage handle * @param uconfig User configurations for log file * @param data1 Data buffer of message header * @param size1 Size of message header buffer * @param data2 Data buffer of extended message body * @param size2 Size of extended message body * @param data3 Data buffer of message body * @param size3 Size of message body * @return 0 on success or write errors < max write errors, -1 on error */ int dlt_logstorage_write(DltLogStorage *handle, DltLogStorageUserConfig *uconfig, unsigned char *data1, int size1, unsigned char *data2, int size2, unsigned char *data3, int size3) { DltLogStorageFilterConfig *config[DLT_CONFIG_FILE_SECTIONS_MAX] = { 0 }; int i = 0; int ret = 0; int num = 0; int err = 0; /* data2 contains DltStandardHeader, DltStandardHeaderExtra and * DltExtendedHeader. We are interested in ecuid, apid, ctid and loglevel */ DltExtendedHeader *extendedHeader = NULL; DltStandardHeaderExtra *extraHeader = NULL; DltStandardHeader *standardHeader = NULL; unsigned int standardHeaderExtraLen = sizeof(DltStandardHeaderExtra); unsigned int header_len = 0; int log_level = -1; if ((handle == NULL) || (uconfig == NULL) || (data1 == NULL) || (data2 == NULL) || (data3 == NULL) || (handle->connection_type != DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) || (handle->config_status != DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE)) return 0; /* Calculate real length of DltStandardHeaderExtra */ standardHeader = (DltStandardHeader *)data2; if (!DLT_IS_HTYP_WEID(standardHeader->htyp)) standardHeaderExtraLen -= DLT_ID_SIZE; if (!DLT_IS_HTYP_WSID(standardHeader->htyp)) standardHeaderExtraLen -= DLT_SIZE_WSID; if (!DLT_IS_HTYP_WTMS(standardHeader->htyp)) standardHeaderExtraLen -= DLT_SIZE_WTMS; extraHeader = (DltStandardHeaderExtra *)(data2 + sizeof(DltStandardHeader)); if (DLT_IS_HTYP_UEH(standardHeader->htyp)) { header_len = sizeof(DltStandardHeader) + sizeof(DltExtendedHeader) + standardHeaderExtraLen; /* check if size2 is big enough to contain expected DLT message header */ if ((unsigned int)size2 < header_len) { dlt_log(LOG_ERR, "DLT message header is too small\n"); return 0; } extendedHeader = (DltExtendedHeader *)(data2 + sizeof(DltStandardHeader) + standardHeaderExtraLen); log_level = DLT_GET_MSIN_MTIN(extendedHeader->msin); /* check if log message need to be stored in a certain device based on * filter configuration */ num = dlt_logstorage_filter(handle, config, extendedHeader->apid, extendedHeader->ctid, extraHeader->ecu, log_level); if ((num == 0) || (num == -1)) { dlt_log(LOG_DEBUG, "No valid filter configuration found!\n"); return 0; } } else { header_len = sizeof(DltStandardHeader) + standardHeaderExtraLen; /* check if size2 is big enough to contain expected DLT message header */ if ((unsigned int)size2 < header_len) { dlt_log(LOG_ERR, "DLT message header is too small (without extended header)\n"); return 0; } log_level = DLT_LOG_VERBOSE; /* check if log message need to be stored in a certain device based on * filter configuration */ num = dlt_logstorage_filter(handle, config, NULL, NULL, extraHeader->ecu, log_level); if ((num == 0) || (num == -1)) { dlt_log(LOG_DEBUG, "No valid filter configuration found!\n"); return 0; } } /* store log message in every found filter */ for (i = 0; i < num; i++) { if (config[i] == NULL) continue; /* If file name is not present, the filter is non verbose control filter * hence skip storing */ if (config[i]->file_name == NULL) continue; /* prepare log file (create and/or open)*/ ret = config[i]->dlt_logstorage_prepare(config[i], uconfig, handle->device_mount_point, size1 + size2 + size3); if (ret == 0) { /* log data (write) */ ret = config[i]->dlt_logstorage_write(config[i], uconfig, handle->device_mount_point, data1, size1, data2, size2, data3, size3); if (ret == 0) { /* flush to be sure log is stored on device */ ret = config[i]->dlt_logstorage_sync(config[i], uconfig, handle->device_mount_point, DLT_LOGSTORAGE_SYNC_ON_MSG); if (ret != 0) dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to sync.\n"); } else { handle->write_errors += 1; if (handle->write_errors >= DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS) err = -1; dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to write.\n"); } } else { dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to prepare.\n"); } } return err; } /** * dlt_logstorage_sync_caches * * Write Cache data to file * * @param handle DltLogStorage handle * @return 0 on success, -1 on error */ int dlt_logstorage_sync_caches(DltLogStorage *handle) { DltLogStorageFilterList **tmp = NULL; if (handle == NULL) return -1; tmp = &(handle->config_list); while (*(tmp) != NULL) { if ((*tmp)->data != NULL) { if ((*tmp)->data->dlt_logstorage_sync((*tmp)->data, &handle->uconfig, handle->device_mount_point, DLT_LOGSTORAGE_SYNC_ON_DEMAND) != 0) dlt_vlog(LOG_ERR, "%s: Sync failed. Continue with next cache.\n", __func__); } tmp = &(*tmp)->next; } return 0; }