diff options
author | Frederic Berat <fberat@de.adit-jv.com> | 2015-10-07 19:35:25 +0900 |
---|---|---|
committer | Lutz Helwing <lutz_helwing@mentor.com> | 2015-11-24 09:48:42 +0100 |
commit | 5574d46a4083d783a915688e0e05593b9558497b (patch) | |
tree | 27284c79587b1576703424fb68d71e09d552b259 /src | |
parent | 8ed28dc15429a736c8404d491ed73fd0b04235e2 (diff) | |
download | DLT-daemon-5574d46a4083d783a915688e0e05593b9558497b.tar.gz |
Control application: Control appliction to support offline log storage trigger
Features :
1. One shot trigger with path
2. Automounter based trigger
3. Udev based trigger
Signed-off-by: Frederic Berat <fberat@de.adit-jv.com>
Signed-off-by: Christoph Lipka <clipka@jp.adit-jv.com>
Signed-off-by: anitha.ba <anithaammaji.baggam@in.bosch.com>
Signed-off-by: S. Hameed <shameed@jp.adit-jv.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/console/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/console/dlt-control-common.c | 588 | ||||
-rw-r--r-- | src/console/dlt-control-common.h | 82 | ||||
-rw-r--r-- | src/console/logstorage/CMakeLists.txt | 41 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-common.c | 318 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-common.h | 83 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-ctrl.c | 551 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-ctrl.h | 30 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-list.c | 236 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-list.h | 33 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-prop.h | 72 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-udev.c | 448 | ||||
-rw-r--r-- | src/console/logstorage/dlt-logstorage-udev.h | 39 |
13 files changed, 2524 insertions, 0 deletions
diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt index fde3fe3..f0a036a 100644 --- a/src/console/CMakeLists.txt +++ b/src/console/CMakeLists.txt @@ -30,6 +30,9 @@ add_executable(dlt-control ${dlt_control_SRCS} ${dlt_most_SRCS}) target_link_libraries(dlt-control dlt ${EXPAT_LIBRARIES}) set_target_properties(dlt-control PROPERTIES LINKER_LANGUAGE C) +set(dlt_control_common_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dlt-control-common.c) +add_subdirectory( logstorage ) + install(TARGETS dlt-convert dlt-receive dlt-control RUNTIME DESTINATION bin COMPONENT base) diff --git a/src/console/dlt-control-common.c b/src/console/dlt-control-common.c new file mode 100644 index 0000000..c3d82cf --- /dev/null +++ b/src/console/dlt-control-common.c @@ -0,0 +1,588 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-control-common.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt-control-common.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** PURPOSE : ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** cl Christoph Lipka ADIT ** +** fb Frederic Berat ADIT ** +*******************************************************************************/ +#define pr_fmt(fmt) "Common control: "fmt + +#include <errno.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "dlt_common.h" +#include "dlt_protocol.h" +#include "dlt_client.h" + +#include "dlt-control-common.h" + +#define DLT_CTRL_APID "DLTC" +#define DLT_CTRL_CTID "DLTC" +#define DLT_CTRL_SOCK "/tmp/dlt-ctrl.sock" + +#define DLT_RECEIVE_TEXTBUFSIZE 1024 + +/** @brief Analyze the daemon answer + * + * This function as to be provided by the user of the connection. + * + * @param answer The textual answer of the daemon + * @param payload The daemons answer payload + * @param length The daemons answer payload length + * + * @return User defined. + */ +static int (*response_analyzer_cb)(char *, void *, int); + +static pthread_t daemon_connect_thread; +static DltClient client; +static int callback_return = -1; +static pthread_mutex_t answer_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t answer_cond = PTHREAD_COND_INITIALIZER; + +static int local_verbose; +static char local_ecuid[DLT_CTRL_ECUID_LEN]; /* Name of ECU */ +static long local_timeout; + +int get_verbosity(void) +{ + return local_verbose; +} + +void set_verbosity(int v) +{ + local_verbose = !!v; +} + +char *get_ecuid(void) +{ + return local_ecuid; +} + +void set_ecuid(char *ecuid) +{ + if (local_ecuid != ecuid) + { + memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN); + strncpy(local_ecuid, ecuid, DLT_CTRL_ECUID_LEN); + local_ecuid[DLT_CTRL_ECUID_LEN - 1] = '\0'; + } +} + +long get_timeout(void) +{ + return local_timeout; +} + +void set_timeout(long t) +{ + local_timeout = DLT_CTRL_TIMEOUT; + + if (t > 1) + { + local_timeout = t; + } + else + { + pr_error("Timeout to small. Set to default: %d", + DLT_CTRL_TIMEOUT); + } +} + +/** @brief Send a message to the daemon through the socket. + * + * The socket as to be opened and active before sending. + * + * @param sock The socket to send the message through + * @param msg The message to be send in DLT format. + * + * @return 0 on success, -1 otherwise. + */ +static int dlt_control_send_message_to_socket(int sock, DltMessage *msg) +{ + if (send(sock, + (const char *)(msg->headerbuffer + sizeof(DltStorageHeader)), + msg->headersize - sizeof(DltStorageHeader), 0) == -1) + { + pr_error("Sending message header failed: %s\n", strerror(errno)); + return -1; + } + + if (send(sock, (const char *) msg->databuffer, msg->datasize, 0) == -1) + { + pr_error("Sending message failed: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +/** @brief Prepare the extra headers of a DLT message + * + * Modifies the extra headers of the message so that it can be sent. + * + * @param msg The message to be prepared + * @param header The base header to be used. + * + * @return 0 on success, -1 otherwise. + */ +static int prepare_extra_headers(DltMessage *msg, uint8_t *header) +{ + int shift = 0; + + pr_verbose("Preparing extra headers.\n"); + + if (!msg || !header) + { + return -1; + } + + shift = sizeof(DltStorageHeader) + + sizeof(DltStandardHeader) + + DLT_STANDARD_HEADER_EXTRA_SIZE(msg->standardheader->htyp); + + /* Set header extra parameters */ + dlt_set_id(msg->headerextra.ecu, get_ecuid()); + + msg->headerextra.tmsp = dlt_uptime(); + + /* Copy header extra parameters to header buffer */ + if (dlt_message_set_extraparameters(msg, get_verbosity()) == -1) + { + pr_error("Cannot copy header extra parameter\n"); + return -1; + } + + /* prepare extended header */ + msg->extendedheader = (DltExtendedHeader *)(header + shift); + + msg->extendedheader->msin = DLT_MSIN_CONTROL_REQUEST; + + msg->extendedheader->noar = 1; /* one payload packet */ + + /* Dummy values have to be set */ + dlt_set_id(msg->extendedheader->apid, DLT_CTRL_APID); + dlt_set_id(msg->extendedheader->ctid, DLT_CTRL_CTID); + + return 0; +} + +/** @brief Prepare the headers of a DLT message + * + * Modifies the headers of the message so that it can be sent. + * + * @param msg The message to be prepared + * @param header The base header to be used. + * + * @return 0 on success, -1 otherwise. + */ +static int prepare_headers(DltMessage *msg, uint8_t *header) +{ + uint32_t len = 0; + + pr_verbose("Preparing headers.\n"); + + if (!msg || !header) + { + return -1; + } + + msg->storageheader = (DltStorageHeader *) header; + + if (dlt_set_storageheader(msg->storageheader, "") == -1) + { + pr_error("Storage header initialization failed.\n"); + return -1; + } + + /* prepare standard header */ + msg->standardheader = + (DltStandardHeader *) (header + sizeof(DltStorageHeader)); + + msg->standardheader->htyp = DLT_HTYP_WEID | + DLT_HTYP_WTMS | DLT_HTYP_UEH | DLT_HTYP_PROTOCOL_VERSION1; + +#if (BYTE_ORDER == BIG_ENDIAN) + msg->standardheader->htyp = (msg->standardheader->htyp | DLT_HTYP_MSBF); +#endif + + msg->standardheader->mcnt = 0; + + /* prepare length information */ + msg->headersize = sizeof(DltStorageHeader) + + sizeof(DltStandardHeader) + + sizeof(DltExtendedHeader) + + DLT_STANDARD_HEADER_EXTRA_SIZE(msg->standardheader->htyp); + + len = msg->headersize - sizeof(DltStorageHeader) + msg->datasize; + + if (len > UINT16_MAX) + { + pr_error("Message header is too long.\n"); + return -1; + } + + msg->standardheader->len = DLT_HTOBE_16(len); + + return 0; +} + +/** @brief Prepare a DLT message. + * + * The DLT message is built using the data given by the user. + * The data is basically composed of a buffer and a size. + * + * @param data The message body to be used to build the DLT message. + * + * @return 0 on success, -1 otherwise. + */ +static DltMessage *dlt_control_prepare_message(DltControlMsgBody *data) +{ + DltMessage *msg = NULL; + + pr_verbose("Preparing message.\n"); + + if (data == NULL) + { + pr_error("Data for message body is NULL\n"); + return NULL; + } + + msg = calloc(1, sizeof(DltMessage)); + + if (msg == NULL) + { + pr_error("Cannot allocate memory for Dlt Message\n"); + return NULL; + } + + if (dlt_message_init(msg, get_verbosity()) == -1) + { + pr_error("Cannot initialize Dlt Message\n"); + free(msg); + return NULL; + } + + /* prepare payload of data */ + msg->databuffersize = msg->datasize = data->size; + + /* Allocate memory for Dlt Message's buffer */ + msg->databuffer = (uint8_t *)calloc(1, data->size); + + if (msg->databuffer == NULL) + { + pr_error("Cannot allocate memory for data buffer\n"); + free(msg); + return NULL; + } + + /* copy data into message */ + memcpy(msg->databuffer, data->data, data->size); + + /* prepare storage header */ + if (prepare_headers(msg, msg->headerbuffer)) + { + dlt_message_free(msg, get_verbosity()); + free(msg); + return NULL; + } + + /* prepare extra headers */ + if (prepare_extra_headers(msg, msg->headerbuffer)) + { + dlt_message_free(msg, get_verbosity()); + free(msg); + return NULL; + } + + return msg; +} + +/** @brief Initialize the connection with the daemon + * + * The connection is initialized using an internal callback. The user's + * response analyzer will be finally executed by this callback. + * The client pointer is used to established the connection. + * + * @param client A pointer to a valid client structure + * @param cb The internal callback to be executed while receiving a new message + * + * @return 0 on success, -1 otherwise. + */ +static int dlt_control_init_connection(DltClient *client, void *cb) +{ + int (*callback)(DltMessage *message, void *data) = cb; + + if (!cb || !client) + { + pr_error("%s Invalid parameters (%p, %p)\n", __func__, client, cb); + return -1; + } + + pr_verbose("Initializing the connection.\n"); + if (dlt_client_init(client, get_verbosity()) != 0) + { + pr_error("Failed to register callback (NULL)\n"); + return -1; + } + + dlt_client_register_message_callback(callback); + + client->socketPath = DLT_CTRL_SOCK; + client->mode = DLT_CLIENT_MODE_UNIX; + + return dlt_client_connect(client, get_verbosity()); +} + +/** @brief Daemon listener function + * + * This function will continuously read on the DLT socket, until an error occurs + * or the thread executing this function is canceled. + * + * @param data Thread parameter + * + * @return The thread parameter given as argument. + */ +static void *dlt_control_listen_to_daemon(void *data) +{ + pr_verbose("Ready to receive DLT answers.\n"); + dlt_client_main_loop(&client, NULL, get_verbosity()); + return data; +} + +/** @brief Internal callback for DLT response + * + * This function is called by the dlt_client_main_loop once a response is read + * from the DLT socket. + * After some basic checks, the user's response analyzer is called. The return + * value of the analyzer is then provided back to the dlt_control_send_message + * function to be given back as a return value. + * As this function is called in a dedicated thread, the return value is + * provided using a global variable. + * Access to this variable is controlled through a dedicated mutex. + * New values are signaled using a dedicated condition variable. + * + * @param message The DLT answer + * @data Unused + * + * @return The analyzer return value or -1 on early errors. + */ +static int dlt_control_callback(DltMessage *message, void *data) +{ + char text[DLT_RECEIVE_TEXTBUFSIZE] = { 0 }; + (void) data; + + if (message == NULL) + { + pr_error("Received message is null\n"); + return -1; + } + + /* prepare storage header */ + if (DLT_IS_HTYP_WEID(message->standardheader->htyp)) + { + dlt_set_storageheader(message->storageheader, message->headerextra.ecu); + } + else + { + dlt_set_storageheader(message->storageheader, "LCTL"); + } + + dlt_message_header(message, text, DLT_RECEIVE_TEXTBUFSIZE, get_verbosity()); + + /* Extracting payload */ + dlt_message_payload(message, text, + DLT_RECEIVE_TEXTBUFSIZE, + DLT_OUTPUT_ASCII, + get_verbosity()); + + /* + * Checking payload with the provided callback and return the result + */ + pthread_mutex_lock(&answer_lock); + callback_return = response_analyzer_cb(text, + message->databuffer, + message->datasize); + pthread_cond_signal(&answer_cond); + pthread_mutex_unlock(&answer_lock); + + return callback_return; +} + +/** @brief Send a message to the daemon and wait for the asynchronous answer. + * + * The answer is received and analyzed by a dedicated thread. Thus we need + * to wait for the signal from this thread and then read the return value + * to be provided to the user. + * In case of timeout, this function fails. + * The message provided by the user is formated in DLT format before sending. + * + * @param body The message provided by the user + * @param timeout The time to wait before considering that no answer will come + * + * @return The user response analyzer return value, -1 in case of early error. + */ +int dlt_control_send_message(DltControlMsgBody *body, int timeout) +{ + struct timespec t; + DltMessage *msg = NULL; + + if (!body) + { + pr_error("Invalid input (%p).\n", body); + return -1; + } + + if (clock_gettime(CLOCK_REALTIME, &t) == -1) + { + pr_error("Cannot read system time.\n"); + return -1; + } + + t.tv_sec += timeout; + + /* send command to daemon here */ + msg = dlt_control_prepare_message(body); + + if (msg == NULL) + { + pr_error("Control message preparation failed\n"); + return -1; + } + + pthread_mutex_lock(&answer_lock); + + /* Re-init the return value */ + callback_return = -1; + + if (dlt_control_send_message_to_socket(client.sock, msg) != 0) + { + pr_error("Sending message to daemon failed\n"); + free(msg); + return -1; + } + + /* If we timeout the lock is not taken back */ + if (!pthread_cond_timedwait(&answer_cond, &answer_lock, &t)) + { + pthread_mutex_unlock(&answer_lock); + } + + /* Destroying the message */ + dlt_message_free(msg, get_verbosity()); + free(msg); + + /* At this point either the value is already correct, either it's still -1. + * Then, we don't care to lock the access. + */ + return callback_return; +} + +/** @brief Control communication initialization + * + * This will prepare the DLT connection and the thread dedicated to the + * response listening. + * + * @param response_analyzer User defined function used to analyze the response + * @param ecuid The ECUID to provide to the daemon + * @param verbosity The verbosity level + * + * @return 0 on success, -1 otherwise. + */ +int dlt_control_init(int (*response_analyzer)(char *, void *, int), + char *ecuid, + int verbosity) +{ + if (!response_analyzer || !ecuid) + { + pr_error("Invalid input (%p %p).\n", response_analyzer, ecuid); + return -1; + } + + response_analyzer_cb = response_analyzer; + set_ecuid(ecuid); + set_verbosity(verbosity); + + if (dlt_control_init_connection(&client, dlt_control_callback) != 0) + { + pr_error("Connection initialization failed\n"); + dlt_client_cleanup(&client, get_verbosity()); + return -1; + } + + /* Contact DLT daemon */ + if (pthread_create(&daemon_connect_thread, + NULL, + dlt_control_listen_to_daemon, + NULL) != 0) + { + pr_error("Cannot create thread to communicate with DLT daemon.\n"); + return -1; + } + + return 0; +} + +/** @brief Control communication clean-up + * + * Cancels the listener thread and clean=up the dlt client structure. + * + * @return 0 on success, -1 otherwise. + */ +int dlt_control_deinit(void) +{ + /* Stopping the listener thread */ + pthread_cancel(daemon_connect_thread); + /* Closing the socket */ + return dlt_client_cleanup(&client, get_verbosity()); +} diff --git a/src/console/dlt-control-common.h b/src/console/dlt-control-common.h new file mode 100644 index 0000000..b8d712f --- /dev/null +++ b/src/console/dlt-control-common.h @@ -0,0 +1,82 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-control-common.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_CONTROL_COMMON_H_ +#define _DLT_CONTROL_COMMON_H_ + +#include <stdio.h> + +#include "dlt_common.h" + +#define DLT_CTRL_TIMEOUT 10 + +#define DLT_CTRL_ECUID_LEN 10 + +#ifndef pr_fmt +# define pr_fmt(fmt) fmt +#endif + +#ifndef USE_STDOUT +# define PRINT_OUT stderr +#else +# define PRINT_OUT stdout +#endif + +#define pr_error(fmt, ...) \ + ({ fprintf(PRINT_OUT, pr_fmt(fmt), ## __VA_ARGS__); fflush(PRINT_OUT); }) +#define pr_verbose(fmt, ...) \ + ({ if (get_verbosity()) { fprintf(PRINT_OUT, pr_fmt(fmt), ## __VA_ARGS__); fflush(PRINT_OUT); } }) + +#define DLT_CTRL_DEFAULT_ECUID "ECU1" + +/* To be used as Dlt Message body when sending to DLT daemon */ +typedef struct +{ + void *data; /**< data to be send to DLT Daemon */ + int size; /**< size of that data */ +} DltControlMsgBody; + +/* As verbosity, ecuid and timeout are needed during the communication, + * defining getter and setters here. + * Then there is no need to define them in the control's user application. + */ +int get_verbosity(void); +void set_verbosity(int); + +char *get_ecuid(void); +void set_ecuid(char *); + +long get_timeout(void); +void set_timeout(long); + +/* Initialize the connection to the daemon */ +int dlt_control_init(int (*response_analyser)(char *, void *, int), + char *ecuid, + int verbosity); + +/* Send a message to the daemon. The call is not thread safe. */ +int dlt_control_send_message(DltControlMsgBody *, int); + +/* Destroys the connection to the daemon */ +int dlt_control_deinit(void); +#endif diff --git a/src/console/logstorage/CMakeLists.txt b/src/console/logstorage/CMakeLists.txt new file mode 100644 index 0000000..830bf5a --- /dev/null +++ b/src/console/logstorage/CMakeLists.txt @@ -0,0 +1,41 @@ +####### +# @licence make begin@ +# SPDX license identifier: MPL-2.0 +# +# Copyright (C) 2015, ADIT 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 http://www.genivi.org/. +# @licence end@ +####### +add_definitions( -Werror ) + +if(WITH_DLT_LOGSTORAGE_CTRL_UDEV AND WITH_DLT_LOGSTORAGE_CTRL_PROP) + set(dlt_logstorage_ctrl_SRCS dlt-logstorage-ctrl.c dlt-logstorage-common.c dlt-logstorage-prop.c dlt-logstorage-udev.c dlt-logstorage-list.c) +elseif(WITH_DLT_LOGSTORAGE_CTRL_PROP) + set(dlt_logstorage_ctrl_SRCS dlt-logstorage-ctrl.c dlt-logstorage-common.c dlt-logstorage-prop.c dlt-logstorage-list.c) +elseif(WITH_DLT_LOGSTORAGE_CTRL_UDEV) + set(dlt_logstorage_ctrl_SRCS dlt-logstorage-ctrl.c dlt-logstorage-common.c dlt-logstorage-udev.c dlt-logstorage-list.c) +else(WITH_DLT_LOGSTORAGE_CTRL_UDEV) + set(dlt_logstorage_ctrl_SRCS dlt-logstorage-ctrl.c dlt-logstorage-common.c dlt-logstorage-list.c) +endif(WITH_DLT_LOGSTORAGE_CTRL_UDEV AND WITH_DLT_LOGSTORAGE_CTRL_PROP) + +add_executable(dlt-logstorage-ctrl ${dlt_logstorage_ctrl_SRCS} ${dlt_control_common_SRCS} ${dlt_most_SRCS} ${CMAKE_SOURCE_DIR}/systemd/3rdparty/sd-daemon.c ) + +if(WITH_DLT_LOGSTORAGE_CTRL_UDEV) + target_link_libraries(dlt-logstorage-ctrl dlt udev ${EXPAT_LIBRARIES}) +else(WITH_DLT_LOGSTORAGE_CTRL_UDEV) + target_link_libraries(dlt-logstorage-ctrl dlt ${EXPAT_LIBRARIES}) +endif(WITH_DLT_LOGSTORAGE_CTRL_UDEV) + +set_target_properties(dlt-logstorage-ctrl PROPERTIES LINKER_LANGUAGE C) + +install(TARGETS dlt-logstorage-ctrl + RUNTIME DESTINATION bin + COMPONENT base) diff --git a/src/console/logstorage/dlt-logstorage-common.c b/src/console/logstorage/dlt-logstorage-common.c new file mode 100644 index 0000000..a2f60a0 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-common.c @@ -0,0 +1,318 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \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 <shameed@jp.adit-jv.com> ADIT 2013 - 2015 + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-common.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt-logstorage-common.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** Frederic Berat fberat@de.adit-jv.com ** +** PURPOSE : ** +** ** +** REMARKS : Code extracted from dlt-control-common.c and reworked. ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** cl Christoph Lipka ADIT ** +** fb Frederic Berat ADIT ** +*******************************************************************************/ +#define pr_fmt(fmt) "Logstorage common: "fmt + +#include <errno.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "dlt_common.h" +#include "dlt_protocol.h" +#include "dlt_client.h" + +#include "dlt-control-common.h" +#include "dlt-logstorage-common.h" + +#ifdef DLT_LOGSTORAGE_CTRL_UDEV_ENABLE +#include "dlt-logstorage-udev.h" +#endif + +#include "dlt-logstorage-prop.h" + +static struct LogstorageOptions { + int event_type; /**< EVENT_UNMOUNTING/EVENT_MOUNTED */ + char device_path[DLT_MOUNT_PATH_MAX]; /**< Default Mount path */ + DltLogstorageHandler handler_type; /**< be controlled by udev or prop */ + long timeout; /**< Default timeout */ +} g_options = { + .event_type = EVENT_MOUNTED, + .handler_type = CTRL_NOHANDLER, +}; + +DltLogstorageHandler get_handler_type(void) +{ + return g_options.handler_type; +} + +void set_handler_type(char *type) +{ + g_options.handler_type = CTRL_UDEV; + + if (type && check_proprietary_handling(type)) + { + g_options.handler_type = CTRL_PROPRIETARY; + } +} + +int get_default_event_type(void) +{ + return g_options.event_type; +} + +void set_default_event_type(long type) +{ + g_options.event_type = !!type; +} + +char *get_default_path(void) +{ + return g_options.device_path; +} + +void set_default_path(char *path) +{ + memset(g_options.device_path, 0, DLT_MOUNT_PATH_MAX); + strncpy(g_options.device_path, path, DLT_MOUNT_PATH_MAX - 1); +} + +/* Used by the handlers */ +static DltLogstorageCtrl lctrl; + +DltLogstorageCtrl *get_logstorage_control(void) +{ + return &lctrl; +} + +void *dlt_logstorage_get_handler_cb(void) +{ + return lctrl.callback; +} + +int dlt_logstorage_get_handler_fd(void) +{ + return lctrl.fd; +} + +/** @brief Initialized the handler based on configuration + * + * @return 0 on success, -1 otherwise. + */ +int dlt_logstorage_init_handler(void) +{ + switch (get_handler_type()) + { + case CTRL_PROPRIETARY: + return dlt_logstorage_prop_init(); + case CTRL_UDEV: + default: +#ifdef DLT_LOGSTORAGE_CTRL_UDEV_ENABLE + return dlt_logstorage_udev_init(); +#else + return -1; +#endif + } +} + +/** @brief Clean-up the handler based on configuration + * + * @return 0 on success, -1 otherwise. + */ +int dlt_logstorage_deinit_handler(void) +{ + switch (get_handler_type()) + { + case CTRL_PROPRIETARY: + return dlt_logstorage_prop_deinit(); + case CTRL_UDEV: + default: +#ifdef DLT_LOGSTORAGE_CTRL_UDEV_ENABLE + return dlt_logstorage_udev_deinit(); +#else + return -1; +#endif + } +} + +/** @brief Search for config file in given mount point + * + * The file is searched at the top directory. The function exits once it + * founds it. + * + * @param mnt_point The mount point to check + * + * @return 1 if the file is found, 0 otherwise. + */ +int dlt_logstorage_check_config_file(char *mnt_point) +{ + struct dirent **files; + int n; + int i = 0; + int ret = 0; + + if ((mnt_point == NULL) || (mnt_point[0] == '\0')) + { + pr_error("Mount point missing.\n"); + return ret; + } + + pr_verbose("Now scanning %s\n", mnt_point); + + n = scandir(mnt_point, &files, NULL, alphasort); + + if (n <= 0) + { + pr_error("Cannot read mounted directory\n"); + return ret; + } + + do + { + pr_verbose("Checking %s.\n", files[i]->d_name); + + if (strncmp(files[i]->d_name, CONF_NAME, strlen(CONF_NAME)) == 0) + { + /* We found it ! */ + pr_verbose("File found.\n"); + ret = 1; + break; + } + } + while (++i < n); + + for (i = 0 ; i < n ; i++) + { + free(files[i]); + } + + free(files); + return ret; +} + +/** @brief Prepares the body of the message to be send to DLT + * + * @param body A pointer to the MsgBody structure pointer + * @param conn_type The type of the event (Mounted/Unmounting) + * @param path The mount point path. + * + * @return The body once built or NULL. + */ +static DltControlMsgBody *prepare_message_body(DltControlMsgBody **body, + int conn_type, + char *path) +{ + DltServiceOfflineLogstorage *serv = NULL; + + if (path == NULL) + { + pr_error("Mount path is uninitialized: %s\n", path); + return NULL; + } + + pr_verbose("Sending event %d for %s.\n", conn_type, path); + + *body = calloc(1, sizeof(DltControlMsgBody)); + + if (!*body) + { + pr_error("Not able to allocate memory for body.\n"); + return *body; + } + + (*body)->data = calloc(1, sizeof(DltServiceOfflineLogstorage)); + + if (!(*body)->data) + { + free(*body); + *body = NULL; + pr_error("Not able to allocate memory for body data.\n"); + return NULL; + } + + (*body)->size = sizeof(DltServiceOfflineLogstorage); + + serv = (DltServiceOfflineLogstorage *) (*body)->data; + + serv->service_id = DLT_SERVICE_ID_OFFLINE_LOGSTORAGE; + serv->connection_type = conn_type; + /* mount_point is DLT_MOUNT_PATH_MAX + 1 long, + * and the memory is already zeroed. + */ + strncpy(serv->mount_point, path, DLT_MOUNT_PATH_MAX); + + pr_verbose("Body is now ready.\n"); + + return *body; +} + +/** @brief Send a logstorage event to DLT + * + * @param type The type of the event (Mounted/Unmounting) + * @param mount_point The mount point for this event + * + * @return 0 On success, -1 otherwise. + */ +int dlt_logstorage_send_event(int type, char *mount_point) +{ + int ret = 0; + DltControlMsgBody *msg_body = NULL; + + /* mount_point is checked against NULL in the preparation */ + if (!prepare_message_body(&msg_body, type, mount_point)) + { + pr_error("Data for Dlt Message body is NULL\n"); + return -1; + } + + ret = dlt_control_send_message(msg_body, get_timeout()); + + free(msg_body->data); + free(msg_body); + + return ret; +} diff --git a/src/console/logstorage/dlt-logstorage-common.h b/src/console/logstorage/dlt-logstorage-common.h new file mode 100644 index 0000000..712f2e3 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-common.h @@ -0,0 +1,83 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \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 <shameed@jp.adit-jv.com> ADIT 2013 - 2015 + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-common.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_LOGSTORAGE_COMMON_H_ +#define _DLT_LOGSTORAGE_COMMON_H_ + +#define CONF_NAME "dlt_logstorage.conf" + +#define EVENT_UNMOUNTING 0 +#define EVENT_MOUNTED 1 + +typedef enum +{ + CTRL_NOHANDLER = 0, /**< one shot application */ + CTRL_UDEV, /**< Handles udev events */ + CTRL_PROPRIETARY /**< Handles proprietary event */ +} DltLogstorageHandler; + +DltLogstorageHandler get_handler_type(void); +void set_handler_type(char *); + +char *get_default_path(void); +void set_default_path(char *); + +int get_default_event_type(void); +void set_default_event_type(long type); + +typedef struct { + int fd; + int (*callback)(void); /* callback for event handling */ + void *prvt; /* Private data */ +} DltLogstorageCtrl; + +/* Get a reference to the logstorage control instance */ +DltLogstorageCtrl *get_logstorage_control(void); +void *dlt_logstorage_get_handler_cb(void); +int dlt_logstorage_get_handler_fd(void); +int dlt_logstorage_init_handler(void); +int dlt_logstorage_deinit_handler(void); + +/** + * Send an event to the dlt daemon + * + * @param type Event type (EVENT_UNMOUNTING/EVENT_MOUNTED) + * @param mount_point The mount point path concerned by this event + * + * @return 0 on success, -1 on error + */ +int dlt_logstorage_send_event(int, char *); + +/** @brief Search for config file in given mount point + * + * The file is searched at the top directory. The function exits once it + * founds it. + * + * @param mnt_point The mount point to check + * + * @return 1 if the file is found, 0 otherwise. + */ +int dlt_logstorage_check_config_file(char *); + +#endif diff --git a/src/console/logstorage/dlt-logstorage-ctrl.c b/src/console/logstorage/dlt-logstorage-ctrl.c new file mode 100644 index 0000000..b4d2b92 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-ctrl.c @@ -0,0 +1,551 @@ +/** + * @licence app begin@ + * 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. * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \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 <shameed@jp.adit-jv.com> ADIT 2013 - 2015 + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-ctrl.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ +/******************************************************************************* +** ** +** SRC-MODULE: dlt-logstorage-ctrl.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Syed Hameed shameed@jp.adit-jv.com ** +** Christoph Lipka clipka@jp.adit-jv.com ** +** AnithaAmmaji.baggam@in.bosch.com ** +** Frederic Berat fberat@de.adit-jv.com ** +** PURPOSE : ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** sh Syed Hameed ADIT ** +** cl Christoph Lipka ADIT ** +** BA Anitha BA ADIT ** +** fb Frederic Berat ADIT ** +*******************************************************************************/ + +#define pr_fmt(fmt) "Logstorage control: "fmt + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> + +#include <sys/epoll.h> + +#include "sd-daemon.h" + +#include "dlt_protocol.h" +#include "dlt_client.h" +#include "dlt-control-common.h" +#include "dlt-logstorage-common.h" +#include "dlt-logstorage-ctrl.h" + +#define EPOLL_MAX_EVENTS 10 +#define EPOLL_TIME_OUT 500 + +#define DLT_LOGSTORAGE_CTRL_EXIT 1 +static int must_exit; +static int efd; + +/** @brief Triggers the application exit + * + * The application will exit on next epoll timeout. + */ +void dlt_logstorage_exit(void) +{ + must_exit = DLT_LOGSTORAGE_CTRL_EXIT; +} + +/** @brief Check if the application must exit + * + * The application will exit on next epoll timeout. + */ +int dlt_logstorage_must_exit(void) +{ + return must_exit; +} + +/** @brief Signal handler. + * + * Triggers the exit of the application in case of specific signals + * + * @param signo The value of the signal received. + */ +static void catch_signal(int signo) +{ + if (signo) + { + pr_error("Signal %d received, exiting.", signo); + dlt_logstorage_exit(); + } +} + +/** @brief Install a handler for some signals + * + * Handler are installed on exit related signals. That allows to exit from + * the main loop gracefully. + */ +static void install_signal_handler(void) +{ + int signals[] = { SIGINT, SIGQUIT, SIGTERM, 0 }; + unsigned int i; + struct sigaction sa; + + pr_verbose("Installing signal handler.\n"); + + /* install a signal handler for the above listed signals */ + for (i = 0 ; signals[i] ; i++) + { + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = catch_signal; + + if (sigaction(signals[i], &sa, NULL) < 0) + { + pr_error("Failed to install signal %u handler. Error: %s\n", + signals[i], strerror(errno)); + } + } +} + +#define MAX_RESPONSE_LENGTH 32 +/** @brief Analyze the daemon answer to a request + * + * This function checks whether if the daemon answered positively to + * the request or not. + * + * @param data The textual answer + * @param payload The answer payload + * @param len The answer payload length + * @return 0 on success, -1 otherwise. + */ +static int analyze_response(char *data, void *payload, int len) +{ + int ret = -1; + char resp_ok[MAX_RESPONSE_LENGTH] = { 0 }; + + if (data == NULL || payload == NULL) + { + return -1; + } + + /* satisfy compiler */ + payload = payload; + len = len; + + snprintf(resp_ok, + MAX_RESPONSE_LENGTH, + "service(%u), ok", + DLT_SERVICE_ID_OFFLINE_LOGSTORAGE); + + if (strncmp(data, resp_ok, strlen(resp_ok)) == 0) + { + ret = 0; + } + + pr_verbose("Response received: '%s'\n", data); + pr_verbose("Response expected: '%s'\n", resp_ok); + + return ret; +} + +/** @brief Add a new event to watch to the epoll instance + * + * This function could be exported to be used by udev/prop so that they can + * register several events. + * There is no remove function as the removal is done on efd closure. + * + * @param fd The file descriptor to watch + * @param cb The callback to be called on event. + * + * @return epoll_ctrl return value, or -1 on earlier failure. + */ +static int dlt_logstorage_ctrl_add_event(int fd, void *cb) +{ + struct epoll_event event; + + if ((fd < 0) || !cb) + { + pr_error("Wrong parameter to add event (%d %p)\n", fd, cb); + return -1; + } + + pr_verbose("Setting up the event handler with (%d, %p).\n", fd, cb); + + event.data.ptr = cb; + event.events = EPOLLIN | EPOLLET; + + return epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event); +} + +/** @brief Main execution loop + * + * Waits on events from the epoll fd, and executes the callbacks retrieved + * back from the event structure. + * + * @return 0 on success, -1 otherwise. + */ +static int dlt_logstorage_ctrl_execute_event_loop(int efd) +{ + struct epoll_event *events; + int i; + int ret = 0; + int n = 0; + + events = calloc(10, sizeof(struct epoll_event)); + + if (!events) + { + pr_error("No memory available for events.\n"); + return -1; + } + + n = epoll_wait(efd, events, EPOLL_MAX_EVENTS, EPOLL_TIME_OUT); + + if (n < 0) + { + pr_error("epoll_wait error: %s\n", strerror(errno)); + + if (errno == EINTR) + { + /* Only exit if the daemon has received QUIT/INT/TERM */ + free(events); + return 0; + } + + free(events); + return -1; + } + + for (i = 0 ; i < n ; i++) + { + int (*callback)() = events[i].data.ptr; + + if (!(events[i].events & (EPOLLIN | EPOLLET))) + { + pr_error("Error while polling. Event received: 0x%x\n", + events[i].events); + /* We only support one event producer. + * Error means that this producer died. + */ + pr_error("Now closing fd and exiting.\n"); + close(events[i].data.fd); + dlt_logstorage_exit(); + ret = -1; + break; + } + + if (!callback) + { + pr_error("Callback not found, exiting.\n"); + dlt_logstorage_exit(); + ret = -1; + break; + } + + pr_verbose("Got new event, calling %p.\n", callback); + + if (callback() < 0) + { + pr_error("Error while calling the callback, exiting.\n"); + dlt_logstorage_exit(); + ret = -1; + break; + } + } + + free(events); + return ret; +} + +/** @brief Start event loop and receive messages from DLT. + * + * The function will first install the signal handler, + * then create the epoll instance, initialize the communication controller, + * initialize the event handler and finally start the polling. + * + * @return 0 on success, -1 on error + */ +static int dlt_logstorage_ctrl_setup_event_loop(void) +{ + int ret = 0; + + install_signal_handler(); + + pr_verbose("Creating epoll instance.\n"); + efd = epoll_create1(0); + + if (efd == -1) + { + pr_error("epoll_create error: %s\n", strerror(errno)); + dlt_logstorage_exit(); + return -errno; + } + + /* Initializing the communication with the daemon */ + while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) && + !dlt_logstorage_must_exit()) + { + pr_error("Failed to initialize connection with the daemon.\n"); + pr_error("Retrying to connect in %lds.\n", get_timeout()); + sleep(get_timeout()); + } + + if (dlt_logstorage_must_exit()) + { + pr_verbose("Exiting.\n"); + return 0; + } + + pr_verbose("Initializing event generator.\n"); + + if (dlt_logstorage_init_handler() < 0) + { + pr_error("Failed to initialize handler.\n"); + dlt_control_deinit(); + return -1; + } + + if (dlt_logstorage_ctrl_add_event(dlt_logstorage_get_handler_fd(), + dlt_logstorage_get_handler_cb()) < 0) + { + pr_error("epoll_ctl error: %s\n", strerror(errno)); + dlt_logstorage_exit(); + } + + while (!dlt_logstorage_must_exit() && (ret == 0)) + { + ret = dlt_logstorage_ctrl_execute_event_loop(efd); + } + + /* Clean up */ + close(efd); + + dlt_logstorage_deinit_handler(); + dlt_control_deinit(); + + return ret; +} + +/** @brief Send a single command to DLT daemon and wait for response + * + * @return 0 on success, -1 otherwise. + */ +static int dlt_logstorage_ctrl_single_request() +{ + int ret = 0; + /* Check if a 'CONF_NAME' file is present at the given path */ + if (!dlt_logstorage_check_config_file(get_default_path())) + { + pr_error("No '%s' file available at: %s\n", + CONF_NAME, + get_default_path()); + return -1; + } + + /* Initializing the communication with the daemon */ + while (dlt_control_init(analyze_response, get_ecuid(), get_verbosity()) && + !dlt_logstorage_must_exit()) + { + pr_error("Failed to initialize connection with the daemon.\n"); + pr_error("Retrying to connect in %lds.\n", get_timeout()); + sleep(get_timeout()); + } + + pr_verbose("event type is [%d]\t device path is [%s]\n", + get_default_event_type(), + get_default_path()); + + ret = dlt_logstorage_send_event(get_default_event_type(), + get_default_path()); + + dlt_control_deinit(); + + return ret; +} + +/** @brief Print out the application help + */ +static void usage(void) +{ + printf("Usage: dlt-logstorage-ctrl [options]\n"); + printf("Send a trigger to DLT daemon to connect/disconnect" + "a certain logstorage device\n"); + printf("\n"); + printf("Options:\n"); + printf(" -c Connection type: connect = 1, disconnect = 0\n"); + printf(" -d[prop] Run as daemon: prop = use proprietary handler\n"); + printf(" 'prop' may be replaced by any meaningful word\n"); + printf(" -e Set ECU ID (Default: %s)\n", DLT_CTRL_DEFAULT_ECUID); + printf(" -h Usage\n"); + printf(" -p Mount point path\n"); + printf(" -t Specify connection timeout (Default: %ds)\n", + DLT_CTRL_TIMEOUT); + printf(" -v Set verbose flag (Default:%d)\n", get_verbosity()); +} + +/** @brief Parses the application arguments + * + * The arguments are parsed and saved in static structure for future use. + * + * @param argc The amount of arguments + * @param argv The table of arguments + * + * @return 0 on success, -1 otherwise + */ +static int parse_args(int argc, char *argv[]) +{ + int c = -1; + + while ((c = getopt(argc, argv, ":t:he:p:d::c:v")) != -1) + { + switch (c) + { + case 't': + set_timeout(strtol(optarg, NULL, 10)); + break; + case 'h': + usage(); + return -1; + case 'e': + set_ecuid(optarg); + break; + case 'd': + pr_verbose("Choosing handler.\n"); + set_handler_type(optarg); + pr_verbose("Handler chosen: %d.\n", get_handler_type()); + break; + case 'p': + + if (strlen(optarg) >= DLT_MOUNT_PATH_MAX) + { + pr_error("Mount path '%s' too long\n", optarg); + return -1; + } + + set_default_path(optarg); + break; + case 'c': + set_default_event_type(strtol(optarg, NULL, 10)); + break; + case 'v': + set_verbosity(1); + pr_verbose("Now in verbose mode.\n"); + break; + case ':': + pr_error("Option -%c requires an argument.\n", optopt); + usage(); + return -1; + case '?': + + if (isprint(optopt)) + { + pr_error("Unknown option -%c.\n", optopt); + } + else + { + pr_error("Unknown option character \\x%x.\n", optopt); + } + + usage(); + return -1; + default: + pr_error("Try %s -h for more information.\n", argv[0]); + return -1; + } + } + + return 0; +} + +/** @brief Entry point + * + * Execute the argument parser and call the main feature accordingly. + * + * @param argc The amount of arguments + * @param argv The table of arguments + * + * @return 0 on success, -1 otherwise + */ +int main(int argc, char *argv[]) +{ + int ret = 0; + + set_ecuid(DLT_CTRL_DEFAULT_ECUID); + set_timeout(DLT_CTRL_TIMEOUT); + + /* Get command line arguments */ + if (parse_args(argc, argv) != 0) + { + return -1; + } + + /* all parameter valid, start communication with daemon or setup + * communication with control daemon */ + if (get_handler_type() == CTRL_NOHANDLER) + { + pr_verbose("One shot.\n"); + + ret = dlt_logstorage_ctrl_single_request(); + if (ret < 0) + { + pr_error("Message failed to be send. Please check DLT config.\n"); + } + } + else + { + pr_verbose("Entering in daemon mode.\n"); + + /* Let's daemonize */ + if (sd_notify(0, "READY=1") <= 0) + { + pr_verbose("SD notify failed, manually daemonizing.\n"); + + /* No message can be sent or Systemd is not available. + * Daemonizing manually. + */ + if (daemon(1, 1)) + { + pr_error("Failed to daemonize: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + } + + pr_verbose("Executing the event loop\n"); + ret = dlt_logstorage_ctrl_setup_event_loop(); + } + + pr_verbose("Exiting.\n"); + return ret; +} diff --git a/src/console/logstorage/dlt-logstorage-ctrl.h b/src/console/logstorage/dlt-logstorage-ctrl.h new file mode 100644 index 0000000..11abe10 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-ctrl.h @@ -0,0 +1,30 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \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 <shameed@jp.adit-jv.com> ADIT 2013 - 2015 + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-ctrl.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_LOGSTORAGE_CONTROL_H_ +#define _DLT_LOGSTORAGE_CONTROL_H_ + +/* Triggers the exit at the end of the event */ +void dlt_logstorage_exit(void); + +#endif diff --git a/src/console/logstorage/dlt-logstorage-list.c b/src/console/logstorage/dlt-logstorage-list.c new file mode 100644 index 0000000..0b7a8c0 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-list.c @@ -0,0 +1,236 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \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 Anitha.BA <anithaammaji.baggam@in.bosch.com> ADIT 2015 + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-list.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt-logstorage-list.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** Anitha.B.A anithaammaji.baggam@in.bosch.com ** +** Frederic Berat fberat@de.adit-jv.com ** +** ** +** PURPOSE : linked list implementation for storing the device info ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** BA Anitha ADIT ** +** cl Christoph Lipka ADIT ** +** fb Frederic Berat ADIT ** +*******************************************************************************/ +#define pr_fmt(fmt) "Log storage list: "fmt + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dlt_common.h" +#include "dlt-control-common.h" +#include "dlt-logstorage-common.h" + +static struct LogstorageDeviceInfo +{ + char *dev_node; /**< The device node */ + char *mnt_point; /**< Mount point for this device */ + struct LogstorageDeviceInfo *prev; /**< Previous element of the list */ + struct LogstorageDeviceInfo *next; /**< Next element of the list */ +} *g_info; + +/** @brief Prints the device list in verbose mode + * + * This can be used to debug the behavior. + * Therefore, it's only available in verbose mode. + */ +void print_list() +{ + struct LogstorageDeviceInfo *ptr = g_info; + pr_verbose(" -------Device list-------\n"); + + while (ptr != NULL) + { + pr_verbose("%p:\t[%s][%s] \n", ptr, ptr->dev_node, ptr->mnt_point); + ptr = ptr->next; + } + + pr_verbose(" -------Device list end-------\n\n"); + + return; +} + +/** @brief Find element in the list based on device node + * + * Allows to check whether a device is already in the list or + * to find out the one to be removed. + * + * @param node The device node to look for + * + * @return The element of the list found, NULL either. + */ +static struct LogstorageDeviceInfo *logstorage_find_dev_info(const char *node) +{ + struct LogstorageDeviceInfo *ptr = g_info; + + if (!node) + { + return NULL; + } + + pr_verbose("Looking for %s.\n", node); + + while (ptr != NULL) + { + if (strncmp(ptr->dev_node, node, DLT_MOUNT_PATH_MAX) == 0) + { + pr_verbose("%s found in %p.\n", node, ptr); + break; + } + else + { + ptr = ptr->next; + } + } + + return ptr; +} + +/** @brief Add new device in the list + * + * The device is only added if a configuration file has been found and + * if it's not already in the list. + * + * @param node The device node to add + * @param path The corresponding mount point path + * + * @return 0 on success, -1 in case of error. + */ +int logstorage_store_dev_info(const char *node, const char *path) +{ + struct LogstorageDeviceInfo *ptr = NULL; + + if ((node == NULL) || (path == NULL)) + { + pr_error("Invalid input\n"); + return -1; + } + + if (logstorage_find_dev_info(node)) + { + pr_verbose("%s already in list.\n", node); + print_list(); + return 0; + } + + ptr = calloc(1, sizeof(struct LogstorageDeviceInfo)); + + if (ptr == NULL) + { + pr_error("Node creation failed\n"); + return -1; + } + + ptr->dev_node = strdup(node); + ptr->mnt_point = strndup(path, DLT_MOUNT_PATH_MAX); + + /* Put it on head */ + ptr->next = g_info; + + if (g_info) + { + g_info->prev = ptr; + } + + g_info = ptr; + + pr_verbose("%s added to list.\n", node); + print_list(); + + return 0; +} + +/** @brief Remove a device from the list + * + * If the device is removed from the list, the mount point + * pointer is given back to the caller. That means that + * he has to free it. + * + * @param node The device node to be removed + * + * @return the mount point if the node is found, NULL either. + */ +char *logstorage_delete_dev_info(const char *node) +{ + struct LogstorageDeviceInfo *del = NULL; + char *ret = NULL; + + del = logstorage_find_dev_info(node); + + if (del == NULL) + { + pr_verbose("%s not found in list.\n", node); + print_list(); + return ret; + } + + /* Has to be freed by the caller */ + ret = del->mnt_point; + + if (del->prev) + { + del->prev->next = del->next; + } + + if (del->next) + { + del->next->prev = del->prev; + } + + if (del == g_info) + { + g_info = g_info->next; + } + + free(del->dev_node); + free(del); + + pr_verbose("%s removed from list.\n", node); + print_list(); + + return ret; +} diff --git a/src/console/logstorage/dlt-logstorage-list.h b/src/console/logstorage/dlt-logstorage-list.h new file mode 100644 index 0000000..3df2171 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-list.h @@ -0,0 +1,33 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka clipka@jp.adit-jv.com + * \author Anitha BA <anithaammaji.baggam@in.bosch.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-list.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_LOGSTORAGE_LIST_H_ +#define _DLT_LOGSTORAGE_LIST_H_ + +/* Return 0 it the node as been added (or is already present) */ +int logstorage_store_dev_info(const char *node, const char *path); +/* Returns the mount point if node has been found and deleted. NULL either */ +char *logstorage_delete_dev_info(const char *node); + +#endif diff --git a/src/console/logstorage/dlt-logstorage-prop.h b/src/console/logstorage/dlt-logstorage-prop.h new file mode 100644 index 0000000..836dc99 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-prop.h @@ -0,0 +1,72 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-udev.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_LOGSTORAGE_PROP_H_ +#define _DLT_LOGSTORAGE_PROP_H_ + +#ifndef HAS_PROPRIETARY_LOGSTORAGE +/** @brief Initialize proprietary connection + * + * @return 0 + */ +static inline int dlt_logstorage_prop_init(void) { + return 0; +} + +/** @brief Clean-up proprietary connection + * + * @return 0 + */ +static inline int dlt_logstorage_prop_deinit(void) { + return 0; +} + +/** @brief Check whether user wants to use proprietary handler + * + * @return 0 + */ +static inline int check_proprietary_handling(char *type) { + (void)type; return 0; +} +#else +/** + * Initialize proprietary connection + * + * @return 0 on success, -1 on error + */ +int dlt_logstorage_prop_init(void); + +/** + * Clean-up proprietary connection + * + * @return 0 on success, -1 on error + */ +int dlt_logstorage_prop_deinit(void); + +/** + * Check whether user wants to use proprietary event handler + * + * @return 1 if yes, 0 either. + */ +int check_proprietary_handling(char *); +#endif /* HAS_PROPRIETARY_LOGSTORAGE */ + +#endif /* _DLT_LOGSTORAGE_PROP_H_ */ diff --git a/src/console/logstorage/dlt-logstorage-udev.c b/src/console/logstorage/dlt-logstorage-udev.c new file mode 100644 index 0000000..355977e --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-udev.c @@ -0,0 +1,448 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-udev.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt-logstorage-udev.c ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** Frederic Berat fberat@de.adit-jv.com ** +** ** +** PURPOSE : For udev-based handling of any device ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** cl Christoph Lipka ADIT ** +** fb Frederic Berat ADIT ** +*******************************************************************************/ + +#define pr_fmt(fmt) "Udev control: "fmt + +#include <libudev.h> +#include <errno.h> +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/mount.h> + +#include "dlt-control-common.h" +#include "dlt-logstorage-common.h" +#include "dlt-logstorage-list.h" +#include "dlt-logstorage-udev.h" + +typedef struct { + struct udev *udev; /**< Udev instance */ + struct udev_monitor *mon; /**< Udev monitor instance */ +} LogstorageCtrlUdev; + +/** @brief Get mount point of a device node + * + * This function search for the mount point in /proc/mounts + * based on the device node. + * + * @param dev_node Device node as string + * + * @return mount path or NULL on error + */ +static char *dlt_logstorage_udev_get_mount_point(char *dev_node) +{ + struct mntent *ent; + FILE *f; + char *mnt_point = NULL; + + if (dev_node == NULL) + { + return NULL; + } + + f = setmntent("/proc/mounts", "r"); + + if (f == NULL) + { + pr_error("Cannot read /proc/mounts\n"); + return NULL; + } + + while (NULL != (ent = getmntent(f))) + { + if (strncmp(ent->mnt_fsname, dev_node, strlen(ent->mnt_fsname)) == 0) + { + mnt_point = strdup(ent->mnt_dir); + + /* Remounting rw */ + if (strlen(mnt_point)) + { + /* capabilities needed. Thus we don't really car on failure. + * Therefor we can ignore the return value. + */ + (void) mount(NULL, mnt_point, NULL, MS_REMOUNT, ent->mnt_opts); + } + + break; + } + } + + endmntent(f); + + return mnt_point; +} + +/** @brief Check if the daemon needs to be notified by the event + * + * On mount event: + * If the device mount point contains the DLT configuration file, + * the function will then send a message to the daemon. + * On Unmounting event: + * Check if the device was on the list, remove it and send the message + * to the daemon. + * + * @event The kind of event happening + * @part The device partition to be checked + * + * @return 0 on success, -1 if an error occured. + */ +static int check_mountpoint_from_partition(int event, struct udev_device *part) +{ + int logstorage_dev = 0; + char *mnt_point = NULL; + char *dev_node = NULL; + int ret = 0; + + if (!part) + { + pr_verbose("No partition structure given.\n"); + return -1; + } + + pr_verbose("Checking mount point.\n"); + + if (!udev_device_get_devnode(part)) + { + pr_verbose("Skipping as no devnode.\n"); + return 0; + } + + dev_node = strdup(udev_device_get_devnode(part)); + + if (event == EVENT_MOUNTED) + { + mnt_point = dlt_logstorage_udev_get_mount_point(dev_node); + logstorage_dev = dlt_logstorage_check_config_file(mnt_point); + + if (logstorage_dev) /* Configuration file available, add node to internal list */ + { + logstorage_store_dev_info(dev_node, mnt_point); + } + else + { + mnt_point = NULL; + } + } + else + { + /* remove device information */ + mnt_point = logstorage_delete_dev_info(dev_node); + } + + if (mnt_point) + { + ret = dlt_logstorage_send_event(event, mnt_point); + + if (ret) + { + pr_error("Can't send event for %s to DLT.\n", mnt_point); + } + } + + free(dev_node); + free(mnt_point); + + return 0; +} + +/** @brief Handles the udev events + * + * On event, it finds the corresponding action, and calls + * check_mountpoint_from_partition with the corresponding event. + * + * @return 0 on success, -1 on error. + */ +static int logstorage_udev_udevd_callback(void) +{ + const char *action; + int ret = 0; + DltLogstorageCtrl *lctrl = get_logstorage_control(); + LogstorageCtrlUdev *prvt = NULL; + struct udev_device *partition = NULL; + + if (!lctrl) + { + pr_error("Not able to get logstorage control instance.\n"); + return -1; + } + + prvt = (LogstorageCtrlUdev *)lctrl->prvt; + + if (!prvt || !prvt->mon) + { + pr_error("Not able to get private data.\n"); + return -1; + } + + partition = udev_monitor_receive_device(prvt->mon); + + if (!partition) + { + pr_error("Not able to get partition.\n"); + return -1; + } + + action = udev_device_get_action(partition); + + if (!action) + { + pr_error("Not able to get action.\n"); + udev_device_unref(partition); + return -1; + } + + pr_verbose("%s action received from udev for %s.\n", + action, + udev_device_get_devnode(partition)); + + if (strncmp(action, "add", sizeof("add")) == 0) + { + /*TODO: This can be replaced by polling on /proc/mount. + * we could get event on modification, and keep track on a list + * of mounted devices. New devices could be check that way. + * That also would solve the unmount event issue. + * Then, udev is only interesting to simplify the check on new devices, + * and/or for hot unplug (without unmount). + */ + usleep(500 * 1000); + ret = check_mountpoint_from_partition(EVENT_MOUNTED, partition); + } + else if (strncmp(action, "remove", sizeof("remove")) == 0) + { + ret = check_mountpoint_from_partition(EVENT_UNMOUNTING, partition); + } + + udev_device_unref(partition); + + return ret; +} + +/** @brief Check all partitions on the system to find configuration file + * + * The function looks for block devices that are of "partition" type. + * Then, it gets the node, and call check_mountpoint_from_partition with it. + * + * @udev The udev device used to find all the nodes + * + * @return 0 on success, -1 otherwise. + */ +static int dlt_logstorage_udev_check_mounted(struct udev *udev) +{ + /* Create a list of the devices in the 'partition' subsystem. */ + struct udev_enumerate *enumerate = udev_enumerate_new(udev); + struct udev_list_entry *devices = NULL; + struct udev_list_entry *dev_list_entry = NULL; + + if (!enumerate) + { + pr_error("Can't enumerate devices.\n"); + return -1; + } + + udev_enumerate_add_match_subsystem(enumerate, "block"); + udev_enumerate_add_match_property(enumerate, "DEVTYPE", "partition"); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + /* For each list entry, get the corresponding device */ + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path; + struct udev_device *partition = NULL; + + /* Get the filename of the /sys entry for the device + * and create a udev_device object representing it + */ + path = udev_list_entry_get_name(dev_list_entry); + partition = udev_device_new_from_syspath(udev, path); + + if (!partition) + { + continue; + } + + pr_verbose("Found device %s %s %s.\n", + path, + udev_device_get_devnode(partition), + udev_device_get_devtype(partition)); + + /* Check the device and clean-up */ + check_mountpoint_from_partition(EVENT_MOUNTED, partition); + udev_device_unref(partition); + } + + /* Free the enumerator object */ + udev_enumerate_unref(enumerate); + + return 0; +} + +/** @brief Clean-up the udev data + * + * That will destroy all the private data. + * + * @return 0 on success, -1 otherwise. + */ +int dlt_logstorage_udev_deinit(void) +{ + DltLogstorageCtrl *lctrl = get_logstorage_control(); + LogstorageCtrlUdev *prvt = NULL; + + if (!lctrl) + { + return -1; + } + + prvt = (LogstorageCtrlUdev *)lctrl->prvt; + + if (prvt->mon) + { + udev_monitor_unref(prvt->mon); + } + + if (prvt->udev) + { + udev_unref(prvt->udev); + } + + free(prvt); + lctrl->prvt = NULL; + + return 0; +} + +/** @brief Initialize the private data + * + * That function will create the udev device and monitor. + * + * @return 0 on success, -1 otherwise. + */ +int dlt_logstorage_udev_init(void) +{ + int ret = 0; + + DltLogstorageCtrl *lctrl = get_logstorage_control(); + LogstorageCtrlUdev *prvt = NULL; + + pr_verbose("Initializing.\n"); + + if (!lctrl) + { + pr_error("Not able to get logstorage control instance.\n"); + return -1; + } + + lctrl->prvt = calloc(1, sizeof(LogstorageCtrlUdev)); + + if (!lctrl->prvt) + { + pr_error("No memory to allocate private data.\n"); + return -1; + } + + prvt = (LogstorageCtrlUdev *)lctrl->prvt; + + /* Initialize udev object */ + prvt->udev = udev_new(); + + if (!prvt->udev) + { + pr_error("Cannot initialize udev object\n"); + dlt_logstorage_udev_deinit(); + return -1; + } + + /* setup udev monitor which will report events when + * devices attached to the system change. Events include + * "add", "remove", "change", etc */ + prvt->mon = udev_monitor_new_from_netlink(prvt->udev, "udev"); + + if (!prvt->mon) + { + pr_error("Cannot initialize udev monitor\n"); + dlt_logstorage_udev_deinit(); + return -1; + } + + ret = udev_monitor_filter_add_match_subsystem_devtype(prvt->mon, + "block", + NULL); + + if (ret) + { + pr_error("Cannot attach filter to monitor: %s.\n", strerror(-ret)); + dlt_logstorage_udev_deinit(); + return -1; + } + + ret = udev_monitor_enable_receiving(prvt->mon); + + if (ret < 0) + { + pr_error("Cannot start receiving: %s.\n", strerror(-ret)); + dlt_logstorage_udev_deinit(); + return -1; + } + + /* get file descriptor */ + lctrl->fd = udev_monitor_get_fd(prvt->mon); + /* set callback function */ + lctrl->callback = &logstorage_udev_udevd_callback; + + /* check if there is something already mounted */ + return dlt_logstorage_udev_check_mounted(prvt->udev); +} diff --git a/src/console/logstorage/dlt-logstorage-udev.h b/src/console/logstorage/dlt-logstorage-udev.h new file mode 100644 index 0000000..d202453 --- /dev/null +++ b/src/console/logstorage/dlt-logstorage-udev.h @@ -0,0 +1,39 @@ +/** + * @licence app begin@ + * 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. + * + * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Frederic Berat <fberat@de.adit-jv.com> ADIT 2015 + * + * \file dlt-logstorage-udev.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#ifndef _DLT_LOGSTORAGE_UDEV_H_ +#define _DLT_LOGSTORAGE_UDEV_H_ + +/** + * Initialize udev connection + * + * @return 0 on success, -1 on error + */ +int dlt_logstorage_udev_init(void); + +/** + * Clean-up udev connection + * + * @return 0 on success, -1 on error + */ +int dlt_logstorage_udev_deinit(void); + +#endif |