From c78d08d63f47ec2baa08c20f3068adbe8c3cc0ca Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Thi Date: Thu, 29 Nov 2018 16:30:32 +0100 Subject: slog2 adapter on QNX dlt-qnx-system can be used to send syslog on QNX to dlt-daemon using slog2 API. It was be built with setting cmake option WITH_DLT_QNX_SYSTEM to ON. Add markdown manual page for dlt-qnx-system Signed-off-by: Nguyen Dinh Thi (RBVH/ENG2) Signed-off-by: Le Hoang Ngoc Quynh Signed-off-by: Sebastian Unger Signed-off-by: Bui Nguyen Quoc Thanh Signed-off-by: Saya Sugiura Signed-off-by: Felix Herrmann --- CMakeLists.txt | 5 + README.md | 1 + doc/dlt-qnx-system.md | 102 ++++++ src/CMakeLists.txt | 4 + src/dlt-qnx-system/CMakeLists.txt | 33 ++ src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp | 251 ++++++++++++++ src/dlt-qnx-system/dlt-qnx-system.c | 433 ++++++++++++++++++++++++ src/dlt-qnx-system/dlt-qnx-system.conf | 25 ++ src/dlt-qnx-system/dlt-qnx-system.h | 109 ++++++ src/dlt-qnx-system/dlt-slog2ctxt.json | 14 + 10 files changed, 977 insertions(+) create mode 100644 doc/dlt-qnx-system.md create mode 100644 src/dlt-qnx-system/CMakeLists.txt create mode 100644 src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp create mode 100644 src/dlt-qnx-system/dlt-qnx-system.c create mode 100644 src/dlt-qnx-system/dlt-qnx-system.conf create mode 100644 src/dlt-qnx-system/dlt-qnx-system.h create mode 100644 src/dlt-qnx-system/dlt-slog2ctxt.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 710cb15..81fe9ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ option(WITH_DLT_SYSTEM "Set to ON to build src/system binaries" option(WITH_DLT_DBUS "Set to ON to build src/dbus binaries" OFF) option(WITH_DLT_TESTS "Set to ON to build src/test binaries" ON) option(WITH_DLT_UNIT_TESTS "Set to ON to build gtest framework and tests/binaries" OFF) +option(WITH_DLT_QNX_SYSTEM "Set to ON to build QNX system binary dlt-qnx-system" OFF) set(DLT_IPC "FIFO" CACHE STRING "UNIX_SOCKET,FIFO") set(DLT_USER "genivi" CACHE STRING "Set user for process not run as root") @@ -135,6 +136,9 @@ if(WITH_DLT_USE_IPv6) add_definitions(-DDLT_USE_IPv6) endif() +if(WITH_DLT_QNX_SYSTEM AND NOT "${CMAKE_C_COMPILER}" MATCHES "nto-qnx") + message(FATAL_ERROR "Can only compile for QNX with a QNX compiler.") +endif() if(WITH_GPROF) add_compile_options(-pg) @@ -271,6 +275,7 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}") message(STATUS "WITH_DLT_LOGSTORAGE_CTRL_UDEV = ${WITH_DLT_LOGSTORAGE_CTRL_UDEV}") message(STATUS "DLT_IPC = ${DLT_IPC}(Path: ${DLT_USER_IPC_PATH})") message(STATUS "WITH_UDP_CONNECTION = ${WITH_UDP_CONNECTION}") +message(STATUS "WITH_DLT_QNX_SYSTEM = ${WITH_DLT_QNX_SYSTEM})") message(STATUS "Change a value with: cmake -D=") message(STATUS "-------------------------------------------------------------------------------") message(STATUS) diff --git a/README.md b/README.md index 384ae5c..e70f787 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ make doc - [dlt-passive-node-ctrl(1)](doc/dlt-passive-node-ctrl.1.md) - [dlt-adaptor-stdin(1)](doc/dlt-adaptor-stdin.1.md) - [dlt-adaptor-udp(1)](doc/dlt-adaptor-udp.1.md) +- [dlt-qnx-system(1)](doc/dlt-qnx-system.md) The man pages are generated with *pandoc*. diff --git a/doc/dlt-qnx-system.md b/doc/dlt-qnx-system.md new file mode 100644 index 0000000..ffda347 --- /dev/null +++ b/doc/dlt-qnx-system.md @@ -0,0 +1,102 @@ +# dlt-qnx-system + +QNX specific logging features of dlt are managed by the ```dlt-qnx-system``` process. +It currently contains the message forwarder from slogger2 to DLT. + +The application listens to the system logs on QNX (slogger2) and sends them to +DLT. The prerequisite is that dlt-daemon is already started and running. +dlt-qnx-system loads by default the configuration file ```/etc/dlt-qnx-system.conf```. + +> In order to catch all logs via slog2, the syslog needs to forward to slogger2 in [syslog.conf](http://www.qnx.com/developers/docs/7.0.0/index.html#com.qnx.doc.neutrino.utilities/topic/s/syslog.conf.html). + +To change the log level, use application ID and context ID set in configuration +file. ```DLT_INITIAL_LOG_LEVEL``` can be set on startup phase, or control +message can be sent from DLT client (e.g. dlt-control, DLT Viewer) at runtime. +Refer to [dlt_for_developers.md](dlt_for_developers.md) for more detail. + + +## Usage + +```bash +dlt-qnx-system [-h] [-d] [-c FILENAME] +``` + +-h + +: Display a short help text. + +-d + +: Daemonize. Detach from Terminal and run in background. + +-c + +: Load an alternative configuration file. By default the configuration file + */etc/dlt-qnx-system.conf* is loaded. + + +Non zero is returned in case of failure. + + +## Configuration + +By default, the configuration is loaded from */etc/dlt-qnx-system.conf*. It +contains a few basic options: + +- *ApplicationId*: this QNX system log forwarder will have this application ID + and appear on DLT client. Default value is *QSYM*. +- *ApplicationContextID*: the context ID of the above application to appear on + DLT client. Default value is *QSYC*. +- *QnxSlogger2Enable*: when the value is 1 (by default), the QNX slogger2 + adapter which sends slogger2 to DLT will be started. Otherwise if the value + if 0, it won't be started. +- *QnxSlogger2ContextId*: this will set the context ID of the QNX slogger2 + adapter. Default value is *QSLA*. +- *QnxSlogger2UseOriginalTimestamp*: when the value is 1 (by default), slogger2 + event timestamps will be used as DLT timestamps. + + + +## Slogger2 adapter + +The slogger2 adapter that can be enabled in dlt-qnx-system attaches to slogger2 and converts the messages to dlt messages. + + +### Log level mapping + +As the severity levels on QNX system log are different from DLT Log Level, the below table shows how they're converted from the former to the latter. + + +| QNX System Log Level | DLT Log Level | +|----------------------|--------------------| +| SLOG2\_SHUTDOWN | DLT\_LOG\_FATAL | +| SLOG2\_CRITICAL | DLT\_LOG\_FATAL | +| SLOG2\_ERROR | DLT\_LOG\_ERROR | +| SLOG2\_WARNING | DLT\_LOG\_WARN | +| SLOG2\_NOTICE | DLT\_LOG\_INFO | +| SLOG2\_INFO | DLT\_LOG\_INFO | +| SLOG2\_DEBUG1 | DLT\_LOG\_DEBUG | +| SLOG2\_DEBUG2 | DLT\_LOG\_VERBOSE | + + +### Context Mapping + +The json file dlt-slog2ctxt.json can be used to map slogger names to dlt-contexts. + +#### Example + +Here is an example that sets a mapping from the "dumper" process to the DLT Context "DUMP", and the QNX Hypervisor to "QVM". +The description field is in the registration with libdlt. + +```python +{ + "DUMP": { + "name": "dumper", + "description": "Writes core dump files to disk" + }, + "SYSL": { + "name": "syslogd", + "description": "" + } +} +``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4037ef9..e4ff133 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,3 +48,7 @@ endif( WITH_DLT_COREDUMPHANDLER ) if( WITH_DLT_KPI ) add_subdirectory( kpi ) endif( WITH_DLT_KPI ) + +if( WITH_DLT_QNX_SYSTEM ) + add_subdirectory( dlt-qnx-system ) +endif( WITH_DLT_QNX_SYSTEM ) diff --git a/src/dlt-qnx-system/CMakeLists.txt b/src/dlt-qnx-system/CMakeLists.txt new file mode 100644 index 0000000..9a9db46 --- /dev/null +++ b/src/dlt-qnx-system/CMakeLists.txt @@ -0,0 +1,33 @@ +####### +# @licence make begin@ +# SPDX license identifier: MPL-2.0 +# +# Copyright (C) 2018 Advanced Driver Information Technology. +# +# 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@ +####### + +if(NOT WITH_DLT_CXX11_EXT) + message(FATAL_ERROR "DLT_QNX_SYSTEM needs the C++ features of dlt, please enable the WITH_DLT_CXX11_EXT option.") +endif() + +set(dlt-qnx-system_SRCS dlt-qnx-system.c dlt-qnx-slogger2-adapter.cpp) +add_executable(dlt-qnx-system ${dlt-qnx-system_SRCS}) + +target_link_libraries(dlt-qnx-system dlt slog2parse json) + +install(TARGETS dlt-qnx-system + RUNTIME DESTINATION bin + COMPONENT base) + +install(FILES dlt-qnx-system.conf dlt-slog2ctxt.json + DESTINATION ${CONFIGURATION_FILES_DIR} + COMPONENT base) diff --git a/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp b/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp new file mode 100644 index 0000000..5ebfc0c --- /dev/null +++ b/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp @@ -0,0 +1,251 @@ +/** + * Copyright (C) 2018-2020 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT QNX system 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 Nguyen Dinh Thi ADIT 2018 + * \author Felix Herrmann ADIT 2020 + * + * \file: dlt-qnx-slogger2-adapter.cpp + * For further information see http://www.genivi.org/. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dlt-qnx-system.h" +#include "dlt_cpp_extension.hpp" + +/* Teach dlt about json_decoder_error_t */ +template<> +inline int32_t logToDlt(DltContextData &log, const json_decoder_error_t &value) +{ + return logToDlt(log, static_cast(value)); +} + +extern DltContext dltQnxSystem; + +static DltContext dltQnxSlogger2Context; + +extern DltQnxSystemThreads g_threads; +static std::unordered_map g_slog2file; + +static void dlt_context_map_read(const char *json_filename) +{ + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_VERBOSE, + "Loading Slog2Ctxt Map from json file: ", json_filename); + + auto dec = json_decoder_create(); + if (json_decoder_parse_file(dec, json_filename) != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_ERROR, + "Could not load Slog2Ctxt Map from json file: ", json_filename); + return; + } + + const char *ctxtID, *name, *description; + + /* go to first element in dlt-slog2ctxt.json e.g. "ADIO" */ + auto ret = json_decoder_push_object(dec, nullptr, false); + while (ret == JSON_DECODER_OK) { + ctxtID = json_decoder_name(dec); + + /* go into the element e.g. { name: "", description: "" } */ + ret = json_decoder_push_object(dec, nullptr, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while descending into context dict. ret=", ret); + break; + } + + ret = json_decoder_get_string(dec, "name", &name, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while retrieving 'name' element of ", ctxtID, ". ret=", ret); + break; + } + + ret = json_decoder_get_string(dec, "description", &description, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while retrieving 'description' element of ", ctxtID, ". ret=", ret); + break; + } + + auto ctxt = new DltContext; + g_slog2file.emplace(name, ctxt); + + auto search = g_slog2file.find(name); + if (search == g_slog2file.end()) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_INFO, + "Could not emplace slog2ctxt map key: ", name); + } else { + dlt_register_context(ctxt, ctxtID, description); + } + + ret = json_decoder_pop(dec); + } + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_DEBUG, + "Added ", g_slog2file.size(), " elements into the mapping table."); +} + +/** + * Map the slog2 logfile name to a dlt context + * e.g. i2c_service.2948409 -> Context with id "I2CS" + */ +static DltContext *dlt_context_from_slog2file(const char *file_name) { + auto d = strchr(file_name, '.'); + + if (d == nullptr) + return &dltQnxSlogger2Context; + + auto name = std::string(file_name).substr(0, d - file_name); + + auto search = g_slog2file.find(name); + if (search == g_slog2file.end()) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_VERBOSE, + "slog2 filename not found in mapping: ", name.c_str()); + return &dltQnxSlogger2Context; + } else { + return search->second; + } +} + +/** + * Function which is invoked by slog2_parse_all() + * See slog2_parse_all api docs on qnx.com for details + */ +static int sloggerinfo_callback(slog2_packet_info_t *info, void *payload, void *param) +{ + DltQnxSystemConfiguration* conf = (DltQnxSystemConfiguration*) param; + + if (param == NULL) + return -1; + + DltLogLevelType loglevel; + switch (info->severity) + { + case SLOG2_SHUTDOWN: + case SLOG2_CRITICAL: + loglevel = DLT_LOG_FATAL; + break; + case SLOG2_ERROR: + loglevel = DLT_LOG_ERROR; + break; + case SLOG2_WARNING: + loglevel = DLT_LOG_WARN; + break; + case SLOG2_NOTICE: + case SLOG2_INFO: + loglevel = DLT_LOG_INFO; + break; + case SLOG2_DEBUG1: + loglevel = DLT_LOG_DEBUG; + break; + case SLOG2_DEBUG2: + loglevel = DLT_LOG_VERBOSE; + break; + default: + loglevel = DLT_LOG_INFO; + break; + } + + DltContextData log_local; /* Used in DLT_* macros, do not rename */ + DltContext *ctxt = dlt_context_from_slog2file(info->file_name); + + int ret; + ret = dlt_user_log_write_start(ctxt, &log_local, loglevel); + + /* OK means loglevel under threshold */ + if (ret == DLT_RETURN_OK) { + return 0; + } + + if (ret != DLT_RETURN_TRUE) { + fprintf(stderr, "%s: could not log to DLT status=%d\n", __func__, ret); + return -1; + } + + if (conf->qnxslogger2.useOriginalTimestamp == 1) { + /* convert from ns to .1 ms */ + log_local.user_timestamp = (uint32_t) (info->timestamp / 100000); + log_local.use_timestamp = DLT_USER_TIMESTAMP; + } else { + DLT_UINT64(info->timestamp); + } + + DLT_UINT16(info->sequence_number); + DLT_STRING((char *)info->file_name); + DLT_STRING((char *)info->buffer_name); + DLT_UINT16(info->thread_id); + DLT_UINT8(info->severity); + DLT_STRING((char *)payload); + + dlt_user_log_write_finish(&log_local); + + return 0; +} + +static void *slogger2_thread(void *v_conf) +{ + DltQnxSystemConfiguration *conf = (DltQnxSystemConfiguration *)v_conf; + + if (v_conf == NULL) + return reinterpret_cast(EINVAL); + + slog2_packet_info_t packet_info = SLOG2_PACKET_INFO_INIT; + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-slogger2-adapter, in thread.")); + DLT_REGISTER_CONTEXT(dltQnxSlogger2Context, conf->qnxslogger2.contextId, + "SLOGGER2 Adapter"); + + dlt_context_map_read(CONFIGURATION_FILES_DIR "/dlt-slog2ctxt.json"); + + /** + * Thread will block inside this function to get new log because + * flag = SLOG2_PARSE_FLAGS_DYNAMIC + */ + int ret = slog2_parse_all( + SLOG2_PARSE_FLAGS_DYNAMIC, /* live streaming of all buffers merged */ + NULL, NULL, &packet_info, sloggerinfo_callback, (void*) conf); + if (ret == -1) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_ERROR, + "slog2_parse_all() returned error=", ret); + ret = EBADMSG; + } + + DLT_LOG_CXX(dltQnxSystem, DLT_LOG_DEBUG, __func__, ": Exited main loop."); + + DLT_UNREGISTER_CONTEXT(dltQnxSlogger2Context); + + /* Send a signal to main thread to wake up sigwait */ + pthread_kill(g_threads.mainThread, SIGTERM); + return reinterpret_cast(ret); +} + +void start_qnx_slogger2(DltQnxSystemConfiguration *conf) +{ + static pthread_attr_t t_attr; + static pthread_t pt; + + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_DEBUG, + "dlt-qnx-slogger2-adapter, start syslog"); + pthread_create(&pt, &t_attr, slogger2_thread, conf); + g_threads.threads[g_threads.count++] = pt; +} diff --git a/src/dlt-qnx-system/dlt-qnx-system.c b/src/dlt-qnx-system/dlt-qnx-system.c new file mode 100644 index 0000000..afd34b4 --- /dev/null +++ b/src/dlt-qnx-system/dlt-qnx-system.c @@ -0,0 +1,433 @@ +/** + * Copyright (C) 2020 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT QNX system 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 Nguyen Dinh Thi + * + * \file: dlt-qnx-system.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dlt.h" +#include "dlt-qnx-system.h" + +DLT_DECLARE_CONTEXT(dltQnxSystem) + +/* Global variables */ +volatile DltQnxSystemThreads g_threads; + +/* Function prototype */ +static void daemonize(); +static void start_threads(DltQnxSystemConfiguration *config); +static void join_threads(); +static int read_configuration_file(DltQnxSystemConfiguration *config, + const char *file_name); +static int read_command_line(DltQnxSystemCliOptions *options, int argc, char *argv[]); + +int main(int argc, char* argv[]) +{ + DltQnxSystemCliOptions options; + DltQnxSystemConfiguration config; + int sigNo = 0; + int ret = 0; + sigset_t mask; + int i; + + if (read_command_line(&options, argc, argv) < 0) + { + fprintf(stderr, "Failed to read command line!\n"); + return -1; + } + + if (read_configuration_file(&config, options.configurationFileName) < 0) + { + fprintf(stderr, "Failed to read configuration file!\n"); + return -1; + } + + if (options.daemonize > 0) + { + daemonize(); + } + + DLT_REGISTER_APP(config.applicationId, "DLT QNX System"); + DLT_REGISTER_CONTEXT(dltQnxSystem, config.applicationContextId, + "Context of main dlt qnx system manager"); + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("Setting signals wait for abnormal exit")); + + g_threads.mainThread = pthread_self(); + + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGHUP); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGALRM); + if (pthread_sigmask(SIG_BLOCK, &mask, NULL) == -1) { + DLT_LOG(dltQnxSystem, DLT_LOG_WARN, + DLT_STRING("Failed to block signals!")); + DLT_UNREGISTER_APP(); + return -1; + } + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, DLT_STRING("Launching threads.")); + start_threads(&config); + + ret = sigwait(&mask, &sigNo); + + for (i = 0; i < MAX_THREADS; i++) { + pthread_cancel(g_threads.threads[i]); + } + join_threads(); + + if (ret != 0) { + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("sigwait failed with error: "), + DLT_INT(ret)); + DLT_UNREGISTER_APP(); + return -1; + } + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("Received signal: "), + DLT_STRING(strsignal(sigNo))); + + DLT_UNREGISTER_APP_FLUSH_BUFFERED_LOGS(); + return 0; + +} + +/** + * Print information how to use this program. + */ +static void usage(char *prog_name) +{ + char version[255]; + dlt_get_version(version, 255); + + printf("Usage: %s [options]\n", prog_name); + printf("Application to manage QNX system, such as:\n"); + printf(" - forward slogger2 messages from QNX to DLT) .\n"); + printf("%s\n", version); + printf("Options:\n"); + printf(" -d Daemonize. Detach from terminal and run in background.\n"); + printf(" -c filename Use configuration file. \n"); + printf(" Default: %s\n", DEFAULT_CONF_FILE); + printf(" -h This help message.\n"); +} + +/** + * Initialize command line options with default values. + */ +static void init_cli_options(DltQnxSystemCliOptions *options) +{ + options->configurationFileName = DEFAULT_CONF_FILE; + options->daemonize = 0; +} + +/** + * Read command line options and set the values in provided structure + */ +static int read_command_line(DltQnxSystemCliOptions *options, int argc, char *argv[]) +{ + init_cli_options(options); + int opt; + + while ((opt = getopt(argc, argv, "c:hd")) != -1) + { + switch (opt) { + case 'd': + { + options->daemonize = 1; + break; + } + case 'c': + { + options->configurationFileName = (char *)malloc(strlen(optarg)+1); + MALLOC_ASSERT(options->configurationFileName); + /** + * strcpy unritical here, because size matches exactly the size + * to be copied + */ + strcpy(options->configurationFileName, optarg); + break; + } + case 'h': + { + usage(argv[0]); + exit(0); + return -1; + } + default: + { + fprintf(stderr, "Unknown option '%c'\n", optopt); + usage(argv[0]); + return -1; + } + } + } + return 0; +} + +/** + * Initialize configuration to default values. + */ +static void init_configuration(DltQnxSystemConfiguration *config) +{ + /* Common */ + config->applicationId = "QSYM"; + config->applicationContextId = "QSYC"; + + /* Slogger2 */ + config->qnxslogger2.enable = 0; + config->qnxslogger2.contextId = "QSLA"; + config->qnxslogger2.useOriginalTimestamp = 1; +} + +/** + * Read options from the configuration file + */ +static int read_configuration_file(DltQnxSystemConfiguration *config, + const char *file_name) +{ + FILE *file; + char *line; + char *token; + char *value; + char *pch; + int ret = 0; + + init_configuration(config); + + file = fopen(file_name, "r"); + + if (file == NULL) + { + fprintf(stderr, + "dlt-qnx-system, could not open configuration file.\n"); + return -1; + } + + line = malloc(MAX_LINE); + token = malloc(MAX_LINE); + value = malloc(MAX_LINE); + + MALLOC_ASSERT(line); + MALLOC_ASSERT(token); + MALLOC_ASSERT(value); + + while (fgets(line, MAX_LINE, file) != NULL) + { + token[0] = 0; + value[0] = 0; + + pch = strtok(line, " =\r\n"); + while (pch != NULL) + { + if (pch[0] == '#') + { + break; + } + + if (token[0] == 0) + { + strncpy(token, pch, MAX_LINE-1); + token[MAX_LINE-1] = 0; + } + else + { + strncpy(value, pch, MAX_LINE); + value[MAX_LINE-1] = 0; + break; + } + + pch = strtok(NULL, " =\r\n"); + } + + if (token[0] && value[0]) + { + /* Common */ + if (strcmp(token, "ApplicationId") == 0) + { + config->applicationId = (char *)malloc(strlen(value) + 1); + MALLOC_ASSERT(config->applicationId); + /** + * strcpy unritical here, because size matches exactly the + * size to be copied + */ + strcpy(config->applicationId, value); + } + else if (strcmp(token, "ApplicationContextID") == 0) + { + config->applicationContextId = (char *)malloc(strlen(value) + 1); + MALLOC_ASSERT(config->applicationContextId); + /** + * strcpy unritical here, because size matches exactly + * the size to be copied + */ + strcpy(config->applicationContextId, value); + } + /* Slogger2 */ + else if (strcmp(token, "QnxSlogger2Enable") == 0) + { + config->qnxslogger2.enable = atoi(value); + } + else if (strcmp(token, "QnxSlogger2ContextId") == 0) + { + config->qnxslogger2.contextId = (char *)malloc(strlen(value) + 1); + MALLOC_ASSERT(config->qnxslogger2.contextId); + /** + * strcpy unritical here, because size matches exactly + * the size to be copied + */ + strcpy(config->qnxslogger2.contextId, value); + } + else if (strcmp(token, "QnxSlogger2UseOriginalTimestamp") == 0) + { + config->qnxslogger2.useOriginalTimestamp = atoi(value); + } + else + { + /* Do nothing */ + } + } + } + + fclose(file); + file = NULL; + + free(value); + value = NULL; + + free(token); + token = NULL; + + free(line); + line = NULL; + + return ret; +} + +static void daemonize() +{ + pid_t pid = fork(); + + if (pid == -1) { + err(-1, "%s failed on fork()", __func__); + } + + if (pid > 0) { /* parent process*/ + exit(0); + } + + /* Create a new process group */ + if (setsid() == -1) { + err(-1, "%s failed on setsid()", __func__); + } + + /* Point std(in,out,err) to /dev/null */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + int fd = open("/dev/null", O_RDWR); + if (fd == -1) { + err(-1, "%s failed on open() /dev/null", __func__); + } + + if ((dup2(fd, STDIN_FILENO) == -1) || + (dup2(fd, STDOUT_FILENO) == -1 ) || + (dup2(fd, STDERR_FILENO) == -1 )) { + err(-1, "%s failed on dup2()", __func__); + } + + /** + * Ignore signals related to child processes and + * terminal handling. + */ + signal(SIGCHLD, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); +} + +static void start_threads(DltQnxSystemConfiguration *config) +{ + int i = 0; + + /* Check parameter */ + if (!config) + { + return; + } + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-system, start threads")); + + g_threads.count = 0; + g_threads.shutdown = 0; + + for (i = 0; i < MAX_THREADS; i++) + { + g_threads.threads[i] = 0; + } + + if (config->qnxslogger2.enable) + { + start_qnx_slogger2(config); + } +} + +/** + * Wait for threads to exit. + */ +static void join_threads() +{ + int i = 0; + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-system, waiting for threads to exit")); + + if (g_threads.count < 1) + { + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-system, no threads, waiting for signal.")); + } + else + { + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-system, thread count: "), + DLT_INT(g_threads.count)); + + for (i = 0; i < g_threads.count; i++) + { + pthread_join(g_threads.threads[i], NULL); + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-system, thread exit: "), + DLT_INT(g_threads.threads[i])); + } + } + + DLT_UNREGISTER_CONTEXT(dltQnxSystem); +} diff --git a/src/dlt-qnx-system/dlt-qnx-system.conf b/src/dlt-qnx-system/dlt-qnx-system.conf new file mode 100644 index 0000000..8a12e89 --- /dev/null +++ b/src/dlt-qnx-system/dlt-qnx-system.conf @@ -0,0 +1,25 @@ +# Configuration file of DLT QNX Slogger2 Manager +# + +######################################################################## +# General configuration +######################################################################## + +# The application Id used for the QNX system Manager (Default: QSYM) +ApplicationId = QSYM + +# Context of main dlt QNX system +ApplicationContextID = QSYC + +######################################################################## +# Syslog Adapter configuration +######################################################################## + +# Enable the Qnx slogger2 Adapter (Default: 1) +QnxSlogger2Enable = 1 + +# The Context Id of the Qnx syslog adapter (Default: QSLA) +QnxSlogger2ContextId = QSLA + +# Use slogger2 event timestamps as DLT timestamps (Default: 1) +QnxSlogger2UseOriginalTimestamp = 1 diff --git a/src/dlt-qnx-system/dlt-qnx-system.h b/src/dlt-qnx-system/dlt-qnx-system.h new file mode 100644 index 0000000..270b8be --- /dev/null +++ b/src/dlt-qnx-system/dlt-qnx-system.h @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2020 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT QNX system functionality header file. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Nguyen Dinh Thi ADIT 2020 + * + * \file: dlt-qnx-system.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt_qnx-system.h ** +** ** +** TARGET : QNX ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Thi.NguyenDinh@vn.bosch.com ** +** ** +** PURPOSE : ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** ndt Nguyen Dinh Thi ADIT ** +** ** +*******************************************************************************/ + +#ifndef DLT_QNX_SYSTEM_H_ +#define DLT_QNX_SYSTEM_H_ + +#include "dlt.h" + +/* Constants */ +#define DEFAULT_CONF_FILE ( CONFIGURATION_FILES_DIR "/dlt-qnx-system.conf") + +#define MAX_LINE 1024 +#define MAX_THREADS 8 + +/* Macros */ +#define MALLOC_ASSERT(x)\ + do\ + {\ + if(x == NULL) {\ + fprintf(stderr, "%s - %d: Out of memory\n", __func__, __LINE__);\ + abort();\ + }\ + }\ + while (0) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Command line options */ +typedef struct { + char *configurationFileName; + int daemonize; +} DltQnxSystemCliOptions; + +/* Configuration slogger2 options */ +typedef struct { + int enable; + char *contextId; + int useOriginalTimestamp; +} Qnxslogger2Options; + +typedef struct { + char *applicationId; + char *applicationContextId; + Qnxslogger2Options qnxslogger2; +} DltQnxSystemConfiguration; + +typedef struct { + pthread_t threads[MAX_THREADS]; + pthread_t mainThread; + int count; + int shutdown; +} DltQnxSystemThreads; + +void start_qnx_slogger2(DltQnxSystemConfiguration *conf); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* DLT_QNX_SYSTEM_H_ */ diff --git a/src/dlt-qnx-system/dlt-slog2ctxt.json b/src/dlt-qnx-system/dlt-slog2ctxt.json new file mode 100644 index 0000000..6d69ec0 --- /dev/null +++ b/src/dlt-qnx-system/dlt-slog2ctxt.json @@ -0,0 +1,14 @@ +{ + "SRCN": { + "name": "screen", + "description": "" + }, + "SLM ": { + "name": "slm", + "description": "" + }, + "SYSL": { + "name": "syslogd", + "description": "" + } +} -- cgit v1.2.1