summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format90
-rw-r--r--.github/workflows/cmake-ctest.yml37
-rwxr-xr-x.travis/gtest_dlt_all.sh66
-rw-r--r--Android.bp14
-rw-r--r--CMakeLists.txt68
-rw-r--r--README.md32
-rw-r--r--ReleaseNotes.md68
-rw-r--r--automotive-dlt.pc.in2
-rw-r--r--doc/dlt.conf.5.md20
-rw-r--r--doc/dlt_for_developers.md5
-rw-r--r--doc/dlt_offline_logstorage.md3
-rw-r--r--include/dlt/CMakeLists.txt2
-rw-r--r--include/dlt/dlt_common.h82
-rw-r--r--include/dlt/dlt_cpp_extension.hpp4
-rw-r--r--include/dlt/dlt_multiple_files.h154
-rw-r--r--include/dlt/dlt_offline_trace.h103
-rw-r--r--include/dlt/dlt_user.h.in4
-rw-r--r--include/dlt/dlt_user_macros.h62
-rwxr-xr-xscripts/pre-commit.sample28
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/adaptor/CMakeLists.txt30
-rw-r--r--src/android/dlt-logd-converter.cpp5
-rw-r--r--src/console/CMakeLists.txt17
-rw-r--r--src/console/dlt-control-common.c2
-rw-r--r--src/console/dlt-control.c8
-rw-r--r--src/console/dlt-convert.c31
-rw-r--r--src/console/dlt-receive.c57
-rw-r--r--src/console/dlt-sortbytimestamp.c6
-rw-r--r--src/daemon/CMakeLists.txt7
-rw-r--r--src/daemon/dlt-daemon.c113
-rw-r--r--src/daemon/dlt-daemon.h15
-rw-r--r--src/daemon/dlt.conf11
-rw-r--r--src/daemon/dlt_daemon_client.c14
-rw-r--r--src/daemon/dlt_daemon_common.c4
-rw-r--r--src/daemon/dlt_daemon_common.h2
-rw-r--r--src/daemon/dlt_daemon_connection.c15
-rw-r--r--src/daemon/dlt_daemon_offline_logstorage.c9
-rw-r--r--src/daemon/dlt_daemon_unix_socket.c50
-rw-r--r--src/gateway/dlt_gateway.c30
-rw-r--r--src/lib/CMakeLists.txt1
-rw-r--r--src/lib/dlt_client.c120
-rw-r--r--src/lib/dlt_filetransfer.c17
-rw-r--r--src/lib/dlt_user.c311
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage.c71
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage.h36
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage_behavior.c343
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h8
-rw-r--r--src/offlinelogstorage/dlt_offline_logstorage_internal.h4
-rw-r--r--src/shared/dlt_common.c249
-rw-r--r--src/shared/dlt_config_file_parser.c2
-rw-r--r--src/shared/dlt_multiple_files.c498
-rw-r--r--src/shared/dlt_offline_trace.c394
-rw-r--r--src/shared/dlt_user_shared.c47
-rw-r--r--src/shared/dlt_user_shared.h25
-rw-r--r--src/system/dlt-system-process-handling.c10
-rw-r--r--src/system/dlt-system-watchdog.c7
-rw-r--r--systemd/CMakeLists.txt10
-rwxr-xr-xsystemd/dlt.socket.cmake8
-rw-r--r--tests/CMakeLists.txt15
-rw-r--r--tests/gtest_dlt_common.cpp92
-rw-r--r--tests/gtest_dlt_daemon_gateway.cpp2
-rw-r--r--tests/gtest_dlt_daemon_multiple_files_logging.cpp277
-rw-r--r--tests/gtest_dlt_daemon_offline_log.cpp141
-rw-r--r--tests/gtest_dlt_user.cpp87
-rw-r--r--uncrustify.cfg2736
65 files changed, 2995 insertions, 3790 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..18f4a2e
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,90 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ - Regex: '^(<|"(gtest|isl|json)/)'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 1
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
+
diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml
new file mode 100644
index 0000000..6cbfa51
--- /dev/null
+++ b/.github/workflows/cmake-ctest.yml
@@ -0,0 +1,37 @@
+name: CMake
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+env:
+ # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
+ BUILD_TYPE: Release
+ WITH_DLT_UNIT_TESTS: ON
+
+jobs:
+ build:
+ # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
+ # You can convert this to a matrix build if you need cross-platform coverage.
+ # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Configure CMake
+ # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
+ # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
+ run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DWITH_DLT_UNIT_TESTS=${{env.WITH_DLT_UNIT_TESTS}}
+
+ - name: Build
+ # Build your program with the given configuration
+ run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
+
+ - name: Test
+ working-directory: ${{github.workspace}}/build
+ # Execute tests defined by the CMake configuration.
+ # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
+ run: ctest -C ${{env.BUILD_TYPE}}
diff --git a/.travis/gtest_dlt_all.sh b/.travis/gtest_dlt_all.sh
deleted file mode 100755
index 8cae6a5..0000000
--- a/.travis/gtest_dlt_all.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/bash
-################################################################################
-# SPDX license identifier: MPL-2.0
-#
-# Copyright (C) 2019, 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.
-#
-# 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/.
-################################################################################
-
-################################################################################
-#file : gtest_dlt_all.sh
-#
-#Description : Run all unit tests in Travis CI
-#
-#Author Name : Saya Sugiura
-################################################################################
-
-function gtest_run_test()
-{
- LOG="../.travis/$1.log"
-
- # Send all messsages and system errors to log file
- export LIBC_FATAL_STDERR_=1
-
- # Execute unit test
- { ./$1 ;} > $LOG 2>&1
-
- # Release
- export LIBC_FATAL_STDERR_=0
-
- # Check for result
- grep "FAILED TEST\|core dumped" $LOG
- if [ $? -eq 0 ]
- then
- cat $LOG
- echo "$1 failed"
- exit 1
- fi
- echo "$1 passed"
-}
-
-CTEST_OUTPUT_ON_FAILURE=1 make test
-
-pushd tests > /dev/null
-
-# Without General section in dlt_gateway.conf
-./gtest_dlt_daemon_gateway.sh > /dev/null
-gtest_run_test gtest_dlt_daemon_gateway
-
-# With General section in dlt_gateway.conf
-./gtest_dlt_daemon_gateway.sh -w > /dev/null
-gtest_run_test gtest_dlt_daemon_gateway
-
-./gtest_dlt_daemon_offline_log.sh > /dev/null
-gtest_run_test gtest_dlt_daemon_offline_log
-
-popd > /dev/null
diff --git a/Android.bp b/Android.bp
index 96cd73d..36f27d7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -60,6 +60,13 @@ genrule {
out: ["dlt_user.h"],
}
+prebuilt_etc {
+ name: "dlt-daemon-configuration",
+ vendor: true,
+ src: "src/daemon/dlt.conf",
+ filename_from_src: true,
+}
+
cc_binary {
name: "dlt-daemon",
@@ -91,6 +98,7 @@ cc_binary {
"src/lib/dlt_client.c",
"src/shared/dlt_common.c",
"src/shared/dlt_config_file_parser.c",
+ "src/shared/dlt_multiple_files.c",
"src/shared/dlt_offline_trace.c",
"src/shared/dlt_protocol.c",
"src/shared/dlt_user_shared.c",
@@ -103,6 +111,8 @@ cc_binary {
"libutils",
"libcutils",
],
+
+ required: ["dlt-daemon-configuration"],
}
cc_library_shared {
@@ -129,6 +139,7 @@ cc_library_shared {
"src/lib/dlt_filetransfer.c",
"src/lib/dlt_user.c",
"src/shared/dlt_common.c",
+ "src/shared/dlt_multiple_files.c",
"src/shared/dlt_protocol.c",
"src/shared/dlt_user_shared.c",
],
@@ -185,9 +196,6 @@ cc_binary {
"libdlt",
"liblog",
],
- include_dirs: [
- "system/core/include",
- ],
}
// vim: ft=python
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e88f886..ff53ceb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@
#######
cmake_minimum_required(VERSION 3.3)
-project(automotive-dlt VERSION 2.18.8)
+project(automotive-dlt VERSION 2.18.9)
mark_as_advanced(CMAKE_BACKWARDS_COMPATIBILITY)
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
@@ -48,6 +48,7 @@ option(BUILD_SHARED_LIBS "Set to OFF to build static libraries"
option(WITH_SYSTEMD "Set to ON to create unit files and systemd check on dlt-daemon startup" OFF)
option(WITH_SYSTEMD_WATCHDOG "Set to ON to use the systemd watchdog in dlt-daemon" OFF)
option(WITH_SYSTEMD_JOURNAL "Set to ON to use the systemd journal in dlt-system" OFF)
+option(WITH_SYSTEMD_SOCKET_ACTIVATION "Set to ON to use systemd socket activation" OFF)
option(WITH_DOC "Set to ON to build documentation target" OFF)
option(WITH_MAN "Set to ON to build man pages" OFF)
option(WITH_CHECK_CONFIG_FILE "Set to ON to create a configure file of CheckIncludeFiles and CheckFunctionExists" OFF)
@@ -55,10 +56,17 @@ option(WITH_TESTSCRIPTS "Set to ON to run CMakeLists.txt in testscripts"
option(WITH_GPROF "Set -pg to compile flags" OFF)
option(WITH_DLTTEST "Set to ON to build with modifications to test User-Daemon communication with corrupt messages" OFF)
option(WITH_DLT_SHM_ENABLE "EXPERIMENTAL! Set to ON to use shared memory as IPC. EXPERIMENTAL!" OFF)
-option(WITH_DLT_ADAPTOR "Set to ON to build src/adaptor binaries" OFF)
+option(WITH_DLT_ADAPTOR "Set to ON to build src/adaptor binaries" OFF)
+option(WITH_DLT_ADAPTOR_STDIN "Set to ON to build src/adaptor/stdin binaries" OFF)
+option(WITH_DLT_ADAPTOR_UDP "Set to ON to build src/adaptor/udp binaries" OFF)
option(WITH_DLT_CONSOLE "Set to ON to build src/console binaries" ON)
option(WITH_DLT_CONSOLE_WO_CTRL "Set to ON not to build control commands under src/console" OFF)
option(WITH_DLT_CONSOLE_WO_SBTM "Set to ON not to build dlt-sortbytimestamp under src/console" OFF)
+option(WITH_DLT_CONSOLE_RECEIVE "Set to OFF to skip building dlt_receive" ON)
+option(WITH_DLT_CONSOLE_CONVERT "Set to OFF to skip building dlt_convert" ON)
+option(WITH_DLT_CONSOLE_CONTROL "Set to OFF to skip building dlt_control" ON)
+option(WITH_DLT_CONSOLE_PASSIVE_NODE_CTRL "Set to OFF to skip building dlt_passive_node_ctrl" ON)
+
option(WITH_DLT_EXAMPLES "Set to ON to build src/examples binaries" ON)
option(WITH_DLT_FILETRANSFER "Set to ON to build dlt-system with filetransfer support" OFF)
option(WITH_DLT_SYSTEM "Set to ON to build src/system binaries" OFF)
@@ -66,6 +74,8 @@ option(WITH_DLT_DBUS "Set to ON to build src/dbus binaries"
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)
+option(WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK "Set to ON to enable fallback to syslog if dlt logging to file fails" OFF)
+option(WITH_DLT_NETWORK_TRACE "Set to ON to enable network trace (if message queue is supported)" ON)
set(DLT_IPC "FIFO" CACHE STRING "UNIX_SOCKET,FIFO")
set(DLT_USER "genivi" CACHE STRING "Set user for process not run as root")
@@ -74,6 +84,7 @@ option(WITH_DLT_PKGCONFIG "Set to ON to generate pkgconfig .pc files"
option(WITH_DLT_CXX11_EXT "Set to ON to build C++11 extensions" OFF)
option(WITH_DLT_COREDUMPHANDLER "EXPERIMENTAL! Set to ON to build src/core_dump_handler binaries. EXPERIMENTAL" OFF)
option(WITH_DLT_LOGSTORAGE_CTRL_UDEV "PROTOTYPE! Set to ON to build logstorage control application with udev support" OFF)
+option(WITH_DLT_LOGSTORAGE_GZIP "Set to ON to build logstorage control application with gzip compression support" OFF)
option(WITH_DLT_USE_IPv6 "Set to ON for IPv6 support" ON)
option(WITH_DLT_KPI "Set to ON to build src/kpi binaries" OFF)
option(WITH_DLT_FATAL_LOG_TRAP "Set to ON to enable DLT_LOG_FATAL trap(trigger segv inside dlt-user library)" OFF)
@@ -85,7 +96,10 @@ option(WITH_EXTENDED_FILTERING "Set to OFF to build without extended filtering.
option(WITH_DLT_DAEMON_VSOCK_IPC "Set to ON to enable VSOCK support in daemon" OFF)
option(WITH_DLT_LIB_VSOCK_IPC "Set to ON to enable VSOCK support in library (DLT_IPC is not used in library)" OFF)
+
set(DLT_VSOCK_PORT "13490" CACHE STRING "VSOCK port number for logging traffic.")
+set(DLT_WRITEV_TIMEOUT_SEC "1" CACHE STRING "Set sec timeout for writev to prevent blocking indefinitely")
+set(DLT_WRITEV_TIMEOUT_USEC "0" CACHE STRING "Set usec timeout for writev to prevent blocking indefinitely")
# RPM settings
set(GENIVI_RPM_RELEASE "1") # ${DLT_REVISION}")
@@ -93,7 +107,10 @@ set(LICENSE "Mozilla Public License Version 2.0")
# Build, project and include settings
find_package(Threads REQUIRED)
-if(WITH_DLT_COREDUMPHANDLER OR WITH_DLT_FILETRANSFER)
+if(WITH_DLT_LOGSTORAGE_GZIP)
+ set(ZLIB_LIBRARY "-lz")
+ find_package(ZLIB 1.2.9 REQUIRED)
+elseif(WITH_DLT_COREDUMPHANDLER OR WITH_DLT_FILETRANSFER)
set(ZLIB_LIBRARY "-lz")
find_package(ZLIB REQUIRED)
else()
@@ -120,6 +137,8 @@ include_directories(
)
add_definitions(-D_GNU_SOURCE)
+add_definitions(-DDLT_WRITEV_TIMEOUT_SEC=${DLT_WRITEV_TIMEOUT_SEC})
+add_definitions(-DDLT_WRITEV_TIMEOUT_USEC=${DLT_WRITEV_TIMEOUT_USEC})
if(NOT DLT_IPC STREQUAL "UNIX_SOCKET" AND NOT DLT_IPC STREQUAL "FIFO")
message(FATAL_ERROR "${DLT_IPC} is not a valid value for DLT_IPC")
@@ -162,6 +181,14 @@ if(WITH_DLT_QNX_SYSTEM AND NOT "${CMAKE_C_COMPILER}" MATCHES "nto-qnx|qcc")
message(FATAL_ERROR "Can only compile for QNX with a QNX compiler.")
endif()
+if (WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK)
+ add_definitions(-DWITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK)
+endif()
+
+if (WITH_DLT_LOGSTORAGE_GZIP)
+ add_definitions(-DDLT_LOGSTORAGE_USE_GZIP)
+endif()
+
if(WITH_GPROF)
add_compile_options(-pg)
endif()
@@ -182,6 +209,12 @@ else()
set(PACKAGE_DOC "")
endif()
+if (BUILD_SHARED_LIBS)
+ set(CMAKE_STATIC_LIB_PATH "")
+else()
+ set(CMAKE_STATIC_LIB_PATH "-L\$\{libdir\}/static")
+endif()
+
if(WITH_DLT_PKGCONFIG)
configure_file(${PROJECT_SOURCE_DIR}/${PROJECT_NAME}.spec.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.spec)
configure_file(${PROJECT_SOURCE_DIR}/${PROJECT_NAME}.pc.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.pc @ONLY)
@@ -198,16 +231,20 @@ add_definitions(-DCONFIGURATION_FILES_DIR="${CONFIGURATION_FILES_DIR}")
add_subdirectory(cmake)
-# Message queue
-if(HAVE_MQUEUE_H AND HAVE_FUNC_MQOPEN AND HAVE_FUNC_MQCLOSE AND
- HAVE_FUNC_MQUNLINK AND HAVE_FUNC_MQSEND AND HAVE_FUNC_MQRECEIVE)
- add_definitions(-DDLT_NETWORK_TRACE_ENABLE)
- set(DLT_NETWORK_TRACE_ENABLE 1)
+if (WITH_DLT_NETWORK_TRACE)
+ # Message queue
+ if(HAVE_MQUEUE_H AND HAVE_FUNC_MQOPEN AND HAVE_FUNC_MQCLOSE AND
+ HAVE_FUNC_MQUNLINK AND HAVE_FUNC_MQSEND AND HAVE_FUNC_MQRECEIVE)
+ add_definitions(-DDLT_NETWORK_TRACE_ENABLE)
+ set(DLT_NETWORK_TRACE_ENABLE 1)
+ else()
+ message(STATUS "Disable network trace interface since message queue is not supported")
+ endif()
else()
- message(STATUS "Disable network trace interface since message queue is not supported")
+ message(STATUS "Network trace interface disabled")
endif()
-if(WITH_SYSTEMD OR WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD_JOURNAL)
+if(WITH_SYSTEMD OR WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD_JOURNAL OR WITH_SYSTEMD_SOCKET_ACTIVATION)
find_package(PkgConfig REQUIRED)
execute_process(COMMAND pkg-config --modversion systemd OUTPUT_VARIABLE SYSTEMD_VERSION)
string(REPLACE "\n" "" SYSTEMD_VERSION ${SYSTEMD_VERSION})
@@ -224,6 +261,13 @@ if(WITH_SYSTEMD OR WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD_JOURNAL)
add_definitions(-DDLT_SYSTEMD_JOURNAL_ENABLE)
endif()
+ if (WITH_SYSTEMD_SOCKET_ACTIVATION)
+ if(NOT DLT_IPC STREQUAL "UNIX_SOCKET")
+ message(FATAL_ERROR "WITH_SYSTEMD_SOCKET_ACTIVATION is only supported for UNIX_SOCKET")
+ endif()
+ add_definitions(-DDLT_SYSTEM_SOCKET_ACTIVATION_ENABLE)
+ endif()
+
set(systemd_SRCS ${PROJECT_SOURCE_DIR}/systemd/3rdparty/sd-daemon.c)
set(SYSTEMD_UNITDIR "${CMAKE_INSTALL_PREFIX}/lib/systemd/system" CACHE PATH
@@ -285,6 +329,7 @@ message(STATUS "WITH_DOC = ${WITH_DOC}")
message(STATUS "WITH_MAN = ${WITH_MAN}")
message(STATUS "WITH_DLT_ADAPTOR = ${WITH_DLT_ADAPTOR}")
+message(STATUS "WITH_DLT_ADAPTOR_UDP = ${WITH_DLT_ADAPTOR_UDP}")
message(STATUS "WITH_DLT_CONSOLE = ${WITH_DLT_CONSOLE}")
message(STATUS "WITH_DLT_CONSOLE_WO_CTRL = ${WITH_DLT_CONSOLE_WO_CTRL}")
message(STATUS "WITH_DLT_CONSOLE_WO_SBTM = ${WITH_DLT_CONSOLE_WO_SBTM}")
@@ -317,16 +362,19 @@ message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_HOST_SYSTEM_PROCESSOR = ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "WITH_DLT_LOGSTORAGE_CTRL_UDEV = ${WITH_DLT_LOGSTORAGE_CTRL_UDEV}")
+message(STATUS "WITH_DLT_LOGSTORAGE_GZIP = ${WITH_DLT_LOGSTORAGE_GZIP}")
message(STATUS "DLT_IPC = ${DLT_IPC}(Path: ${DLT_USER_IPC_PATH})")
message(STATUS "WITH_DLT_DAEMON_VSOCK_IPC = ${WITH_DLT_DAEMON_VSOCK_IPC}")
message(STATUS "WITH_DLT_LIB_VSOCK_IPC = ${WITH_DLT_LIB_VSOCK_IPC}")
message(STATUS "DLT_VSOCK_PORT = ${DLT_VSOCK_PORT}")
message(STATUS "WITH_UDP_CONNECTION = ${WITH_UDP_CONNECTION}")
message(STATUS "WITH_DLT_QNX_SYSTEM = ${WITH_DLT_QNX_SYSTEM}")
+message(STATUS "WITH_DLT_NETWORK_TRACE = ${WITH_DLT_NETWORK_TRACE}")
message(STATUS "WITH_LIB_SHORT_VERSION = ${WITH_LIB_SHORT_VERSION}")
message(STATUS "WITH_LEGACY_INCLUDE_PATH = ${WITH_LEGACY_INCLUDE_PATH}")
message(STATUS "WITH_EXTENDED_FILTERING = ${WITH_EXTENDED_FILTERING}")
message(STATUS "WITH_DLT_DISABLE_MACRO = ${WITH_DLT_DISABLE_MACRO}")
+message(STATUS "WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK = ${WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK}" )
message(STATUS "Change a value with: cmake -D<Variable>=<Value>")
message(STATUS "-------------------------------------------------------------------------------")
message(STATUS)
diff --git a/README.md b/README.md
index 788a954..5a72c54 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,7 @@
# Diagnostic Log and Trace
-Build and Test status: [![Build Status](https://travis-ci.com/GENIVI/dlt-daemon.svg?branch=master)](https://travis-ci.com/GENIVI/dlt-daemon)
-Alerts: [![Total alerts](https://img.shields.io/lgtm/alerts/g/GENIVI/dlt-daemon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/GENIVI/dlt-daemon/alerts/)
-Code quality: [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/GENIVI/dlt-daemon.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/GENIVI/dlt-daemon/context:cpp)
+Status: [![Build Status](https://github.com/COVESA/dlt-daemon/actions/workflows/cmake-ctest.yml/badge.svg)]( https://github.com/COVESA/dlt-daemon/actions/workflows/cmake-ctest.yml)
+[![CodeQL](https://github.com/COVESA/dlt-daemon/actions/workflows/codeql-analysis.yml/badge.svg?branch=master)](https://github.com/COVESA/dlt-daemon/actions/workflows/codeql-analysis.yml)
# Diagnostic Log and Trace
@@ -18,7 +17,7 @@ you can [learn more](#learn-more) about advanced concepts and features.
GENIVI DLT provides a log and trace interface, based on the standardised
protocol specified in the
-[AUTOSAR standard 4.0 DLT](https://www.autosar.org/fileadmin/user_upload/standards/classic/4-0/AUTOSAR_SWS_DiagnosticLogAndTrace.pdf).
+[AUTOSAR standard 4 DLT](https://www.autosar.org/fileadmin/standards/R22-11/CP/AUTOSAR_SWS_DiagnosticLogAndTrace.pdf).
It is used by other GENIVI components but can serve as logging framework for
other applications without relation to GENIVI.
@@ -194,10 +193,22 @@ make sure to follow the
### Coding Rules
-Before contributing code, run uncrustify to harmonize code style.
+This project is now using clang-format as replacement of uncrustify.
-Configuration: util/uncrustify.cfg
-uncrustify version: 0.68\_f
+For convenience, any code changes will be harmonized before commit by hooks/pre-commit.
+
+- Install clang-format
+
+- Install pre-commit script by:
+
+ ```bash
+ cp scripts/pre-commit.sample .git/hooks/pre-commit
+ ```
+
+- Configuration: .clang-format
+
+For reference to clang-format, you can check with:
+[Configurator](https://zed0.co.uk/clang-format-configurator/)
## Known issues
@@ -222,13 +233,10 @@ file.
Full information on the license for the cityhash code is available in "COPYING"
file in src/core\_dump\_handler/cityhash\_c.
-## Mailinglist
-
-https://lists.genivi.org/mailman/listinfo/genivi-diagnostic-log-and-trace_lists.genivi.org
## Contact
-Saya Sugiura <ssugiura@jp.adit-jv.com>,
-Bui Nguyen Quoc, Thanh <thanh.buinguyenquoc@vn.bosch.com>
+Methner, Michael <mmethner@de.adit-jv.com>,
+Le Van, Khanh <Khanh.LeVan@vn.bosch.com>
![alt text](doc/images/genivilogo.png "GENIVI")
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index a5e2806..8426de4 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -4,10 +4,76 @@ Back to [README.md](../README.md)
## Version
-2.18.8 STABLE
+2.18.9 STABLE
## Changes
+### 2.18.9
+
+ * dlt-user: fix crash with certain strings (#463)
+ * dlt_multiple_files: remove superfluous mode bits and add header file to header list (#462)
+ * Android: Add new feature in Android bp (#461)
+ * cmake: remove duplicated option message (#454)
+ * house-keeper: remove infinite wait (#438)
+ * dlt-logd-converter: Fix getting log level from log msg (#456)
+ * dlt-logd-converter: fixes android 12 compilation (#445)
+ * logfile: exhance internal dlt logging by introducing size limits (#369)
+ * This changes a mispatch from fcb676a7 to install the udp binary correctly. (#449)
+ * Installs dlt.conf on android (#446)
+ * dlt-connection: add socket timeout (#439)
+ * Fix memory leak (#441)
+ * Check for negative index in dlt_file_message (#437)
+ * dlt-user: fix potential non closed socket in init/free (#435)
+ * dlt-convert: Fix memory leak by calling dlt_file_free (#434)
+ * dlt-user: Fix crashes in dlt_free during dlt_init (#362)
+ * Update contacts and removed mailing lists (#431)
+ * Updates for Coding Styles (#425)
+ * gateway: Fix Node handling and ECUid checks (#429)
+ * filetransfer: fix filesize divisible by blocksize case (#383)
+ * client: Fix Get Log Info response conversion method (#422)
+ * cmake: network trace enable toggle (#424)
+ * dlt-system: Fix buffer overflow detection on 32bit targets (#398)
+ * dlt-receive: set host interface and allow multiple udp multicast addresses (#420)
+ * Fix for Resource and Memory Leak (#418)
+ * dlt_daemon_client: Fix Control Msg ECUId comparison with active Gateway (#414)
+ * Avoid memory corruption behind buffer wp in function dlt_getloginfo_conv_ascii_to_id (#411)
+ * dlt_common: change output of message for log initialization (#412)
+ * internal-logging: Fix issues with file logging (#378)
+ * systemd: add support for socket activation via systemd (#401)
+ * Update maintainer (#410)
+ * dlt_daemon_client: Fix change loglevel of application (#408)
+ * dlt_client:Block in connect() (#409)
+ * dlt-gateway: Fix crash on invalid ip (#381)
+ * Update dlt_for_developers.md (#405)
+ * logstorage: Truncate ECUid in Logstorage filter to prevent crash (#402)
+ * dlt_common.c: Change default logging_mode (#406)
+ * dlt-daemon-connection: Start up even if not all bindings are valid (#380)
+ * enforce-trace-limit: ContextLogLevel is now enforced in the daemon (#382)
+ * automotive-dlt.pc: add the path to find the static library (#387)
+ * systemd: install adaptor-udp service for adaptor=on (#393)
+ * Fix handle returned value (#384)
+ * README: Update link to github actions (#392)
+ * Update for CI (#389)
+ * Fix a double-free bug. (#376)
+ * Issue-ID: make-adaptor-configurablecmake: Add option to enable each adaptor by itself (#364)
+ * Fix the target name in documentation (#372)
+ * cmake: Add options to enable/disable each dlt console tool (#363)
+ * filetransfer: Fix getFileCreationDate2 stat check (#361)
+ * tests: Deplicate unused files and variables (#359)
+ * Fix DLT User/Client tests (#357)
+ * lib: Correct VARI usage in dlt_user_log_write_uint (#356)
+ * filetransfer: Return error if no free space (#354)
+ * Support for Cygwin toolchain. (#351)
+ * dlt-system: fix invalid free by removing unused TempDir (#350)
+ * fix -Wformat issues reported by clang (#349)
+ * Forcibly the severity level set (#346)
+ * daemon: Do not exit when accept returns ECONNABORTED (#347)
+ * dlt-system : fix invalid free with ConfigurationFileName (#342)
+ * dlt-daemon: Only create directories if they do not exist yet (#340)
+ * fixes compilation issue with clang (#339)
+ * dlt-daemon: create sockets using "android way" (#333)
+ * dlt-system: fix a libc buffer overflow detection on 32bit targets (#337)
+
### 2.18.8
* lib: Fix wrong type alert from lgtm
diff --git a/automotive-dlt.pc.in b/automotive-dlt.pc.in
index a52da01..ddca060 100644
--- a/automotive-dlt.pc.in
+++ b/automotive-dlt.pc.in
@@ -22,6 +22,6 @@ Name: DLT
Description: Diagnostic Log and Trace
Version: @PROJECT_VERSION@
Requires:
-Libs: -L${libdir} -ldlt -lrt -lpthread @ZLIB_LIBRARY@
+Libs: -L${libdir} @CMAKE_STATIC_LIB_PATH@ -ldlt -lrt -lpthread @ZLIB_LIBRARY@
Cflags: -I${includedir}/dlt -I${includedir} -DDLT_@PROJECT_VERSION_MAJOR@_@PROJECT_VERSION_MINOR@
diff --git a/doc/dlt.conf.5.md b/doc/dlt.conf.5.md
index aeb2dfc..8090438 100644
--- a/doc/dlt.conf.5.md
+++ b/doc/dlt.conf.5.md
@@ -79,6 +79,26 @@ If LoggingMode is set to 2 logs are written to the file path given here.
Default: /tmp/dlt.log
+## EnableLoggingFileLimit
+
+Only relevant for logging in file (LoggingMode = 2).
+If EnableLoggingFileLimit is set to 0, the daemon logs to one logging file without any size limit.
+If EnableLoggingFileLimit is set to 1, the daemon considers the size limits configured by LoggingFileSize and LoggingFileMaxSize. If the limits are configured accordingly, multiple log files are used.
+
+ Default: 0
+
+## LoggingFileSize
+
+Only considered for logging in file (LoggingMode = 2) and EnableLoggingFileLimit = 1. Maximum size in bytes of one logging file.
+
+ Default: 250000
+
+## LoggingFileMaxSize
+
+Only considered for logging in file (LoggingMode = 2) and EnableLoggingFileLimit = 1. Maximum size in bytes of all logging files.
+
+ Default: 1000000
+
## TimeOutOnSend
Socket timeout in seconds for sending to clients.
diff --git a/doc/dlt_for_developers.md b/doc/dlt_for_developers.md
index d664ab8..355eb03 100644
--- a/doc/dlt_for_developers.md
+++ b/doc/dlt_for_developers.md
@@ -69,7 +69,7 @@ You can thus:
```
find_package(automotive-dlt REQUIRED)
...
-target_link_libraries(myapp PRIVATE Genivi::DLT)
+target_link_libraries(myapp PRIVATE Genivi::dlt)
```
which lets your project automatically gain all necessary compile and link flags
needed by libdlt, including the include directories.
@@ -226,7 +226,8 @@ for(int index=0; index<MAX; index++)
Good example:
```
-for(int index=0; index<MAX; index++)
+int index = 0;
+for(; index<MAX; index++)
{
/* ... */
}
diff --git a/doc/dlt_offline_logstorage.md b/doc/dlt_offline_logstorage.md
index 3d29dab..91ef75b 100644
--- a/doc/dlt_offline_logstorage.md
+++ b/doc/dlt_offline_logstorage.md
@@ -74,6 +74,7 @@ NOFiles=<number of files> # Number of created files before oldest is
SyncBehavior=<strategy> # Specify sync strategy. Default: Sync'ed after every message. See Logstorage Rinbuffer Implementation below.
EcuID=<ECUid> # Specify ECU identifier
SpecificSize=<spec size in bytes> # Store logs in storage devices after specific size is reached.
+GzipCompression=<on or off> # Write the logfiles with gzip compression.
```
The Parameter "SyncBehavior","EcuID" and "SpecificSize" are optional - all
@@ -103,6 +104,7 @@ NOFiles=5
EcuID=ECU1
SyncBehavior=ON_SPECIFIC_SIZE
SpecificSize=5000
+GzipCompression=on
[FILTER3]
LogAppName=TEST
@@ -123,6 +125,7 @@ EcuID=<ECUid> # Specify ECU identifier
File=<file name> # Base name of the created files that containing the logs, e.g. "example". For further file naming scheme configurations see man dlt.conf
FileSize=<file size in bytes> # Maximum file size in bytes
NOFiles=<number of files> # Number of created files before oldest is deleted and a new one is created
+GzipCompression=on # Compress the log files
[NON-VERBOSE-LOGLEVEL-CTRL<unique number>] # filter configuration name to control log level of Non-Verbose applications
LogAppName=<APID> # Name of application (wildcard allowed)
diff --git a/include/dlt/CMakeLists.txt b/include/dlt/CMakeLists.txt
index ae05cc3..c2ee49a 100644
--- a/include/dlt/CMakeLists.txt
+++ b/include/dlt/CMakeLists.txt
@@ -21,7 +21,7 @@ configure_file(dlt_user.h.in dlt_user.h)
set(HEADER_LIST dlt.h dlt_user_macros.h dlt_client.h dlt_protocol.h
dlt_common.h dlt_types.h dlt_shm.h dlt_offline_trace.h
- dlt_filetransfer.h dlt_common_api.h
+ dlt_filetransfer.h dlt_common_api.h dlt_multiple_files.h
${CMAKE_CURRENT_BINARY_DIR}/dlt_version.h
${CMAKE_CURRENT_BINARY_DIR}/dlt_user.h)
diff --git a/include/dlt/dlt_common.h b/include/dlt/dlt_common.h
index 9a99fce..1757873 100644
--- a/include/dlt/dlt_common.h
+++ b/include/dlt/dlt_common.h
@@ -191,13 +191,13 @@
# define LOG_DAEMON (3 << 3)
# endif
-enum {
+typedef enum {
DLT_LOG_TO_CONSOLE = 0,
DLT_LOG_TO_SYSLOG = 1,
DLT_LOG_TO_FILE = 2,
DLT_LOG_TO_STDERR = 3,
DLT_LOG_DROPPED = 4
-};
+} DltLoggingMode;
/**
* The standard TCP Port used for DLT daemon, can be overwritten via -p \<port\> when starting dlt-daemon
@@ -300,7 +300,7 @@ enum {
{ length = -1; } \
else \
{ dst = *((type *)src); src += sizeof(type); length -= sizeof(type); } \
- } while(0)
+ } while(false)
# define DLT_MSG_READ_ID(dst, src, length) \
do { \
@@ -308,7 +308,7 @@ enum {
{ length = -1; } \
else \
{ memcpy(dst, src, DLT_ID_SIZE); src += DLT_ID_SIZE; length -= DLT_ID_SIZE; } \
- } while(0)
+ } while(false)
# define DLT_MSG_READ_STRING(dst, src, maxlength, dstlength, length) \
do { \
@@ -324,7 +324,7 @@ enum {
src += length; \
maxlength -= length; \
} \
- } while(0)
+ } while(false)
# define DLT_MSG_READ_NULL(src, maxlength, length) \
do { \
@@ -332,7 +332,7 @@ enum {
{ length = -1; } \
else \
{ src += length; maxlength -= length; } \
- } while(0)
+ } while(false)
# define DLT_HEADER_SHOW_NONE 0x0000
# define DLT_HEADER_SHOW_TIME 0x0001
@@ -1195,7 +1195,7 @@ void dlt_print_with_attributes(bool state);
* Initialize (external) logging facility
* @param mode positive, 0 = log to stdout, 1 = log to syslog, 2 = log to file, 3 = log to stderr
*/
-void dlt_log_init(int mode);
+DltReturnValue dlt_log_init(int mode);
/**
* Print with variable arguments to specified file descriptor by DLT_LOG_MODE environment variable (like fprintf)
* @param format format string for message
@@ -1631,15 +1631,28 @@ int16_t dlt_getloginfo_conv_ascii_to_uint16_t(char *rp, int *rp_count);
*/
int16_t dlt_getloginfo_conv_ascii_to_int16_t(char *rp, int *rp_count);
+
+/**
+ * Convert get log info from ASCII to string (with '\0' termination)
+ *
+ * @param rp char
+ * @param rp_count int
+ * @param wp char Array needs to be 1 byte larger than len to store '\0'
+ * @param len int
+ */
+void dlt_getloginfo_conv_ascii_to_string(char *rp, int *rp_count, char *wp, int len);
+
+
/**
- * Convert get log info from ASCII to ID
+ * Convert get log info from ASCII to ID (without '\0' termination)
*
* @param rp char
* @param rp_count int
* @param wp char
* @param len int
+ * @return position of last read character in wp
*/
-void dlt_getloginfo_conv_ascii_to_id(char *rp, int *rp_count, char *wp, int len);
+int dlt_getloginfo_conv_ascii_to_id(char *rp, int *rp_count, char *wp, int len);
/**
* Convert from hex ASCII to binary
@@ -1657,6 +1670,57 @@ void dlt_hex_ascii_to_binary(const char *ptr, uint8_t *binary, int *size);
*/
int dlt_execute_command(char *filename, char *command, ...);
+/**
+ * Return the extension of given file name.
+ * @param filename Only file names without prepended path allowed.
+ * @return pointer to extension
+ */
+char *get_filename_ext(const char *filename);
+
+/**
+ * Extract the base name of given file name (without the extension).
+ * @param abs_file_name Absolute path to file name.
+ * @param base_name Base name it is extracted to.
+ * @param base_name_length Base name length.
+ * @return indicating success
+ */
+bool dlt_extract_base_name_without_ext(const char* const abs_file_name, char* base_name, long base_name_len);
+
+/**
+ * Initialize (external) logging facility
+ * @param mode DltLoggingMode, 0 = log to stdout, 1 = log to syslog, 2 = log to file, 3 = log to stderr
+ * @param enable_multiple_logfiles, true if multiple logfiles (incl. size limits) should be use
+ * @param logging_file_size, maximum size in bytes of one logging file
+ * @param logging_files_max_size, maximum size in bytes of all logging files
+ */
+DltReturnValue dlt_log_init_multiple_logfiles_support(DltLoggingMode mode, bool enable_multiple_logfiles, int logging_file_size, int logging_files_max_size);
+
+/**
+ * Initialize (external) logging facility for single logfile.
+ */
+DltReturnValue dlt_log_init_single_logfile();
+
+/**
+ * Initialize (external) logging facility for multiple files logging.
+ */
+DltReturnValue dlt_log_init_multiple_logfiles(int logging_file_size, int logging_files_max_size);
+
+/**
+ * Logs into log files represented by the multiple files buffer.
+ * @param format First element in a specific format that will be logged.
+ * @param ... Further elements in a specific format that will be logged.
+ */
+void dlt_log_multiple_files_write(const char* format, ...);
+
+void dlt_log_free_single_logfile();
+
+void dlt_log_free_multiple_logfiles();
+
+/**
+ * Checks whether (internal) logging in multiple files is active.
+ */
+bool dlt_is_log_in_multiple_files_active();
+
# ifdef __cplusplus
}
# endif
diff --git a/include/dlt/dlt_cpp_extension.hpp b/include/dlt/dlt_cpp_extension.hpp
index c2600e7..cd82896 100644
--- a/include/dlt/dlt_cpp_extension.hpp
+++ b/include/dlt/dlt_cpp_extension.hpp
@@ -203,7 +203,7 @@ static inline int32_t logToDltVariadic(DltContextData &log, First const &valueA,
dlt_user_log_write_finish(&log);\
}\
}\
- while(0)
+ while(false)
/**
* @brief macro to write a log message with variable number of arguments and without the need to specify the type of log data.
@@ -227,6 +227,6 @@ static inline int32_t logToDltVariadic(DltContextData &log, First const &valueA,
dlt_user_log_write_finish(&log);\
}\
}\
- while(0)
+ while(false)
#endif /* DLT_CPP_EXTENSION_HPP */
diff --git a/include/dlt/dlt_multiple_files.h b/include/dlt/dlt_multiple_files.h
new file mode 100644
index 0000000..d5e13c7
--- /dev/null
+++ b/include/dlt/dlt_multiple_files.h
@@ -0,0 +1,154 @@
+/*
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2011-2015, BMW AG
+ *
+ * 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/.
+ */
+
+/*!
+ * \author
+ * Oleg Tropmann <oleg.tropmann@daimler.com>
+ * Daniel Weber <daniel.w.weber@daimler.com>
+ *
+ * \copyright Copyright © 2022 Mercedes-Benz AG. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_multiple_files.h
+ */
+
+
+#ifndef DLT_MULTIPLE_FILES_H
+#define DLT_MULTIPLE_FILES_H
+
+#include <limits.h>
+
+#include "dlt_common.h"
+#include "dlt_types.h"
+
+#define MULTIPLE_FILES_FILENAME_INDEX_DELIM "."
+#define MULTIPLE_FILES_FILENAME_TIMESTAMP_DELIM "_"
+
+/**
+ * Represents a ring buffer of multiple files of identical file size.
+ * File names differ in timestamp or index (depending on chosen mode).
+ * This buffer is used, e.g. for dlt offline traces and the internal dlt logging (dlt.log)
+ */
+typedef struct
+{
+ char directory[NAME_MAX + 1];/**< (String) Store DLT messages to local directory */
+ char filename[NAME_MAX + 1]; /**< (String) Filename of currently used log file */
+ int fileSize; /**< (int) Maximum size in bytes of one file, e.g. for offline trace 1000000 as default */
+ int maxSize; /**< (int) Maximum size of all files, e.g. for offline trace 4000000 as default */
+ bool filenameTimestampBased; /**< (bool) is filename timestamp based? false = index based (Default: true) */
+ char filenameBase[NAME_MAX + 1];/**< (String) Prefix of file name */
+ char filenameExt[NAME_MAX + 1];/**< (String) Extension of file name */
+ int ohandle; /**< (int) file handle to current output file */
+} MultipleFilesRingBuffer;
+
+/**
+ * Initialise the multiple files buffer.
+ * This function call opens the currently used log file.
+ * A check of the complete size of the files is done during startup.
+ * Old files are deleted, if there is not enough space left to create new file.
+ * This function must be called before using further multiple files functions.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @param directory directory where to store multiple files.
+ * @param file_size maximum size of one files.
+ * @param max_size maximum size of complete multiple files in bytes.
+ * @param filename_timestamp_based filename to be created on timestamp-based or index-based.
+ * @param append Indicates whether the current log files is used or a new file should be be created
+ * @param filename_base Base name.
+ * @param filename_ext File extension.
+ * @return negative value if there was an error.
+ */
+extern DltReturnValue multiple_files_buffer_init(MultipleFilesRingBuffer *files_buffer,
+ const char *directory,
+ int file_size,
+ int max_size,
+ bool filename_timestamp_based,
+ bool append,
+ const char *filename_base,
+ const char *filename_ext);
+
+/**
+ * Uninitialise the multiple files buffer.
+ * This function call closes currently used log file.
+ * This function must be called after usage of multiple files.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @return negative value if there was an error.
+*/
+extern DltReturnValue multiple_files_buffer_free(const MultipleFilesRingBuffer *files_buffer);
+
+/**
+ * Write data into multiple files.
+ * If the current used log file exceeds the max file size, new log file is created.
+ * A check of the complete size of the multiple files is done before new file is created.
+ * Old files are deleted, if there is not enough space left to create new file.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @param data pointer to first data block to be written, null if not used.
+ * @param size size in bytes of first data block to be written, 0 if not used.
+ * @return negative value if there was an error.
+ */
+extern DltReturnValue multiple_files_buffer_write(MultipleFilesRingBuffer *files_buffer,
+ const unsigned char *data,
+ int size);
+
+/**
+ * First the limits are verified. Then the oldest file is deleted and a new file is created on demand.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @param size size in bytes of data that will be written.
+ */
+void multiple_files_buffer_rotate_file(MultipleFilesRingBuffer *files_buffer,
+ int size);
+
+/**
+ * Writes the given data to current file specified by corresponding file handle.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @param data pointer to data block to be written, null if not used.
+ * @param size size in bytes of given data block to be written, 0 if not used.
+ */
+DltReturnValue multiple_files_buffer_write_chunk(const MultipleFilesRingBuffer *files_buffer,
+ const unsigned char *data,
+ int size);
+
+/**
+ * Get size of currently used multiple files buffer.
+ * @return size in bytes.
+ */
+extern ssize_t multiple_files_buffer_get_total_size(const MultipleFilesRingBuffer *files_buffer);
+
+/**
+ * Provides info about the multiple files storage directory.
+ * @param path path of the storage directory
+ * @param file_name filename to search for
+ * @param newest pointer to store newest filename
+ * @param oldest pointer to store oldest filename
+ * @return num of files in the directory.
+ */
+unsigned int multiple_files_buffer_storage_dir_info(const char *path, const char *file_name,
+ char *newest, char *oldest);
+
+/**
+ * Creates filename with index.
+ * @param files_buffer pointer to MultipleFilesRingBuffer struct.
+ * @param length the maximum length of the log_file_name.
+ * @param idx index to be used for file name creation.
+ */
+void multiple_files_buffer_file_name(MultipleFilesRingBuffer *files_buffer, size_t length, unsigned int idx);
+
+/**
+ * Generates index for log file name.
+ * @param file filename supplied to create index.
+ * @return the index to be used for log file name.
+ */
+unsigned int multiple_files_buffer_get_idx_of_log_file(char *file);
+
+#endif // DLT_MULTIPLE_FILES_H
diff --git a/include/dlt/dlt_offline_trace.h b/include/dlt/dlt_offline_trace.h
index b5e096c..8e571eb 100644
--- a/include/dlt/dlt_offline_trace.h
+++ b/include/dlt/dlt_offline_trace.h
@@ -57,105 +57,32 @@
#include <limits.h>
+#include "dlt_multiple_files.h"
#include "dlt_types.h"
#define DLT_OFFLINETRACE_FILENAME_BASE "dlt_offlinetrace"
-#define DLT_OFFLINETRACE_FILENAME_INDEX_DELI "."
-#define DLT_OFFLINETRACE_FILENAME_TIMESTAMP_DELI "_"
#define DLT_OFFLINETRACE_FILENAME_EXT ".dlt"
-typedef struct
-{
- char directory[NAME_MAX + 1];/**< (String) Store DLT messages to local directory */
- char filename[NAME_MAX + 1]; /**< (String) Filename of currently used log file */
- int fileSize; /**< (int) Maximum size in bytes of one trace file (Default: 1000000) */
- int maxSize; /**< (int) Maximum size of all trace files (Default: 4000000) */
- int filenameTimestampBased; /**< (int) timestamp based or index based (Default: 1 Timestamp based) */
- int ohandle;
-} DltOfflineTrace;
-
-/**
- * Initialise the offline trace
- * This function call opens the currently used log file.
- * A check of the complete size of the offline trace is done during startup.
- * Old files are deleted, if there is not enough space left to create new file.
- * This function must be called before using further offline trace functions.
- * @param trace pointer to offline trace structure
- * @param directory directory where to store offline trace files
- * @param fileSize maximum size of one offline trace file.
- * @param maxSize maximum size of complete offline trace in bytes.
- *.@param filenameTimestampBased filename to be created on timestamp based or index based
- * @return negative value if there was an error
- */
-extern DltReturnValue dlt_offline_trace_init(DltOfflineTrace *trace,
- const char *directory,
- int fileSize,
- int maxSize,
- int filenameTimestampBased);
-
/**
- * Uninitialise the offline trace
- * This function call closes currently used log file.
- * This function must be called after usage of offline trace
- * @param buf pointer to offline trace structure
- * @return negative value if there was an error
- */
-extern DltReturnValue dlt_offline_trace_free(DltOfflineTrace *buf);
-
-/**
- * Write data into offline trace
+ * Write data into offline traces.
* If the current used log file exceeds the max file size, new log file is created.
- * A check of the complete size of the offline trace is done before new file is created.
+ * A check of the complete size of the offline traces is done before new file is created.
* Old files are deleted, if there is not enough space left to create new file.
- * @param trace pointer to offline trace structure
- * @param data1 pointer to first data block to be written, null if not used
- * @param size1 size in bytes of first data block to be written, 0 if not used
- * @param data2 pointer to second data block to be written, null if not used
- * @param size2 size in bytes of second data block to be written, 0 if not used
- * @param data3 pointer to third data block to be written, null if not used
- * @param size3 size in bytes of third data block to be written, 0 if not used
- * @return negative value if there was an error
+ * @param trace pointer to MultipleFilesRingBuffer struct.
+ * @param data1 pointer to first data block to be written, null if not used.
+ * @param size1 size in bytes of first data block to be written, 0 if not used.
+ * @param data2 pointer to second data block to be written, null if not used.
+ * @param size2 size in bytes of second data block to be written, 0 if not used.
+ * @param data3 pointer to third data block to be written, null if not used.
+ * @param size3 size in bytes of third data block to be written, 0 if not used.
+ * @return negative value if there was an error.
*/
-extern DltReturnValue dlt_offline_trace_write(DltOfflineTrace *trace,
- unsigned char *data1,
+extern DltReturnValue dlt_offline_trace_write(MultipleFilesRingBuffer *trace,
+ const unsigned char *data1,
int size1,
- unsigned char *data2,
+ const unsigned char *data2,
int size2,
- unsigned char *data3,
+ const unsigned char *data3,
int size3);
-/**
- * Get size of currently used offline trace buffer
- * @return size in bytes
- */
-extern ssize_t dlt_offline_trace_get_total_size(DltOfflineTrace *trace);
-
-/**
- * Provides info about the offline logs storage directory
- * @param path path of the storage directory
- * @param file_name filename to search for
- * @param newest pointer to store newest filename
- * @param oldest pointer to store oldest filename
- * @return num of files in the directory
- */
-unsigned int dlt_offline_trace_storage_dir_info(char *path, char *file_name, char *newest, char *oldest);
-
-/**
- * creates filename with index
- * @param log_file_name file name created with index
- * @param length the maximum length of the log_file_name
- * @param name filename base
- * @param idx index to be used for file name creation
- */
-void dlt_offline_trace_file_name(char *log_file_name, size_t length,
- char *name, unsigned int idx);
-
-/**
- * generates index for log file name
- * @param file filename supplied to create index
- * @return the index to be used for log file name
- */
-unsigned int dlt_offline_trace_get_idx_of_log_file(char *file);
-
-
#endif /* DLT_OFFLINE_TRACE_H */
diff --git a/include/dlt/dlt_user.h.in b/include/dlt/dlt_user.h.in
index 2c42603..b377dac 100644
--- a/include/dlt/dlt_user.h.in
+++ b/include/dlt/dlt_user.h.in
@@ -74,6 +74,8 @@
\{
*/
+#include <stdbool.h>
+
#ifndef DLT_NETWORK_TRACE_ENABLE
#cmakedefine DLT_NETWORK_TRACE_ENABLE
#endif
@@ -111,7 +113,7 @@ extern "C" {
#define DLT_SEM_LOCK() do{\
while ((sem_wait(&dlt_mutex) == -1) && (errno == EINTR)) \
continue; /* Restart if interrupted */ \
- } while(0)
+ } while(false)
#define DLT_SEM_FREE() { sem_post(&dlt_mutex); }
/**
diff --git a/include/dlt/dlt_user_macros.h b/include/dlt/dlt_user_macros.h
index f7d8033..1538c4e 100644
--- a/include/dlt/dlt_user_macros.h
+++ b/include/dlt/dlt_user_macros.h
@@ -71,6 +71,8 @@
#include "dlt_version.h"
#include "dlt_types.h"
+#include <stdbool.h>
+
/**
* \defgroup userapi DLT User API
* \addtogroup userapi
@@ -110,27 +112,27 @@
*/
#define DLT_REGISTER_APP(APPID, DESCRIPTION) do { \
(void)dlt_check_library_version(_DLT_PACKAGE_MAJOR_VERSION, _DLT_PACKAGE_MINOR_VERSION); \
- (void)dlt_register_app(APPID, DESCRIPTION); } while (0)
+ (void)dlt_register_app(APPID, DESCRIPTION); } while(false)
/**
* Unregister application.
*/
#define DLT_UNREGISTER_APP() do { \
- (void)dlt_unregister_app(); } while (0)
+ (void)dlt_unregister_app(); } while(false)
/**
* Unregister application and flush the logs buffered in startup buffer if any.
*/
#define DLT_UNREGISTER_APP_FLUSH_BUFFERED_LOGS() do { \
- (void)dlt_unregister_app_flush_buffered_logs(); } while (0)
+ (void)dlt_unregister_app_flush_buffered_logs(); } while(false)
/**
* To Get application ID.
* @Param APPID character pointer of minimum 4 bytes
*/
#define DLT_GET_APPID(APPID) do{\
- dlt_get_appid(APPID);} while(0)
+ dlt_get_appid(APPID);} while(false)
/**
* Register context (with default log level and default trace status)
@@ -139,7 +141,7 @@
* @param DESCRIPTION ASCII string containing description
*/
#define DLT_REGISTER_CONTEXT(CONTEXT, CONTEXTID, DESCRIPTION) do { \
- (void)dlt_register_context(&(CONTEXT), CONTEXTID, DESCRIPTION); } while (0)
+ (void)dlt_register_context(&(CONTEXT), CONTEXTID, DESCRIPTION); } while (false)
/**
* Register context with pre-defined log level and pre-defined trace status.
@@ -152,7 +154,7 @@
* (DLT_TRACE_STATUS_DEFAULT is not allowed here)
*/
#define DLT_REGISTER_CONTEXT_LL_TS(CONTEXT, CONTEXTID, DESCRIPTION, LOGLEVEL, TRACESTATUS) do { \
- (void)dlt_register_context_ll_ts(&(CONTEXT), CONTEXTID, DESCRIPTION, LOGLEVEL, TRACESTATUS); } while (0)
+ (void)dlt_register_context_ll_ts(&(CONTEXT), CONTEXTID, DESCRIPTION, LOGLEVEL, TRACESTATUS); } while (false)
/**
* Register context (with default log level and default trace status and log level change callback)
@@ -162,14 +164,14 @@
* @param CBK log level change callback to be registered
*/
#define DLT_REGISTER_CONTEXT_LLCCB(CONTEXT, CONTEXTID, DESCRIPTION, CBK) do { \
- (void)dlt_register_context_llccb(&(CONTEXT), CONTEXTID, DESCRIPTION, CBK); } while (0)
+ (void)dlt_register_context_llccb(&(CONTEXT), CONTEXTID, DESCRIPTION, CBK); } while(false)
/**
* Unregister context.
* @param CONTEXT object containing information about one special logging context
*/
#define DLT_UNREGISTER_CONTEXT(CONTEXT) do { \
- (void)dlt_unregister_context(&(CONTEXT)); } while (0)
+ (void)dlt_unregister_context(&(CONTEXT)); } while(false)
/**
* Register callback function called when injection message was received
@@ -178,7 +180,7 @@
* @param CALLBACK function pointer to callback function
*/
#define DLT_REGISTER_INJECTION_CALLBACK(CONTEXT, SERVICEID, CALLBACK) do { \
- (void)dlt_register_injection_callback(&(CONTEXT), SERVICEID, CALLBACK); } while (0)
+ (void)dlt_register_injection_callback(&(CONTEXT), SERVICEID, CALLBACK); } while(false)
/**
* Register callback function called when injection message was received
@@ -188,7 +190,7 @@
* @param PRIV_DATA data specific to context
*/
#define DLT_REGISTER_INJECTION_CALLBACK_WITH_ID(CONTEXT, SERVICEID, CALLBACK, PRIV_DATA) do { \
- (void)dlt_register_injection_callback_with_id(&(CONTEXT), SERVICEID, CALLBACK, PRIV_DATA); } while (0)
+ (void)dlt_register_injection_callback_with_id(&(CONTEXT), SERVICEID, CALLBACK, PRIV_DATA); } while(false)
/**
* Register callback function called when log level of context was changed
@@ -196,7 +198,7 @@
* @param CALLBACK function pointer to callback function
*/
#define DLT_REGISTER_LOG_LEVEL_CHANGED_CALLBACK(CONTEXT, CALLBACK) do { \
- (void)dlt_register_log_level_changed_callback(&(CONTEXT), CALLBACK); } while (0)
+ (void)dlt_register_log_level_changed_callback(&(CONTEXT), CALLBACK); } while(false)
/**
* Send log message with variable list of messages (intended for verbose mode)
@@ -221,7 +223,7 @@
__VA_ARGS__; \
(void)dlt_user_log_write_finish(&log_local); \
} \
- } while (0)
+ } while (false)
#endif
/**
@@ -250,7 +252,7 @@
log_local.user_timestamp = (uint32_t) TS; \
(void)dlt_user_log_write_finish(&log_local); \
} \
- } while (0)
+ } while (false)
#endif
/**
@@ -279,7 +281,7 @@
__VA_ARGS__; \
(void)dlt_user_log_write_finish(&log_local); \
} \
- } while (0)
+ } while(false)
#endif
/**
@@ -311,7 +313,7 @@
log_local.user_timestamp = (uint32_t) TS; \
(void)dlt_user_log_write_finish(&log_local); \
} \
- } while (0)
+ } while(false)
#endif
/**
@@ -643,7 +645,7 @@
{ \
(void)dlt_user_trace_network(&(CONTEXT), TYPE, HEADERLEN, HEADER, PAYLOADLEN, PAYLOAD); \
} \
- } while (0)
+ } while(false)
/**
* Trace network message, allow truncation
@@ -660,7 +662,7 @@
{ \
(void)dlt_user_trace_network_truncated(&(CONTEXT), TYPE, HEADERLEN, HEADER, PAYLOADLEN, PAYLOAD, 1); \
} \
- } while (0)
+ } while(false)
/**
* Trace network message, segment large messages
@@ -677,7 +679,7 @@
{ \
(void)dlt_user_trace_network_segmented(&(CONTEXT), TYPE, HEADERLEN, HEADER, PAYLOADLEN, PAYLOAD); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with string parameter.
@@ -691,7 +693,7 @@
{ \
(void)dlt_log_string(&(CONTEXT), LOGLEVEL, TEXT); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with string parameter and integer parameter.
@@ -706,7 +708,7 @@
{ \
(void)dlt_log_string_int(&(CONTEXT), LOGLEVEL, TEXT, INT_VAR); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with string parameter and unsigned integer parameter.
@@ -721,7 +723,7 @@
{ \
(void)dlt_log_string_uint(&(CONTEXT), LOGLEVEL, TEXT, UINT_VAR); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with unsigned integer parameter.
@@ -735,7 +737,7 @@
{ \
(void)dlt_log_uint(&(CONTEXT), LOGLEVEL, UINT_VAR); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with integer parameter.
@@ -749,7 +751,7 @@
{ \
(void)dlt_log_int(&(CONTEXT), LOGLEVEL, INT_VAR); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with binary memory block.
@@ -764,7 +766,7 @@
{ \
(void)dlt_log_raw(&(CONTEXT), LOGLEVEL, BUF, LEN); \
} \
- } while (0)
+ } while(false)
/**
* Send log message with marker.
@@ -772,21 +774,21 @@
#define DLT_LOG_MARKER() \
do { \
(void)dlt_log_marker(); \
- } while (0)
+ } while(false)
/**
* Switch to verbose mode
*
*/
#define DLT_VERBOSE_MODE() do { \
- (void)dlt_verbose_mode(); } while (0)
+ (void)dlt_verbose_mode(); } while(false)
/**
* Switch to non-verbose mode
*
*/
#define DLT_NONVERBOSE_MODE() do { \
- (void)dlt_nonverbose_mode(); } while (0)
+ (void)dlt_nonverbose_mode(); } while(false)
/**
* Set maximum logged log level and trace status of application
@@ -795,21 +797,21 @@
* @param TRACESTATUS This is the trace status to be set for the whole application
*/
#define DLT_SET_APPLICATION_LL_TS_LIMIT(LOGLEVEL, TRACESTATUS) do { \
- (void)dlt_set_application_ll_ts_limit(LOGLEVEL, TRACESTATUS); } while (0)
+ (void)dlt_set_application_ll_ts_limit(LOGLEVEL, TRACESTATUS); } while(false)
/**
* Enable local printing of messages
*
*/
#define DLT_ENABLE_LOCAL_PRINT() do { \
- (void)dlt_enable_local_print(); } while (0)
+ (void)dlt_enable_local_print(); } while(false)
/**
* Disable local printing of messages
*
*/
#define DLT_DISABLE_LOCAL_PRINT() do { \
- (void)dlt_disable_local_print(); } while (0)
+ (void)dlt_disable_local_print(); } while(false)
/**
* Check if log level is enabled
diff --git a/scripts/pre-commit.sample b/scripts/pre-commit.sample
new file mode 100755
index 0000000..5324c3b
--- /dev/null
+++ b/scripts/pre-commit.sample
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+gitclangformat=$(which git-clang-format)
+
+if [ "$gitclangformat" == "" ]
+then
+ gitclangformat=$(find /usr/bin/ -name "git-clang-format*")
+fi
+
+against=`git rev-parse --verify HEAD 2>&1`
+
+if [ $against == "" ]
+then
+ # Initial commit: diff against an empty tree object
+ against=5394c6fa5bf40d9bc8619026cbc4c306211a8499
+fi
+
+$gitclangformat $against -f -q
+
+if [ $? != 0 ]
+then
+ echo "Format error!"
+ echo "Use git clang-format"
+ exit 1
+fi
+
+# Now update format changes and commit
+git add $(git diff --name-only --cached)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e4ff133..6255336 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -25,9 +25,9 @@ if( WITH_DLT_EXAMPLES )
add_subdirectory( examples )
endif( WITH_DLT_EXAMPLES )
-if( WITH_DLT_ADAPTOR )
+if( WITH_DLT_ADAPTOR_STDIN OR WITH_DLT_ADAPTOR_UDP OR WITH_DLT_ADAPTOR )
add_subdirectory( adaptor )
-endif( WITH_DLT_ADAPTOR )
+endif( WITH_DLT_ADAPTOR_STDIN OR WITH_DLT_ADAPTOR_UDP OR WITH_DLT_ADAPTOR )
if( WITH_DLT_TESTS )
add_subdirectory( tests )
diff --git a/src/adaptor/CMakeLists.txt b/src/adaptor/CMakeLists.txt
index 93d6ec5..578bbe8 100644
--- a/src/adaptor/CMakeLists.txt
+++ b/src/adaptor/CMakeLists.txt
@@ -13,18 +13,24 @@
# For further information see http://www.genivi.org/.
#######
-set(dlt_adaptor_stdin_SRCS dlt-adaptor-stdin.c)
-add_executable(dlt-adaptor-stdin ${dlt_adaptor_stdin_SRCS})
-target_link_libraries(dlt-adaptor-stdin dlt)
-set_target_properties(dlt-adaptor-stdin PROPERTIES LINKER_LANGUAGE C)
+if (WITH_DLT_ADAPTOR_STDIN OR WITH_DLT_ADAPTOR)
+ set(dlt_adaptor_stdin_SRCS dlt-adaptor-stdin.c)
+ add_executable(dlt-adaptor-stdin ${dlt_adaptor_stdin_SRCS})
+ target_link_libraries(dlt-adaptor-stdin dlt)
+ set_target_properties(dlt-adaptor-stdin PROPERTIES LINKER_LANGUAGE C)
-set(dlt_adaptor_udp_SRCS dlt-adaptor-udp.c)
-add_executable(dlt-adaptor-udp ${dlt_adaptor_udp_SRCS})
-target_link_libraries(dlt-adaptor-udp dlt)
-set_target_properties(dlt-adaptor-udp PROPERTIES LINKER_LANGUAGE C)
-
-install(TARGETS dlt-adaptor-stdin dlt-adaptor-udp
- RUNTIME DESTINATION bin
- COMPONENT base)
+ install(TARGETS dlt-adaptor-stdin
+ RUNTIME DESTINATION bin
+ COMPONENT base)
+endif()
+if (WITH_DLT_ADAPTOR_UDP OR WITH_DLT_ADAPTOR)
+ set(dlt_adaptor_udp_SRCS dlt-adaptor-udp.c)
+ add_executable(dlt-adaptor-udp ${dlt_adaptor_udp_SRCS})
+ target_link_libraries(dlt-adaptor-udp dlt)
+ set_target_properties(dlt-adaptor-udp PROPERTIES LINKER_LANGUAGE C)
+ install(TARGETS dlt-adaptor-udp
+ RUNTIME DESTINATION bin
+ COMPONENT base)
+endif()
diff --git a/src/android/dlt-logd-converter.cpp b/src/android/dlt-logd-converter.cpp
index 77e37a8..d623b9c 100644
--- a/src/android/dlt-logd-converter.cpp
+++ b/src/android/dlt-logd-converter.cpp
@@ -22,7 +22,6 @@
#include <csignal>
#include <log/log_read.h>
-#include <log/logprint.h>
#include <dlt.h>
@@ -51,7 +50,7 @@ static inline struct logger *init_logger(struct logger_list *logger_list, log_id
static struct logger_list *init_logger_list(bool skip_binary_buffers)
{
struct logger_list *logger_list;
- logger_list = android_logger_list_alloc(ANDROID_LOG_RDONLY, 0, 0);
+ logger_list = android_logger_list_alloc(O_RDONLY, 0, 0);
if (logger_list == nullptr) {
DLT_LOG(dlt_ctx_self, DLT_LOG_FATAL, DLT_STRING("could not allocate logger list"));
return nullptr;
@@ -108,7 +107,7 @@ static uint32_t get_timestamp_from_log_msg(struct log_msg *log_msg)
static DltLogLevelType get_log_level_from_log_msg(struct log_msg *log_msg)
{
- android_LogPriority priority = static_cast<android_LogPriority>(log_msg->buf[0]);
+ android_LogPriority priority = static_cast<android_LogPriority>(log_msg->msg()[0]);
switch (priority) {
case ANDROID_LOG_VERBOSE:
return DLT_LOG_VERBOSE;
diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt
index 521e464..b609405 100644
--- a/src/console/CMakeLists.txt
+++ b/src/console/CMakeLists.txt
@@ -17,11 +17,24 @@ set(dlt_control_common_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dlt-control-common.c)
add_library(dlt_control_common_lib STATIC ${dlt_control_common_SRCS})
target_link_libraries(dlt_control_common_lib dlt ${DLT_JSON_LIBRARY})
-set(TARGET_LIST dlt-convert dlt-receive)
+set(TARGET_LIST "")
+
+if (WITH_DLT_CONSOLE_RECEIVE)
+ list(APPEND TARGET_LIST dlt-receive)
+endif()
+
+if (WITH_DLT_CONSOLE_CONVERT)
+ list(APPEND TARGET_LIST dlt-convert)
+endif()
if(NOT WITH_DLT_CONSOLE_WO_CTRL)
add_subdirectory(logstorage)
- list(APPEND TARGET_LIST dlt-control dlt-passive-node-ctrl)
+ if (WITH_DLT_CONSOLE_CONTROL)
+ list(APPEND TARGET_LIST dlt-control)
+ endif()
+ if (WITH_DLT_CONSOLE_PASSIVE_NODE_CTRL)
+ list(APPEND TARGET_LIST dlt-passive-node-ctrl)
+ endif()
endif()
if(NOT WITH_DLT_CONSOLE_WO_SBTM)
diff --git a/src/console/dlt-control-common.c b/src/console/dlt-control-common.c
index abcaf92..64951c1 100644
--- a/src/console/dlt-control-common.c
+++ b/src/console/dlt-control-common.c
@@ -124,6 +124,8 @@ void set_ecuid(char *ecuid)
if (dlt_parse_config_param("ECUId", &ecuid_conf) == 0) {
memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN);
strncpy(local_ecuid, ecuid_conf, DLT_CTRL_ECUID_LEN);
+ if (ecuid_conf !=NULL)
+ free(ecuid_conf);
local_ecuid[DLT_CTRL_ECUID_LEN - 1] = '\0';
}
else {
diff --git a/src/console/dlt-control.c b/src/console/dlt-control.c
index 7bf091a..8fbf9f0 100644
--- a/src/console/dlt-control.c
+++ b/src/console/dlt-control.c
@@ -212,9 +212,9 @@ void dlt_process_get_log_info(void)
dlt_print_id(apid, app.app_id);
if (app.app_description != 0)
- printf("APID:%4s %s\n", apid, app.app_description);
+ printf("APID:%4.4s %s\n", apid, app.app_description);
else
- printf("APID:%4s \n", apid);
+ printf("APID:%4.4s \n", apid);
for (j = 0; j < app.count_context_ids; j++) {
con = app.context_id_info[j];
@@ -222,13 +222,13 @@ void dlt_process_get_log_info(void)
dlt_print_id(ctid, con.context_id);
if (con.context_description != 0)
- printf("CTID:%4s %2d %2d %s\n",
+ printf("CTID:%4.4s %2d %2d %s\n",
ctid,
con.log_level,
con.trace_status,
con.context_description);
else
- printf("CTID:%4s %2d %2d\n",
+ printf("CTID:%4.4s %2d %2d\n",
ctid,
con.log_level,
con.trace_status);
diff --git a/src/console/dlt-convert.c b/src/console/dlt-convert.c
index b82c104..8c72b60 100644
--- a/src/console/dlt-convert.c
+++ b/src/console/dlt-convert.c
@@ -126,17 +126,6 @@ void usage()
printf(" -t Handling input compressed files (tar.gz)\n");
}
-char *get_filename_ext(const char *filename)
-{
- if (filename == NULL)
- fprintf(stderr, "ERROR: %s: invalid arguments\n", __FUNCTION__);
-
- char *dot = strrchr(filename, '.');
- if(!dot || dot == filename)
- return "";
- return dot + 1;
-}
-
void empty_dir(const char *dir)
{
struct dirent **files = { 0 };
@@ -420,6 +409,7 @@ int main(int argc, char *argv[])
if (ovalue)
close(ohandle);
+ dlt_file_free(&file, vflag);
return -1;
}
@@ -428,35 +418,42 @@ int main(int argc, char *argv[])
if (ovalue)
close(ohandle);
+ dlt_file_free(&file, vflag);
return -1;
}
for (num = begin; num <= end; num++) {
- dlt_file_message(&file, num, vflag);
+ if (dlt_file_message(&file, num, vflag) < DLT_RETURN_OK)
+ continue;
if (xflag) {
printf("%d ", num);
- dlt_message_print_hex(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag);
+ if (dlt_message_print_hex(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
+ continue;
}
else if (aflag) {
printf("%d ", num);
- dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag);
+ if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
+ continue;
printf("%s ", text);
- dlt_message_payload(&file.msg, text, DLT_CONVERT_TEXTBUFSIZE, DLT_OUTPUT_ASCII, vflag);
+ if (dlt_message_payload(&file.msg, text, DLT_CONVERT_TEXTBUFSIZE, DLT_OUTPUT_ASCII, vflag) < DLT_RETURN_OK)
+ continue;
printf("[%s]\n", text);
}
else if (mflag) {
printf("%d ", num);
- dlt_message_print_mixed_plain(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag);
+ if (dlt_message_print_mixed_plain(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
+ continue;
}
else if (sflag) {
printf("%d ", num);
- dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag);
+ if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
+ continue;
printf("%s \n", text);
}
diff --git a/src/console/dlt-receive.c b/src/console/dlt-receive.c
index c985447..dec4713 100644
--- a/src/console/dlt-receive.c
+++ b/src/console/dlt-receive.c
@@ -135,6 +135,7 @@ typedef struct {
DltFile file;
DltFilter filter;
int port;
+ char *ifaddr;
} DltReceiveData;
/**
@@ -161,6 +162,7 @@ void usage()
printf(" -R Enable resync serial header\n");
printf(" -y Serial device mode\n");
printf(" -u UDP multicast mode\n");
+ printf(" -i addr Host interface address\n");
printf(" -b baudrate Serial device baudrate (Default: 115200)\n");
printf(" -e ecuid Set ECU ID (Default: RECV)\n");
printf(" -o filename Output messages in new DLT file\n");
@@ -314,28 +316,13 @@ void dlt_receive_close_output_file(DltReceiveData *dltdata)
int main(int argc, char *argv[])
{
DltReceiveData dltdata;
+ memset(&dltdata, 0, sizeof(dltdata));
int c;
int index;
/* Initialize dltdata */
- dltdata.aflag = 0;
- dltdata.sflag = 0;
- dltdata.xflag = 0;
- dltdata.mflag = 0;
- dltdata.vflag = 0;
- dltdata.yflag = 0;
- dltdata.uflag = 0;
- dltdata.ovalue = 0;
- dltdata.ovaluebase = 0;
- dltdata.fvalue = 0;
- dltdata.jvalue = 0;
- dltdata.evalue = 0;
- dltdata.bvalue = 0;
- dltdata.sendSerialHeaderFlag = 0;
- dltdata.resyncSerialHeaderFlag = 0;
dltdata.climit = -1; /* default: -1 = unlimited */
dltdata.ohandle = -1;
- dltdata.totalbytes = 0;
dltdata.part_num = -1;
dltdata.port = 3490;
@@ -354,7 +341,7 @@ int main(int argc, char *argv[])
/* Fetch command line arguments */
opterr = 0;
- while ((c = getopt (argc, argv, "vashSRyuxmf:j:o:e:b:c:p:")) != -1)
+ while ((c = getopt (argc, argv, "vashSRyuxmf:j:o:e:b:c:p:i:")) != -1)
switch (c) {
case 'v':
{
@@ -406,6 +393,11 @@ int main(int argc, char *argv[])
dltdata.uflag = 1;
break;
}
+ case 'i':
+ {
+ dltdata.ifaddr = optarg;
+ break;
+ }
case 'f':
{
dltdata.fvalue = optarg;
@@ -506,11 +498,31 @@ int main(int argc, char *argv[])
if (dltclient.mode == DLT_CLIENT_MODE_TCP || dltclient.mode == DLT_CLIENT_MODE_UDP_MULTICAST) {
dltclient.port = dltdata.port;
- for (index = optind; index < argc; index++)
- if (dlt_client_set_server_ip(&dltclient, argv[index]) == -1) {
+
+ unsigned int servIPLength = 1; // Counting the terminating 0 byte
+ for (index = optind; index < argc; index++) {
+ servIPLength += strlen(argv[index]);
+ if (index > optind) {
+ servIPLength++; // For the comma delimiter
+ }
+ }
+ if (servIPLength > 1) {
+ char* servIPString = malloc(servIPLength);
+ strcpy(servIPString, argv[optind]);
+
+ for (index = optind + 1; index < argc; index++) {
+ strcat(servIPString, ",");
+ strcat(servIPString, argv[index]);
+ }
+
+ int retval = dlt_client_set_server_ip(&dltclient, servIPString);
+ free(servIPString);
+
+ if (retval == -1) {
fprintf(stderr, "set server ip didn't succeed\n");
return -1;
}
+ }
if (dltclient.servIP == 0) {
/* no hostname selected, show usage and terminate */
@@ -519,6 +531,13 @@ int main(int argc, char *argv[])
dlt_client_cleanup(&dltclient, dltdata.vflag);
return -1;
}
+
+ if (dltdata.ifaddr != 0) {
+ if (dlt_client_set_host_if_address(&dltclient, dltdata.ifaddr) != DLT_RETURN_OK) {
+ fprintf(stderr, "set host interface address didn't succeed\n");
+ return -1;
+ }
+ }
}
else {
for (index = optind; index < argc; index++)
diff --git a/src/console/dlt-sortbytimestamp.c b/src/console/dlt-sortbytimestamp.c
index 3e418e1..82fd5d0 100644
--- a/src/console/dlt-sortbytimestamp.c
+++ b/src/console/dlt-sortbytimestamp.c
@@ -160,7 +160,8 @@ void write_messages(int ohandle, DltFile *file,
if ((0 == i % 1001) || (i == message_count - 1))
verbose(2, "Writing message %d\r", i);
- dlt_file_message(file, timestamps[i].num, 0);
+ if (dlt_file_message(file, timestamps[i].num, 0) < DLT_RETURN_OK)
+ continue;
iov[0].iov_base = file->msg.headerbuffer;
iov[0].iov_len = file->msg.headersize;
iov[1].iov_base = file->msg.databuffer;
@@ -402,7 +403,8 @@ int main(int argc, char *argv[]) {
verbose(1, "Filling %d entries\n", message_count);
for (num = begin; num <= end; num++) {
- dlt_file_message(&file, num, vflag);
+ if (dlt_file_message(&file, num, vflag) < DLT_RETURN_OK)
+ continue;
timestamp_index[num - begin].num = num;
timestamp_index[num - begin].systmsp = file.msg.storageheader->seconds;
timestamp_index[num - begin].tmsp = file.msg.headerextra.tmsp;
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index e4e96bd..c585875 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -32,6 +32,7 @@ set(dlt_daemon_SRCS
${PROJECT_SOURCE_DIR}/src/lib/dlt_client.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_common.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_config_file_parser.c
+ ${PROJECT_SOURCE_DIR}/src/shared/dlt_multiple_files.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_offline_trace.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_protocol.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_user_shared.c
@@ -61,6 +62,12 @@ endif(WITH_UDP_CONNECTION)
add_executable(dlt-daemon ${dlt_daemon_SRCS} ${systemd_SRCS})
target_link_libraries(dlt-daemon ${RT_LIBRARY} ${SOCKET_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
+if (WITH_SYSTEMD_SOCKET_ACTIVATION)
+ target_link_libraries(dlt-daemon systemd)
+endif()
+if (WITH_DLT_LOGSTORAGE_GZIP)
+ target_link_libraries(dlt-daemon ${ZLIB_LIBRARY})
+endif()
install(TARGETS dlt-daemon
RUNTIME DESTINATION bin
diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c
index 74f4049..e56381b 100644
--- a/src/daemon/dlt-daemon.c
+++ b/src/daemon/dlt-daemon.c
@@ -46,6 +46,8 @@
#endif
#include <sys/stat.h>
#include <sys/time.h>
+#include <libgen.h>
+
#if defined(linux) && defined(__NR_statx)
# include <linux/stat.h>
#endif
@@ -338,7 +340,7 @@ int option_file_parser(DltDaemonLocal *daemon_local)
daemon_local->flags.offlineTraceDirectory[0] = 0;
daemon_local->flags.offlineTraceFileSize = 1000000;
daemon_local->flags.offlineTraceMaxSize = 4000000;
- daemon_local->flags.offlineTraceFilenameTimestampBased = 1;
+ daemon_local->flags.offlineTraceFilenameTimestampBased = true;
daemon_local->flags.loggingMode = DLT_LOG_TO_CONSOLE;
daemon_local->flags.loggingLevel = LOG_INFO;
@@ -356,6 +358,9 @@ int option_file_parser(DltDaemonLocal *daemon_local)
dlt_vlog(LOG_WARNING, "%s: snprintf truncation/error(%ld) %s\n",
__func__, n, daemon_local->flags.loggingFilename);
}
+ daemon_local->flags.enableLoggingFileLimit = false;
+ daemon_local->flags.loggingFileSize = 250000;
+ daemon_local->flags.loggingFileMaxSize = 1000000;
daemon_local->timeoutOnSend = 4;
daemon_local->RingbufferMinSize = DLT_DAEMON_RINGBUFFER_MIN_SIZE;
@@ -514,7 +519,7 @@ int option_file_parser(DltDaemonLocal *daemon_local)
}
else if (strcmp(token, "LoggingMode") == 0)
{
- daemon_local->flags.loggingMode = atoi(value);
+ daemon_local->flags.loggingMode = (DltLoggingMode)atoi(value);
/*printf("Option: %s=%s\n",token,value); */
}
else if (strcmp(token, "LoggingLevel") == 0)
@@ -530,6 +535,18 @@ int option_file_parser(DltDaemonLocal *daemon_local)
daemon_local->flags.loggingFilename[sizeof(daemon_local->flags.loggingFilename) - 1] = 0;
/*printf("Option: %s=%s\n",token,value); */
}
+ else if (strcmp(token, "EnableLoggingFileLimit") == 0)
+ {
+ daemon_local->flags.enableLoggingFileLimit = (bool)atoi(value);
+ }
+ else if (strcmp(token, "LoggingFileSize") == 0)
+ {
+ daemon_local->flags.loggingFileSize = atoi(value);
+ }
+ else if (strcmp(token, "LoggingFileMaxSize") == 0)
+ {
+ daemon_local->flags.loggingFileMaxSize = atoi(value);
+ }
else if (strcmp(token, "TimeOutOnSend") == 0)
{
daemon_local->timeoutOnSend = atoi(value);
@@ -578,7 +595,7 @@ int option_file_parser(DltDaemonLocal *daemon_local)
}
else if (strcmp(token, "OfflineTraceFileNameTimestampBased") == 0)
{
- daemon_local->flags.offlineTraceFilenameTimestampBased = atoi(value);
+ daemon_local->flags.offlineTraceFilenameTimestampBased = (bool)atoi(value);
/*printf("Option: %s=%s\n",token,value); */
}
else if (strcmp(token, "SendECUSoftwareVersion") == 0)
@@ -940,7 +957,28 @@ int main(int argc, char *argv[])
/* Initialize internal logging facility */
dlt_log_set_filename(daemon_local.flags.loggingFilename);
dlt_log_set_level(daemon_local.flags.loggingLevel);
- dlt_log_init(daemon_local.flags.loggingMode);
+ DltReturnValue log_init_result =
+ dlt_log_init_multiple_logfiles_support(daemon_local.flags.loggingMode,
+ daemon_local.flags.enableLoggingFileLimit,
+ daemon_local.flags.loggingFileSize,
+ daemon_local.flags.loggingFileMaxSize);
+
+ if (log_init_result != DLT_RETURN_OK) {
+ fprintf(stderr, "Failed to init internal logging\n");
+
+#if WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK
+ if (daemon_local.flags.loggingMode == DLT_LOG_TO_FILE) {
+ fprintf(stderr, "Falling back to syslog mode\n");
+
+ daemon_local.flags.loggingMode = DLT_LOG_TO_SYSLOG;
+ log_init_result = dlt_log_init(daemon_local.flags.loggingMode);
+ if (log_init_result != DLT_RETURN_OK) {
+ fprintf(stderr, "Failed to setup syslog logging, internal logs will "
+ "not be available\n");
+ }
+ }
+#endif
+ }
/* Print version information */
dlt_get_version(version, DLT_DAEMON_TEXTBUFSIZE);
@@ -955,7 +993,7 @@ int main(int argc, char *argv[])
if (dlt_mkdir_recursive(dltFifoBaseDir) != 0) {
dlt_vlog(LOG_ERR, "Base dir %s cannot be created!\n", dltFifoBaseDir);
return -1;
- }
+ }
#else
if (dlt_mkdir_recursive(DLT_USER_IPC_PATH) != 0) {
@@ -991,7 +1029,7 @@ int main(int argc, char *argv[])
dlt_log(LOG_ERR, "Could not load runtime config\n");
return -1;
}
-
+
/*
* Load dlt-runtime.cfg if available.
* This must be loaded before offline setup
@@ -1045,7 +1083,7 @@ int main(int argc, char *argv[])
/* initiate gateway */
if (daemon_local.flags.gatewayMode == 1) {
if (dlt_gateway_init(&daemon_local, daemon_local.flags.vflag) == -1) {
- dlt_log(LOG_CRIT, "Fail to create gateway\n");
+ dlt_log(LOG_CRIT, "Failed to create gateway\n");
return -1;
}
@@ -1108,6 +1146,8 @@ int main(int argc, char *argv[])
dlt_log(LOG_NOTICE, "Leaving DLT daemon\n");
+ dlt_log_free();
+
return 0;
} /* main() */
@@ -1150,11 +1190,6 @@ int dlt_daemon_local_init_p1(DltDaemon *daemon, DltDaemonLocal *daemon_local, in
if (daemon_local->flags.dflag)
dlt_daemon_daemonize(daemon_local->flags.vflag);
- /* Re-Initialize internal logging facility after fork */
- dlt_log_set_filename(daemon_local->flags.loggingFilename);
- dlt_log_set_level(daemon_local->flags.loggingLevel);
- dlt_log_init(daemon_local->flags.loggingMode);
-
/* initialise structure to use DLT file */
ret = dlt_file_init(&(daemon_local->file), daemon_local->flags.vflag);
@@ -1200,11 +1235,14 @@ int dlt_daemon_local_init_p2(DltDaemon *daemon, DltDaemonLocal *daemon_local, in
/* init offline trace */
if (((daemon->mode == DLT_USER_MODE_INTERNAL) || (daemon->mode == DLT_USER_MODE_BOTH)) &&
daemon_local->flags.offlineTraceDirectory[0]) {
- if (dlt_offline_trace_init(&(daemon_local->offlineTrace),
- daemon_local->flags.offlineTraceDirectory,
- daemon_local->flags.offlineTraceFileSize,
- daemon_local->flags.offlineTraceMaxSize,
- daemon_local->flags.offlineTraceFilenameTimestampBased) == -1) {
+ if (multiple_files_buffer_init(&(daemon_local->offlineTrace),
+ daemon_local->flags.offlineTraceDirectory,
+ daemon_local->flags.offlineTraceFileSize,
+ daemon_local->flags.offlineTraceMaxSize,
+ daemon_local->flags.offlineTraceFilenameTimestampBased,
+ false,
+ DLT_OFFLINETRACE_FILENAME_BASE,
+ DLT_OFFLINETRACE_FILENAME_EXT) == -1) {
dlt_log(LOG_ERR, "Could not initialize offline trace\n");
return -1;
}
@@ -1621,6 +1659,7 @@ int dlt_daemon_local_connection_init(DltDaemon *daemon,
}
}
else {
+ bool any_open = false;
while (head != NULL) { /* open socket for each IP in the bindAddress list */
if (dlt_daemon_socket_open(&fd, daemon_local->flags.port, head->ip) == DLT_RETURN_OK) {
@@ -1629,17 +1668,22 @@ int dlt_daemon_local_connection_init(DltDaemon *daemon,
fd,
POLLIN,
DLT_CONNECTION_CLIENT_CONNECT)) {
- dlt_log(LOG_ERR, "Could not initialize main socket.\n");
- return DLT_RETURN_ERROR;
+ dlt_vlog(LOG_ERR, "Could not create connection, for binding %s\n", head->ip);
+ } else {
+ any_open = true;
}
}
else {
- dlt_log(LOG_ERR, "Could not initialize main socket.\n");
- return DLT_RETURN_ERROR;
+ dlt_vlog(LOG_ERR, "Could not open main socket, for binding %s\n", head->ip);
}
head = head->next;
}
+
+ if (!any_open) {
+ dlt_vlog(LOG_ERR, "Failed create main socket for any configured binding\n");
+ return DLT_RETURN_ERROR;
+ }
}
#ifdef UDP_CONNECTION_SUPPORT
@@ -1762,7 +1806,7 @@ void dlt_daemon_local_cleanup(DltDaemon *daemon, DltDaemonLocal *daemon_local, i
/* free shared memory */
if (daemon_local->flags.offlineTraceDirectory[0])
- dlt_offline_trace_free(&(daemon_local->offlineTrace));
+ multiple_files_buffer_free(&(daemon_local->offlineTrace));
/* Ignore result */
dlt_file_free(&(daemon_local->file), daemon_local->flags.vflag);
@@ -2133,6 +2177,8 @@ int dlt_daemon_process_client_connect(DltDaemon *daemon,
if (dlt_daemon_send_ringbuffer_to_client(daemon, daemon_local, verbose) == -1) {
dlt_log(LOG_WARNING, "Can't send contents of ringbuffer to clients\n");
+ close(in_sock);
+ in_sock = -1;
return -1;
}
@@ -3177,8 +3223,10 @@ int dlt_daemon_process_user_message_log(DltDaemon *daemon,
return DLT_DAEMON_ERROR_UNKNOWN;
}
- ret = dlt_daemon_client_send_message_to_all_client(daemon,
- daemon_local, verbose);
+ /* discard non-allowed levels if enforcement is on */
+ bool keep_message = enforce_context_ll_and_ts_keep_message(daemon_local);
+ if (keep_message)
+ dlt_daemon_client_send_message_to_all_client(daemon, daemon_local, verbose);
if (DLT_DAEMON_ERROR_OK != ret)
dlt_log(LOG_ERR, "failed to send message to client.\n");
@@ -3205,7 +3253,10 @@ int dlt_daemon_process_user_message_log(DltDaemon *daemon,
return DLT_DAEMON_ERROR_UNKNOWN;
}
- dlt_daemon_client_send_message_to_all_client(daemon, daemon_local, verbose);
+ /* discard non-allowed levels if enforcement is on */
+ bool keep_message = enforce_context_ll_and_ts_keep_message(daemon_local);
+ if (keep_message)
+ dlt_daemon_client_send_message_to_all_client(daemon, daemon_local, verbose);
/* keep not read data in buffer */
size = (int) (daemon_local->msg.headersize +
@@ -3225,6 +3276,18 @@ int dlt_daemon_process_user_message_log(DltDaemon *daemon,
return DLT_DAEMON_ERROR_OK;
}
+bool enforce_context_ll_and_ts_keep_message(DltDaemonLocal *daemon_local) {
+ if (daemon_local->flags.enforceContextLLAndTS &&
+ daemon_local->msg.extendedheader) {
+ const int mtin = DLT_GET_MSIN_MTIN(daemon_local->msg.extendedheader->msin);
+ if (mtin > daemon_local->flags.contextLogLevel) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
int dlt_daemon_process_user_message_set_app_ll_ts(DltDaemon *daemon,
DltDaemonLocal *daemon_local,
DltReceiver *rec,
diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h
index 7a4b29c..cc879cb 100644
--- a/src/daemon/dlt-daemon.h
+++ b/src/daemon/dlt-daemon.h
@@ -69,6 +69,7 @@
#include <limits.h> /* for NAME_MAX */
#include <sys/time.h>
+#include <stdarg.h>
#include "dlt_daemon_common.h"
#include "dlt_user_shared.h"
@@ -103,10 +104,13 @@ typedef struct
char offlineTraceDirectory[DLT_DAEMON_FLAG_MAX]; /**< (String: Directory) Store DLT messages to local directory (Default: /etc/dlt.conf) */
int offlineTraceFileSize; /**< (int) Maximum size in bytes of one trace file (Default: 1000000) */
int offlineTraceMaxSize; /**< (int) Maximum size of all trace files (Default: 4000000) */
- int offlineTraceFilenameTimestampBased; /**< (int) timestamp based or index based (Default: 1 Timestamp based) */
- int loggingMode; /**< (int) The logging console for internal logging of dlt-daemon (Default: 0) */
+ bool offlineTraceFilenameTimestampBased; /**< (Boolean) timestamp based or index based (Default: true=Timestamp based) */
+ DltLoggingMode loggingMode; /**< (int) The logging console for internal logging of dlt-daemon (Default: 0) */
int loggingLevel; /**< (int) The logging level for internal logging of dlt-daemon (Default: 6) */
char loggingFilename[DLT_DAEMON_FLAG_MAX]; /**< (String: Filename) The logging filename if internal logging mode is log to file (Default: /tmp/log) */
+ bool enableLoggingFileLimit; /**< (Boolean) Indicate whether size of logging file(s) is limited (Default: false) */
+ int loggingFileSize; /**< (int) Maximum size in bytes of one logging file (Default: 250000) */
+ int loggingFileMaxSize; /**< (int) Maximum size in bytes of all logging files (Default: 1000000) */
int sendECUSoftwareVersion; /**< (Boolean) Send ECU software version perdiodically */
char pathToECUSoftwareVersion[DLT_DAEMON_FLAG_MAX]; /**< (String: Filename) The file from which to read the ECU version from. */
int sendTimezone; /**< (Boolean) Send Timezone perdiodically */
@@ -154,7 +158,8 @@ typedef struct
DltShm dlt_shm; /**< Shared memory handling */
unsigned char *recv_buf_shm; /**< buffer for receive message from shm */
#endif
- DltOfflineTrace offlineTrace; /**< Offline trace handling */
+ MultipleFilesRingBuffer offlineTrace; /**< Offline trace handling */
+ MultipleFilesRingBuffer dltLogging; /**< Dlt logging handling */
int timeoutOnSend;
unsigned long RingbufferMinSize;
unsigned long RingbufferMaxSize;
@@ -249,6 +254,9 @@ int dlt_daemon_process_user_message_log(DltDaemon *daemon,
DltDaemonLocal *daemon_local,
DltReceiver *rec,
int verbose);
+
+bool enforce_context_ll_and_ts_keep_message(DltDaemonLocal *daemon_local);
+
int dlt_daemon_process_user_message_set_app_ll_ts(DltDaemon *daemon,
DltDaemonLocal *daemon_local,
DltReceiver *rec,
@@ -270,4 +278,3 @@ int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in,
int dlt_daemon_close_socket(int sock, DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
#endif /* DLT_DAEMON_H */
-
diff --git a/src/daemon/dlt.conf b/src/daemon/dlt.conf
index 7e19817..11a5057 100644
--- a/src/daemon/dlt.conf
+++ b/src/daemon/dlt.conf
@@ -46,8 +46,19 @@ LoggingMode = 0
LoggingLevel = 6
# The logging filename if internal logging mode is log to file (Default: /tmp/dlt.log)
+# If access to the file is not possible, the daemon will fall back to syslog
+# if WITH_DLT_FILE_LOGGING_SYSLOG_FALLBACK is set as compile flag
LoggingFilename = /tmp/dlt.log
+# Indicate whether size of logging file(s) is limited (Default: 0)
+EnableLoggingFileLimit = 0
+
+# Maximum size in bytes of one logging file (Default: 250000)
+# LoggingFileSize = 250000
+
+# Maximum size in bytes of all logging files (Default: 1000000)
+# LoggingFileMaxSize = 1000000
+
# Timeout on send to client (sec)
TimeOutOnSend = 4
diff --git a/src/daemon/dlt_daemon_client.c b/src/daemon/dlt_daemon_client.c
index becd061..b256988 100644
--- a/src/daemon/dlt_daemon_client.c
+++ b/src/daemon/dlt_daemon_client.c
@@ -484,7 +484,7 @@ int dlt_daemon_client_process_control(int sock,
/* check if the message needs to be forwarded */
if (daemon_local->flags.gatewayMode == 1) {
- if (strcmp(daemon_local->flags.evalue, extra.ecu) != 0)
+ if (strncmp(daemon_local->flags.evalue, extra.ecu, DLT_ID_SIZE) != 0)
return dlt_gateway_forward_control_message(&daemon_local->pGateway,
daemon_local,
msg,
@@ -1085,7 +1085,7 @@ void dlt_daemon_control_get_log_info(int sock,
daemon->ecuid,
verbose);
- if (application) {
+ if ((user_list->applications) && (application)) {
/* Calculate start offset within contexts[] */
offset_base = 0;
@@ -1622,7 +1622,7 @@ void dlt_daemon_control_callsw_cinjection(int sock,
/* write to FIFO */
DltReturnValue ret =
- dlt_user_log_out3(context->user_handle, &(userheader), sizeof(DltUserHeader),
+ dlt_user_log_out3_with_timeout(context->user_handle, &(userheader), sizeof(DltUserHeader),
&(usercontext), sizeof(DltUserControlMsgInjection),
userbuffer, (size_t) data_length_inject);
@@ -1690,7 +1690,7 @@ void dlt_daemon_find_multiple_context_and_send_log_level(int sock,
int count = 0;
DltDaemonContext *context = NULL;
char src_str[DLT_ID_SIZE + 1] = { 0 };
- int8_t ret = 0;
+ int ret = 0;
DltDaemonRegisteredUsers *user_list = NULL;
if (daemon == 0) {
@@ -1712,7 +1712,7 @@ void dlt_daemon_find_multiple_context_and_send_log_level(int sock,
else
strncpy(src_str, context->ctid, DLT_ID_SIZE);
- ret = (int8_t) strncmp(src_str, str, (size_t) len);
+ ret = strncmp(src_str, str, len);
if (ret == 0)
dlt_daemon_send_log_level(sock, daemon, daemon_local, context, loglevel, verbose);
@@ -1863,7 +1863,7 @@ void dlt_daemon_find_multiple_context_and_send_trace_status(int sock,
int count = 0;
DltDaemonContext *context = NULL;
char src_str[DLT_ID_SIZE + 1] = { 0 };
- int8_t ret = 0;
+ int ret = 0;
DltDaemonRegisteredUsers *user_list = NULL;
if (daemon == 0) {
@@ -1885,7 +1885,7 @@ void dlt_daemon_find_multiple_context_and_send_trace_status(int sock,
else
strncpy(src_str, context->ctid, DLT_ID_SIZE);
- ret = (int8_t) strncmp(src_str, str, (size_t) len);
+ ret = strncmp(src_str, str, len);
if (ret == 0)
dlt_daemon_send_trace_status(sock, daemon, daemon_local, context, tracestatus, verbose);
diff --git a/src/daemon/dlt_daemon_common.c b/src/daemon/dlt_daemon_common.c
index 6ba5935..c5fcbb1 100644
--- a/src/daemon/dlt_daemon_common.c
+++ b/src/daemon/dlt_daemon_common.c
@@ -1380,7 +1380,7 @@ int dlt_daemon_user_send_log_level(DltDaemon *daemon, DltDaemonContext *context,
/* log to FIFO */
errno = 0;
- ret = dlt_user_log_out2(context->user_handle,
+ ret = dlt_user_log_out2_with_timeout(context->user_handle,
&(userheader), sizeof(DltUserHeader),
&(usercontext), sizeof(DltUserControlMsgLogLevel));
@@ -1416,7 +1416,7 @@ int dlt_daemon_user_send_log_state(DltDaemon *daemon, DltDaemonApplication *app,
logstate.log_state = daemon->connectionState;
/* log to FIFO */
- ret = dlt_user_log_out2(app->user_handle,
+ ret = dlt_user_log_out2_with_timeout(app->user_handle,
&(userheader), sizeof(DltUserHeader),
&(logstate), sizeof(DltUserControlMsgLogState));
diff --git a/src/daemon/dlt_daemon_common.h b/src/daemon/dlt_daemon_common.h
index f650ce3..1a07491 100644
--- a/src/daemon/dlt_daemon_common.h
+++ b/src/daemon/dlt_daemon_common.h
@@ -99,7 +99,7 @@ extern "C" {
#define DLT_DAEMON_SEM_LOCK() do{\
while ((sem_wait(&dlt_daemon_mutex) == -1) && (errno == EINTR)) \
continue; /* Restart if interrupted */ \
- } while(0)
+ } while(false)
#define DLT_DAEMON_SEM_FREE() { sem_post(&dlt_daemon_mutex); }
extern sem_t dlt_daemon_mutex;
diff --git a/src/daemon/dlt_daemon_connection.c b/src/daemon/dlt_daemon_connection.c
index 805afed..1658e26 100644
--- a/src/daemon/dlt_daemon_connection.c
+++ b/src/daemon/dlt_daemon_connection.c
@@ -402,6 +402,21 @@ int dlt_connection_create(DltDaemonLocal *daemon_local,
return -1;
}
+ struct timeval timeout;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+ char *watchdogUSec = getenv("WATCHDOG_USEC");
+ if (watchdogUSec) {
+ timeout.tv_sec = atoi(watchdogUSec) / 1000000;
+ timeout.tv_usec = atoi(watchdogUSec) % 1000000;
+ }
+#endif
+
+ if (setsockopt (temp->receiver->fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout) < 0) {
+ dlt_vlog(LOG_WARNING, "Unable to set send timeout %s.\n", strerror(errno));
+ }
+
/* We are single threaded no need for protection. */
temp->id = connectionId++;
diff --git a/src/daemon/dlt_daemon_offline_logstorage.c b/src/daemon/dlt_daemon_offline_logstorage.c
index 5d21a76..c796d06 100644
--- a/src/daemon/dlt_daemon_offline_logstorage.c
+++ b/src/daemon/dlt_daemon_offline_logstorage.c
@@ -233,9 +233,14 @@ DLT_STATIC DltReturnValue dlt_logstorage_split_multi(char *key,
else {
strncpy(ecuid, tok, DLT_ID_SIZE);
tok = strtok(NULL, ":");
- strncpy(apid, tok, DLT_ID_SIZE);
+
+ if (tok != NULL)
+ strncpy(apid, tok, DLT_ID_SIZE);
+
tok = strtok(NULL, ":");
- strncpy(ctid, tok, DLT_ID_SIZE);
+
+ if (tok != NULL)
+ strncpy(ctid, tok, DLT_ID_SIZE);
}
return DLT_RETURN_OK;
diff --git a/src/daemon/dlt_daemon_unix_socket.c b/src/daemon/dlt_daemon_unix_socket.c
index ea889b0..4b9f472 100644
--- a/src/daemon/dlt_daemon_unix_socket.c
+++ b/src/daemon/dlt_daemon_unix_socket.c
@@ -38,6 +38,9 @@
#include <sys/stat.h>
#include <syslog.h>
#include <errno.h>
+#if DLT_SYSTEM_SOCKET_ACTIVATION_ENABLE
+#include <systemd/sd-daemon.h>
+#endif
#include "dlt-daemon.h"
#include "dlt_common.h"
@@ -91,6 +94,48 @@ int dlt_daemon_unix_socket_open(int *sock, char *sock_path, int type, int mask)
return -1;
}
+#ifdef DLT_SYSTEM_SOCKET_ACTIVATION_ENABLE
+
+ char **names = NULL;
+ const int num_fds = sd_listen_fds_with_names(0, &names);
+ bool sd_socket_open = false;
+ int i;
+
+ if (num_fds <= 0) {
+ dlt_vlog(LOG_WARNING, "unix socket: no sockets configured via systemd, error: %s\n", strerror(errno));
+ } else {
+ for (i = 0; i < num_fds; ++i) {
+ if (strcmp(sock_path, names[i]) != 0) {
+ continue;
+ }
+
+ if (sd_is_socket_unix(i + SD_LISTEN_FDS_START, type, 1, names[i], strlen(names[i])) < 0) {
+ dlt_vlog(LOG_WARNING,
+ "unix socket: socket with matching name is not of correct type or not in listen mode, error: %s\n",
+ strerror(errno));
+ continue;
+ }
+
+ *sock = i + SD_LISTEN_FDS_START;
+ sd_socket_open = true;
+ dlt_vlog(LOG_INFO, "unix socket: sock_path %s found systemd socket %s\n", sock_path, names[i]);
+ break;
+ }
+
+ /*
+ * The caller [of sd_listen_fds_with_names] needs to free the array
+ * itself and each of its elements with libc's free() call after use.
+ * */
+ for (i = 0; i < num_fds; ++i) {
+ free(names[i]);
+ }
+ free(names);
+ }
+
+ if (!sd_socket_open) {
+ dlt_vlog(LOG_INFO, "unix socket: sock_path %s no systemd socket found\n", sock_path);
+#endif
+
if ((*sock = socket(AF_UNIX, type, 0)) == -1) {
dlt_log(LOG_WARNING, "unix socket: socket() error");
return -1;
@@ -118,6 +163,11 @@ int dlt_daemon_unix_socket_open(int *sock, char *sock_path, int type, int mask)
/* restore permissions */
umask(old_mask);
+#ifdef DLT_SYSTEM_SOCKET_ACTIVATION_ENABLE
+ } // end of: if (!sd_socket_open) {
+#endif
+
+
return 0;
}
diff --git a/src/gateway/dlt_gateway.c b/src/gateway/dlt_gateway.c
index 9d0041d..3d832ce 100644
--- a/src/gateway/dlt_gateway.c
+++ b/src/gateway/dlt_gateway.c
@@ -669,6 +669,9 @@ int dlt_gateway_configure(DltGateway *gateway, char *config_file, int verbose)
/* read configuration file */
file = dlt_config_file_init(config_file);
+ if(file == NULL) {
+ return DLT_RETURN_ERROR;
+ }
/* get number of entries and allocate memory to store information */
ret = dlt_config_file_get_num_sections(file, &num_sections);
@@ -791,6 +794,10 @@ int dlt_gateway_configure(DltGateway *gateway, char *config_file, int verbose)
configuration_entries[j].key, value);
}
+ if (!tmp.ip_address) {
+ invalid = 1;
+ }
+
if (invalid) {
dlt_vlog(LOG_ERR,
"%s configuration is invalid.\n"
@@ -1285,6 +1292,7 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
DltGateway *gateway = NULL;
DltGatewayConnection *con = NULL;
DltMessage msg = { 0 };
+ bool b_reset_receiver = false;
if ((daemon == NULL) || (daemon_local == NULL) || (receiver == NULL)) {
dlt_vlog(LOG_ERR, "%s: wrong parameter\n", __func__);
@@ -1301,13 +1309,11 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
}
for (i = 0; i < gateway->num_connections; i++)
- if (gateway->connections[i].client.sock == receiver->fd) {
+ if ((gateway->connections[i].status == DLT_GATEWAY_CONNECTED) && (gateway->connections[i].client.sock == receiver->fd)) {
con = &gateway->connections[i];
break;
}
-
-
if (con == NULL) {
dlt_log(LOG_ERR, "Cannot associate fd to passive Node connection\n");
return DLT_RETURN_ERROR;
@@ -1358,14 +1364,15 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
sizeof(DltStandardHeader));
/* only forward messages if the received ECUid is the expected one */
- if (strncmp(header->ecu, con->ecuid, strlen(con->ecuid)) == 0) {
+ if (strncmp(header->ecu, con->ecuid, DLT_ID_SIZE) == 0) {
uint32_t id;
uint32_t id_tmp;
DltPassiveControlMessage *control_msg = con->p_control_msgs;
dlt_vlog(LOG_DEBUG,
- "Received ECUid (%s) similar to configured ECUid(%s). "
+ "Received ECUid (%.*s) similar to configured ECUid(%s). "
"Forwarding message (%s).\n",
+ DLT_ID_SIZE,
header->ecu,
con->ecuid,
msg.databuffer);
@@ -1428,8 +1435,9 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
verbose);
} else { /* otherwise remove this connection and do not connect again */
dlt_vlog(LOG_WARNING,
- "Received ECUid (%s) differs to configured ECUid(%s). "
+ "Received ECUid (%.*s) differs to configured ECUid(%s). "
"Discard this message.\n",
+ DLT_ID_SIZE,
header->ecu,
con->ecuid);
@@ -1445,6 +1453,11 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
dlt_log(LOG_WARNING,
"Disconnect from passive node due to invalid ECUid\n");
+
+ /* it is possible that a partial log was received through the last recv call */
+ /* however, the rest will never be received since the socket will be closed by above method */
+ /* as such, we need to reset the receiver to prevent permanent corruption */
+ b_reset_receiver = true;
}
if (msg.found_serialheader) {
@@ -1468,6 +1481,9 @@ DltReturnValue dlt_gateway_process_passive_node_messages(DltDaemon *daemon,
}
}
+ if (b_reset_receiver)
+ dlt_receiver_remove(receiver, receiver->bytesRcvd);
+
if (dlt_receiver_move_to_begin(receiver) == -1) {
/* Return value ignored */
dlt_message_free(&msg, verbose);
@@ -1539,7 +1555,7 @@ int dlt_gateway_forward_control_message(DltGateway *gateway,
for (i = 0; i < gateway->num_connections; i++)
if (strncmp(gateway->connections[i].ecuid,
ecu,
- strlen(gateway->connections[i].ecuid)) == 0) {
+ DLT_ID_SIZE) == 0) {
con = &gateway->connections[i];
break;
}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 3293376..e6d6334 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -19,6 +19,7 @@ set(dlt_LIB_SRCS
dlt_filetransfer.c
dlt_env_ll.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_common.c
+ ${PROJECT_SOURCE_DIR}/src/shared/dlt_multiple_files.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_protocol.c
${PROJECT_SOURCE_DIR}/src/shared/dlt_user_shared.c
)
diff --git a/src/lib/dlt_client.c b/src/lib/dlt_client.c
index 174cfa0..552ee7a 100644
--- a/src/lib/dlt_client.c
+++ b/src/lib/dlt_client.c
@@ -91,6 +91,7 @@
#include <string.h> /* for strlen(), memcmp(), memmove() */
#include <errno.h>
#include <limits.h>
+#include <poll.h>
#include "dlt_types.h"
#include "dlt_client.h"
@@ -171,13 +172,19 @@ DltReturnValue dlt_client_init(DltClient *client, int verbose)
DltReturnValue dlt_client_connect(DltClient *client, int verbose)
{
const int yes = 1;
- char portnumbuffer[33];
+ char portnumbuffer[33] = {0};
struct addrinfo hints, *servinfo, *p;
struct sockaddr_un addr;
int rv;
struct ip_mreq mreq;
DltReceiverType receiver_type = DLT_RECEIVE_FD;
+ struct pollfd pfds[1];
+ int ret;
+ int n;
+ socklen_t m = sizeof(n);
+ int connect_errno = 0;
+
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
@@ -205,27 +212,80 @@ DltReturnValue dlt_client_connect(DltClient *client, int verbose)
continue;
}
- if (connect(client->sock, p->ai_addr, p->ai_addrlen) < 0) {
+ /* Set socket to Non-blocking mode */
+ if(fcntl(client->sock, F_SETFL, fcntl(client->sock,F_GETFL,0) | O_NONBLOCK) < 0)
+ {
+ dlt_vlog(LOG_WARNING,
+ "%s: Socket cannot be changed to NON BLOCK: %s\n",
+ __func__, strerror(errno));
close(client->sock);
continue;
}
+ if (connect(client->sock, p->ai_addr, p->ai_addrlen) < 0) {
+ if (errno == EINPROGRESS) {
+ pfds[0].fd = client->sock;
+ pfds[0].events = POLLOUT;
+ ret = poll(pfds, 1, 500);
+ if (ret < 0) {
+ dlt_vlog(LOG_ERR, "%s: Failed to poll with err [%s]\n",
+ __func__, strerror(errno));
+ close(client->sock);
+ continue;
+ }
+ else if ((pfds[0].revents & POLLOUT) &&
+ getsockopt(client->sock, SOL_SOCKET,
+ SO_ERROR, (void*)&n, &m) == 0) {
+ if (n == 0) {
+ dlt_vlog(LOG_DEBUG, "%s: Already connect\n", __func__);
+ if(fcntl(client->sock, F_SETFL,
+ fcntl(client->sock,F_GETFL,0) & ~O_NONBLOCK) < 0) {
+ dlt_vlog(LOG_WARNING,
+ "%s: Socket cannot be changed to BLOCK with err [%s]\n",
+ __func__, strerror(errno));
+ close(client->sock);
+ continue;
+ }
+ }
+ else {
+ connect_errno = n;
+ close(client->sock);
+ continue;
+ }
+ }
+ else {
+ connect_errno = errno;
+ close(client->sock);
+ continue;
+ }
+ }
+ else {
+ connect_errno = errno;
+ close(client->sock);
+ continue;
+ }
+ }
+
break;
}
freeaddrinfo(servinfo);
if (p == NULL) {
+ dlt_vlog(LOG_ERR,
+ "%s: ERROR: failed to connect! %s\n",
+ __func__,
+ strerror(connect_errno));
+ return DLT_RETURN_ERROR;
+ }
+
+ if (verbose) {
dlt_vlog(LOG_INFO,
"%s: Connected to DLT daemon (%s)\n",
__func__,
client->servIP);
- return DLT_RETURN_ERROR;
}
- if (verbose)
- printf("Connected to DLT daemon (%s)\n", client->servIP);
-
receiver_type = DLT_RECEIVE_SOCKET;
break;
@@ -368,27 +428,32 @@ DltReturnValue dlt_client_connect(DltClient *client, int verbose)
return DLT_RETURN_ERROR;
}
- mreq.imr_multiaddr.s_addr = inet_addr(client->servIP);
- if (mreq.imr_multiaddr.s_addr == (in_addr_t)-1)
- {
- dlt_vlog(LOG_ERR,
- "%s: ERROR: server address not not valid %s\n",
- __func__,
- client->servIP);
+ char delimiter[] = ",";
+ char* servIP = strtok(client->servIP, delimiter);
- return DLT_RETURN_ERROR;
- }
+ while(servIP != NULL) {
+ mreq.imr_multiaddr.s_addr = inet_addr(servIP);
+ if (mreq.imr_multiaddr.s_addr == (in_addr_t)-1)
+ {
+ dlt_vlog(LOG_ERR,
+ "%s: ERROR: server address not not valid %s\n",
+ __func__,
+ servIP);
- if (setsockopt(client->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
- {
- dlt_vlog(LOG_ERR,
- "%s: ERROR: setsockopt add membership failed: %s\n",
- __func__,
- strerror(errno));
+ return DLT_RETURN_ERROR;
+ }
- return DLT_RETURN_ERROR;
- }
+ if (setsockopt(client->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
+ {
+ dlt_vlog(LOG_ERR,
+ "%s: ERROR: setsockopt add membership failed: %s\n",
+ __func__,
+ strerror(errno));
+ return DLT_RETURN_ERROR;
+ }
+ servIP = strtok(NULL, delimiter);
+ }
receiver_type = DLT_RECEIVE_UDP_SOCKET;
break;
@@ -1146,6 +1211,7 @@ DLT_STATIC void dlt_client_free_calloc_failed_get_log_info(DltServiceGetLogInfoR
free(resp->log_info_type.app_ids);
resp->log_info_type.app_ids = NULL;
+ resp->log_info_type.count_app_ids = 0;
return;
}
@@ -1266,13 +1332,13 @@ DltReturnValue dlt_client_parse_get_log_info_resp_text(DltServiceGetLogInfoRespo
con->context_description = (char *)calloc
((size_t) (con->len_context_description + 1), sizeof(char));
- if (con->context_description == 0) {
+ if (con->context_description == NULL) {
dlt_vlog(LOG_ERR, "%s: calloc failed for context description\n", __func__);
dlt_client_free_calloc_failed_get_log_info(resp, i);
return DLT_RETURN_ERROR;
}
- dlt_getloginfo_conv_ascii_to_id(rp,
+ dlt_getloginfo_conv_ascii_to_string(rp,
&rp_count,
con->context_description,
con->len_context_description);
@@ -1286,13 +1352,13 @@ DltReturnValue dlt_client_parse_get_log_info_resp_text(DltServiceGetLogInfoRespo
app->app_description = (char *)calloc
((size_t) (app->len_app_description + 1), sizeof(char));
- if (app->app_description == 0) {
+ if (app->app_description == NULL) {
dlt_vlog(LOG_ERR, "%s: calloc failed for application description\n", __func__);
dlt_client_free_calloc_failed_get_log_info(resp, i);
return DLT_RETURN_ERROR;
}
- dlt_getloginfo_conv_ascii_to_id(rp,
+ dlt_getloginfo_conv_ascii_to_string(rp,
&rp_count,
app->app_description,
app->len_app_description);
diff --git a/src/lib/dlt_filetransfer.c b/src/lib/dlt_filetransfer.c
index 3a4efc9..3c71e68 100644
--- a/src/lib/dlt_filetransfer.c
+++ b/src/lib/dlt_filetransfer.c
@@ -179,7 +179,7 @@ void getFileCreationDate2(const char *file, int *ok, char *date)
if (-1 == stat(file, &st)) {
*ok = 0;
- date = 0;
+ return;
}
*ok = 1;
@@ -259,7 +259,7 @@ void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filenam
DLT_STRING(filename));
}
- char fcreationdate[50];
+ char fcreationdate[50] = {0};
getFileCreationDate2(filename, &ok, fcreationdate);
if (!ok) {
@@ -326,7 +326,7 @@ int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename)
DLT_STRING(filename));
}
- char creationdate[50];
+ char creationdate[50] = {0};
getFileCreationDate2(filename, &ok, creationdate);
if (!ok) {
@@ -475,7 +475,7 @@ int dlt_user_log_file_header_alias(DltContext *fileContext, const char *filename
DLT_STRING(filename));
}
- char fcreationdate[50];
+ char fcreationdate[50] = {0};
getFileCreationDate2(filename, &ok, fcreationdate);
if (!ok) {
@@ -536,7 +536,7 @@ int dlt_user_log_file_header(DltContext *fileContext, const char *filename)
DLT_STRING(filename));
}
- char fcreationdate[50];
+ char fcreationdate[50] = {0};
getFileCreationDate2(filename, &ok, fcreationdate);
if (!ok) {
@@ -657,6 +657,13 @@ int dlt_user_log_file_data(DltContext *fileContext,
if (checkUserBufferForFreeSpace() > 0) {
pkgNumber++;
readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
+
+ if (readBytes == 0) {
+ // If the file size is divisible by the package size don't send
+ // one empty FLDA. Also we send the correct number of FLDAs too.
+ break;
+ }
+
int ok;
uint32_t fserial = getFileSerialNumber(filename, &ok);
diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c
index 99df11b..0397e48 100644
--- a/src/lib/dlt_user.c
+++ b/src/lib/dlt_user.c
@@ -85,14 +85,22 @@
int *p = NULL; \
*p = 0; \
} \
- } while (0)
+ } while (false)
#else /* DLT_FATAL_LOG_RESET_ENABLE */
# define DLT_LOG_FATAL_RESET_TRAP(LOGLEVEL)
#endif /* DLT_FATAL_LOG_RESET_ENABLE */
+enum InitState {
+ INIT_UNITIALIZED,
+ INIT_IN_PROGRESS,
+ INIT_DONE
+};
+
static DltUser dlt_user;
-static atomic_bool dlt_user_initialised = false;
-static int dlt_user_freeing = 0;
+static _Atomic enum InitState dlt_user_init_state = INIT_UNITIALIZED;
+#define DLT_USER_INITALIZED (dlt_user_init_state == INIT_DONE)
+
+static _Atomic int dlt_user_freeing = 0;
static bool dlt_user_file_reach_max = false;
#ifdef DLT_LIB_USE_FIFO_IPC
@@ -103,6 +111,10 @@ static char dlt_daemon_fifo[DLT_PATH_MAX];
static sem_t dlt_mutex;
static pthread_t dlt_housekeeperthread_handle;
+/* Sync housekeeper thread start */
+pthread_mutex_t dlt_housekeeper_running_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t dlt_housekeeper_running_cond;
+
/* calling dlt_user_atexit_handler() second time fails with error message */
static int atexit_registered = 0;
@@ -209,7 +221,7 @@ static void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *
#endif
static DltReturnValue dlt_user_log_write_string_utils_attr(DltContextData *log, const char *text, const enum StringType type, const char *name, bool with_var_info);
-static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, uint16_t length, const enum StringType type, const char *name, bool with_var_info);
+static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, size_t length, const enum StringType type, const char *name, bool with_var_info);
static DltReturnValue dlt_unregister_app_util(bool force_sending_messages);
@@ -308,7 +320,7 @@ static DltReturnValue dlt_initialize_socket_connection(void)
sockfd,
DLT_RECEIVE_SOCKET,
DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
close(sockfd);
DLT_SEM_FREE();
return DLT_RETURN_ERROR;
@@ -363,7 +375,7 @@ static DltReturnValue dlt_initialize_vsock_connection()
sockfd,
DLT_RECEIVE_SOCKET,
DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
close(sockfd);
DLT_SEM_FREE();
return DLT_RETURN_ERROR;
@@ -445,35 +457,37 @@ static DltReturnValue dlt_initialize_fifo_connection(void)
DltReturnValue dlt_init(void)
{
- /* Compare 'dlt_user_initialised' to false. If equal, 'dlt_user_initialised' will be set to true.
- Calls retruns true, if 'dlt_user_initialised' was false.
- That way it's no problem, if two threads enter this function, because only the very first one will
- pass fully. The other one will immediately return, because when it executes the atomic function
- 'dlt_user_initialised' will be for sure already set to true.
- */
- bool expected = false;
- if (!(atomic_compare_exchange_strong(&dlt_user_initialised, &expected, true)))
+ /* process is exiting. Do not allocate new resources. */
+ if (dlt_user_freeing != 0) {
+ dlt_vlog(LOG_INFO, "%s logging disabled, process is exiting\n", __func__);
+ /* return negative value, to stop the current log */
+ return DLT_RETURN_LOGGING_DISABLED;
+ }
+
+ /* Compare dlt_user_init_state to INIT_UNITIALIZED. If equal it will be set to INIT_IN_PROGRESS.
+ * Call returns DLT_RETURN_OK init state != INIT_UNITIALIZED
+ * That way it's no problem, if two threads enter this function, because only the very first one will
+ * pass fully. The other one will immediately return, because when it executes the atomic function
+ * dlt_user_init_state won't be INIT_UNITIALIZED anymore.
+ * This is not handled via a simple boolean to prevent issues with shutting down while the init is still running.
+ * Furthermore, this makes sure we enter some function only when dlt_init is fully done.
+ * */
+ enum InitState expectedInitState = INIT_UNITIALIZED;
+ if (!(atomic_compare_exchange_strong(&dlt_user_init_state, &expectedInitState, INIT_IN_PROGRESS))) {
return DLT_RETURN_OK;
+ }
/* check environment variables */
dlt_check_envvar();
/* Check logging mode and internal log file is opened or not*/
- if(logging_mode == DLT_LOG_TO_FILE && logging_handle == NULL)
- {
+ if (logging_mode == DLT_LOG_TO_FILE && logging_handle == NULL) {
dlt_log_init(logging_mode);
}
- /* process is exiting. Do not allocate new resources. */
- if (dlt_user_freeing != 0) {
- dlt_vlog(LOG_INFO, "%s logging disabled, process is exiting", __func__);
- /* return negative value, to stop the current log */
- return DLT_RETURN_LOGGING_DISABLED;
- }
-
/* Initialize common part of dlt_init()/dlt_init_file() */
if (dlt_init_common() == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
return DLT_RETURN_ERROR;
}
@@ -515,7 +529,7 @@ DltReturnValue dlt_init(void)
dlt_user.dlt_user_handle,
DLT_RECEIVE_FD,
DLT_USER_RCVBUF_MAX_SIZE) == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
return DLT_RETURN_ERROR;
}
@@ -530,13 +544,18 @@ DltReturnValue dlt_init(void)
#endif
if (dlt_start_threads() < 0) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
return DLT_RETURN_ERROR;
}
/* prepare for fork() call */
pthread_atfork(NULL, NULL, &dlt_fork_child_fork_handler);
+ expectedInitState = INIT_IN_PROGRESS;
+ if (!(atomic_compare_exchange_strong(&dlt_user_init_state, &expectedInitState, INIT_DONE))) {
+ return DLT_RETURN_ERROR;
+ }
+
return DLT_RETURN_OK;
}
@@ -557,19 +576,21 @@ DltReturnValue dlt_init_file(const char *name)
if (!name)
return DLT_RETURN_WRONG_PARAMETER;
- /* Compare 'dlt_user_initialised' to false. If equal, 'dlt_user_initialised' will be set to true.
- Calls retruns true, if 'dlt_user_initialised' was false.
- That way it's no problem, if two threads enter this function, because only the very first one will
- pass fully. The other one will immediately return, because when it executes the atomic function
- 'dlt_user_initialised' will be for sure already set to true.
- */
- bool expected = false;
- if (!(atomic_compare_exchange_strong(&dlt_user_initialised, &expected, true)))
+ /* Compare dlt_user_init_state to INIT_UNITIALIZED. If equal it will be set to INIT_IN_PROGRESS.
+ * Call returns DLT_RETURN_OK init state != INIT_UNITIALIZED
+ * That way it's no problem, if two threads enter this function, because only the very first one will
+ * pass fully. The other one will immediately return, because when it executes the atomic function
+ * dlt_user_init_state won't be INIT_UNITIALIZED anymore.
+ * This is not handled via a simple boolean to prevent issues with shutting down while the init is still running.
+ * Furthermore, this makes sure we enter some function only when dlt_init is fully done.
+ * */
+ enum InitState expectedInitState = INIT_UNITIALIZED;
+ if (!(atomic_compare_exchange_strong(&dlt_user_init_state, &expectedInitState, INIT_IN_PROGRESS)))
return DLT_RETURN_OK;
/* Initialize common part of dlt_init()/dlt_init_file() */
if (dlt_init_common() == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ expectedInitState = INIT_UNITIALIZED;
return DLT_RETURN_ERROR;
}
@@ -699,7 +720,7 @@ DltReturnValue dlt_init_common(void)
/* Binary semaphore for threads */
if (sem_init(&dlt_mutex, 0, 1) == -1) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
return DLT_RETURN_ERROR;
}
@@ -846,7 +867,7 @@ DltReturnValue dlt_init_common(void)
(dlt_user.log_buf_len + header_size));
if (dlt_user.resend_buffer == NULL) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
DLT_SEM_FREE();
dlt_vlog(LOG_ERR, "cannot allocate memory for resend buffer\n");
return DLT_RETURN_ERROR;
@@ -863,7 +884,7 @@ DltReturnValue dlt_init_common(void)
buffer_min,
buffer_max,
buffer_step) == DLT_RETURN_ERROR) {
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
DLT_SEM_FREE();
return DLT_RETURN_ERROR;
}
@@ -892,8 +913,8 @@ void dlt_user_atexit_handler(void)
if (g_dlt_is_child)
return;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
/* close file */
dlt_log_free();
return;
@@ -981,26 +1002,26 @@ DltReturnValue dlt_free(void)
{
uint32_t i;
int ret = 0;
+ int expected = 0;
#ifdef DLT_LIB_USE_FIFO_IPC
char filename[DLT_PATH_MAX];
#endif
- if (dlt_user_freeing != 0)
+ /* library is freeing its resources. Avoid to allocate it in dlt_init() */
+ if (!(atomic_compare_exchange_strong(&dlt_user_freeing, &expected, 1))) {
/* resources are already being freed. Do nothing and return. */
return DLT_RETURN_ERROR;
+ }
- /* library is freeing its resources. Avoid to allocate it in dlt_init() */
- dlt_user_freeing = 1;
-
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
dlt_user_freeing = 0;
return DLT_RETURN_ERROR;
}
- dlt_user_initialised = false;
-
dlt_stop_threads();
+ dlt_user_init_state = INIT_UNITIALIZED;
+
#ifdef DLT_LIB_USE_FIFO_IPC
if (dlt_user.dlt_user_handle != DLT_FD_INIT) {
@@ -1184,7 +1205,7 @@ DltReturnValue dlt_register_app(const char *apid, const char *description)
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1263,7 +1284,7 @@ DltReturnValue dlt_register_context(DltContext *handle, const char *contextid, c
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1512,7 +1533,7 @@ DltReturnValue dlt_register_context_llccb(DltContext *handle,
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1537,8 +1558,8 @@ DltReturnValue dlt_unregister_app_util(bool force_sending_messages)
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -1578,8 +1599,8 @@ DltReturnValue dlt_unregister_app_flush_buffered_logs(void)
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_ERR, "%s dlt_user_initialised false\n", __func__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -1669,7 +1690,7 @@ DltReturnValue dlt_set_application_ll_ts_limit(DltLogLevelType loglevel, DltTrac
return DLT_RETURN_WRONG_PARAMETER;
}
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1719,7 +1740,7 @@ DltReturnValue dlt_set_log_mode(DltUserLogMode mode)
return DLT_RETURN_WRONG_PARAMETER;
}
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1735,7 +1756,7 @@ int dlt_set_resend_timeout_atexit(uint32_t timeout_in_milliseconds)
if (g_dlt_is_child)
return DLT_RETURN_ERROR;
- if (dlt_user_initialised == 0)
+ if (DLT_USER_INITALIZED == 0)
if (dlt_init() < 0)
return -1;
@@ -1813,27 +1834,34 @@ DltReturnValue dlt_user_log_write_start_internal(DltContext *handle,
ret = dlt_user_log_write_start_init(handle, log, loglevel, is_verbose);
if (ret == DLT_RETURN_TRUE) {
/* initialize values */
- if (log->buffer == NULL) {
+ if ((NULL != log->buffer))
+ {
+ free(log->buffer);
+ log->buffer = NULL;
+ }
+ else
+ {
log->buffer = calloc(sizeof(unsigned char), dlt_user.log_buf_len);
-
- if (log->buffer == NULL) {
- dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
- return DLT_RETURN_ERROR;
- }
}
- /* In non-verbose mode, insert message id */
- if (!is_verbose_mode(dlt_user.verbose_mode, log)) {
- if ((sizeof(uint32_t)) > dlt_user.log_buf_len) {
- return DLT_RETURN_USER_BUFFER_FULL;
- }
+ if (log->buffer == NULL) {
+ dlt_vlog(LOG_ERR, "Cannot allocate buffer for DLT Log message\n");
+ return DLT_RETURN_ERROR;
+ }
+ else
+ {
+ /* In non-verbose mode, insert message id */
+ if (!is_verbose_mode(dlt_user.verbose_mode, log)) {
+ if ((sizeof(uint32_t)) > dlt_user.log_buf_len)
+ return DLT_RETURN_USER_BUFFER_FULL;
- /* Write message id */
- memcpy(log->buffer, &(messageid), sizeof(uint32_t));
- log->size = sizeof(uint32_t);
+ /* Write message id */
+ memcpy(log->buffer, &(messageid), sizeof(uint32_t));
+ log->size = sizeof(uint32_t);
- /* as the message id is part of each message in non-verbose mode,
- * it doesn't increment the argument counter in extended header (if used) */
+ /* as the message id is part of each message in non-verbose mode,
+ * it doesn't increment the argument counter in extended header (if used) */
+ }
}
}
@@ -1874,7 +1902,7 @@ DltReturnValue dlt_user_log_write_start_w_given_buffer(DltContext *handle,
return ret;
}
-
+
DltReturnValue dlt_user_log_write_finish(DltContextData *log)
{
int ret = DLT_RETURN_ERROR;
@@ -1913,8 +1941,8 @@ static DltReturnValue dlt_user_log_write_raw_internal(DltContextData *log, const
return DLT_RETURN_WRONG_PARAMETER;
}
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2007,8 +2035,8 @@ static DltReturnValue dlt_user_log_write_generic_attr(DltContextData *log, const
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2086,8 +2114,8 @@ static DltReturnValue dlt_user_log_write_generic_formatted(DltContextData *log,
return DLT_RETURN_WRONG_PARAMETER;
}
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2162,8 +2190,8 @@ DltReturnValue dlt_user_log_write_uint(DltContextData *log, unsigned int data)
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2227,7 +2255,7 @@ DltReturnValue dlt_user_log_write_uint_attr(DltContextData *log, unsigned int da
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2320,7 +2348,7 @@ DltReturnValue dlt_user_log_write_ptr(DltContextData *log, void *data)
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
dlt_vlog(LOG_WARNING, "%s user_initialised false\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2348,8 +2376,8 @@ DltReturnValue dlt_user_log_write_int(DltContextData *log, int data)
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2413,7 +2441,7 @@ DltReturnValue dlt_user_log_write_int_attr(DltContextData *log, int data, const
if (log == NULL)
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -2578,19 +2606,19 @@ DltReturnValue dlt_user_log_write_sized_constant_utf8_string_attr(DltContextData
return is_verbose_mode(dlt_user.verbose_mode, log) ? dlt_user_log_write_sized_utf8_string_attr(log, text, length, name) : DLT_RETURN_OK;
}
-static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, uint16_t length, const enum StringType type, const char *name, bool with_var_info)
+static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData *log, const char *text, size_t length, const enum StringType type, const char *name, bool with_var_info)
{
if ((log == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
const uint16_t name_size = (name != NULL) ? strlen(name)+1 : 0;
- uint16_t arg_size = (uint16_t) (length + 1);
+ size_t arg_size = (size_t) (length + 1);
size_t new_log_size = log->size + arg_size + sizeof(uint16_t);
@@ -2615,13 +2643,13 @@ static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData
ret = DLT_RETURN_USER_BUFFER_FULL;
/* Re-calculate arg_size */
- arg_size = (uint16_t) (dlt_user.log_buf_len - log->size - sizeof(uint16_t));
+ arg_size = (size_t) (dlt_user.log_buf_len - log->size - sizeof(uint16_t));
size_t min_payload_str_truncate_msg = log->size + str_truncate_message_length + sizeof(uint16_t);
if (is_verbose_mode(dlt_user.verbose_mode, log)) {
min_payload_str_truncate_msg += sizeof(uint32_t);
- arg_size -= (uint16_t) sizeof(uint32_t);
+ arg_size -= (size_t) sizeof(uint32_t);
if (with_var_info) {
min_payload_str_truncate_msg += sizeof(uint16_t) + name_size;
arg_size -= sizeof(uint16_t) + name_size;
@@ -2659,7 +2687,7 @@ static DltReturnValue dlt_user_log_write_sized_string_utils_attr(DltContextData
}
max_payload_str_msg -= reduce_size;
- arg_size -= (uint16_t) reduce_size;
+ arg_size -= (size_t) reduce_size;
}
}
@@ -2738,7 +2766,7 @@ static DltReturnValue dlt_user_log_write_string_utils_attr(DltContextData *log,
if ((log == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- uint16_t length = (uint16_t) strlen(text);
+ size_t length = strlen(text);
return dlt_user_log_write_sized_string_utils_attr(log, text, length, type, name, with_var_info);
}
@@ -3248,7 +3276,7 @@ DltReturnValue dlt_user_trace_network_segmented(DltContext *handle,
return DLT_RETURN_ERROR;
/* Send as normal trace if possible */
- if (header_len + payload_len + (uint16_t) sizeof(uint16_t) < dlt_user.log_buf_len)
+ if (header_len + payload_len + sizeof(uint16_t) < dlt_user.log_buf_len)
return dlt_user_trace_network(handle, nw_trace_type, header_len, header, payload_len, payload);
/* Allocate Memory */
@@ -3378,7 +3406,7 @@ DltReturnValue dlt_user_trace_network_truncated(DltContext *handle,
header_len = 0;
/* If truncation is allowed, check if we must do it */
- if ((allow_truncate > 0) && ((header_len + payload_len + (uint16_t) sizeof(uint16_t)) > dlt_user.log_buf_len)) {
+ if ((allow_truncate > 0) && ((header_len + payload_len + sizeof(uint16_t)) > dlt_user.log_buf_len)) {
/* Identify as truncated */
if (dlt_user_log_write_string(&log, DLT_TRACE_NW_TRUNCATED) < DLT_RETURN_OK) {
dlt_user_free_buffer(&(log.buffer));
@@ -3570,7 +3598,7 @@ DltReturnValue dlt_log_raw(DltContext *handle, DltLogLevelType loglevel, void *d
DltReturnValue dlt_log_marker()
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3582,7 +3610,7 @@ DltReturnValue dlt_log_marker()
DltReturnValue dlt_verbose_mode(void)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3597,7 +3625,7 @@ DltReturnValue dlt_verbose_mode(void)
DltReturnValue dlt_nonverbose_mode(void)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3612,7 +3640,7 @@ DltReturnValue dlt_nonverbose_mode(void)
DltReturnValue dlt_use_extended_header_for_non_verbose(int8_t use_extended_header_for_non_verbose)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3627,7 +3655,7 @@ DltReturnValue dlt_use_extended_header_for_non_verbose(int8_t use_extended_heade
DltReturnValue dlt_with_session_id(int8_t with_session_id)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3642,7 +3670,7 @@ DltReturnValue dlt_with_session_id(int8_t with_session_id)
DltReturnValue dlt_with_timestamp(int8_t with_timestamp)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3657,7 +3685,7 @@ DltReturnValue dlt_with_timestamp(int8_t with_timestamp)
DltReturnValue dlt_with_ecu_id(int8_t with_ecu_id)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3672,7 +3700,7 @@ DltReturnValue dlt_with_ecu_id(int8_t with_ecu_id)
DltReturnValue dlt_enable_local_print(void)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3686,7 +3714,7 @@ DltReturnValue dlt_enable_local_print(void)
DltReturnValue dlt_disable_local_print(void)
{
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
if (dlt_init() < DLT_RETURN_OK) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -3712,10 +3740,12 @@ static void dlt_user_cleanup_handler(void *arg)
DLT_SEM_FREE();
}
-void dlt_user_housekeeperthread_function(__attribute__((unused)) void *ptr)
+void dlt_user_housekeeperthread_function(void *ptr)
{
struct timespec ts;
bool in_loop = true;
+ int signal_status = 0;
+ atomic_bool* dlt_housekeeper_running = (atomic_bool*)ptr;
#ifdef __ANDROID_API__
sigset_t set;
@@ -3743,6 +3773,13 @@ void dlt_user_housekeeperthread_function(__attribute__((unused)) void *ptr)
pthread_cleanup_push(dlt_user_cleanup_handler, NULL);
+ // signal dlt thread to be running
+ *dlt_housekeeper_running = true;
+ signal_status = pthread_cond_signal(&dlt_housekeeper_running_cond);
+ if (signal_status != 0) {
+ dlt_log(LOG_CRIT, "Housekeeper thread failed to signal running state\n");
+ }
+
while (in_loop) {
/* Check for new messages from DLT daemon */
if (!dlt_user.disable_injection_msg)
@@ -3787,7 +3824,7 @@ DltReturnValue dlt_user_log_init(DltContext *handle, DltContextData *log)
if ((handle == NULL) || (log == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- if (!dlt_user_initialised) {
+ if (!DLT_USER_INITALIZED) {
ret = dlt_init();
if (ret < DLT_RETURN_OK) {
@@ -3811,8 +3848,8 @@ DltReturnValue dlt_user_log_send_log(DltContextData *log, int mtype)
DltReturnValue ret = DLT_RETURN_OK;
- if (!dlt_user_initialised) {
- dlt_vlog(LOG_ERR, "%s dlt_user_initialised false\n", __FUNCTION__);
+ if (!DLT_USER_INITALIZED) {
+ dlt_vlog(LOG_WARNING, "%s dlt_user_init_state != INIT_DONE\n", __FUNCTION__);
return DLT_RETURN_ERROR;
}
@@ -4920,15 +4957,63 @@ void dlt_user_test_corrupt_message_size(int enable, int16_t size)
int dlt_start_threads()
{
- /* Start housekeeper thread */
+ struct timespec time_to_wait;
+ struct timespec now;
+ int signal_status;
+ atomic_bool dlt_housekeeper_running = false;
+
+ /*
+ * Configure the condition varibale to use CLOCK_MONOTONIC.
+ * This makes sure we're protected against changes in the system clock
+ */
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ pthread_cond_init(&dlt_housekeeper_running_cond, &attr);
+
if (pthread_create(&(dlt_housekeeperthread_handle),
0,
(void *)&dlt_user_housekeeperthread_function,
- 0) != 0) {
+ &dlt_housekeeper_running) != 0) {
dlt_log(LOG_CRIT, "Can't create housekeeper thread!\n");
return -1;
}
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ /* wait at most 10s */
+ time_to_wait.tv_sec = now.tv_sec + 10;
+ time_to_wait.tv_nsec = 0;
+
+ /*
+ * wait until the house keeper is up and running
+ * Even though the condition variable and the while are
+ * using the same time out the while loop is not a no op.
+ * This is due to the fact that the pthread_cond_timedwait
+ * can be woken before time is up and dlt_housekeeper_running is not true yet.
+ * (spurious wakeup)
+ * To protect against this, a while loop with a timeout is added
+ * */
+ while (!dlt_housekeeper_running
+ && now.tv_sec <= time_to_wait.tv_sec) {
+ signal_status = pthread_cond_timedwait(
+ &dlt_housekeeper_running_cond,
+ &dlt_housekeeper_running_mutex,
+ &time_to_wait);
+
+ /* otherwise it might be a spurious wakeup, try again until the time is over */
+ if (signal_status == 0) {
+ break;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+
+ if (signal_status != 0 && !dlt_housekeeper_running) {
+ dlt_log(LOG_CRIT, "Failed to wait for house keeper thread!\n");
+ dlt_stop_threads();
+ return -1;
+ }
+
#ifdef DLT_NETWORK_TRACE_ENABLE
/* Start the segmented thread */
if (pthread_create(&(dlt_user.dlt_segmented_nwt_handle), NULL,
@@ -5015,7 +5100,7 @@ void dlt_stop_threads()
static void dlt_fork_child_fork_handler()
{
g_dlt_is_child = 1;
- dlt_user_initialised = false;
+ dlt_user_init_state = INIT_UNITIALIZED;
dlt_user.dlt_log_handle = -1;
}
diff --git a/src/offlinelogstorage/dlt_offline_logstorage.c b/src/offlinelogstorage/dlt_offline_logstorage.c
index 07d09a5..b8793c7 100644
--- a/src/offlinelogstorage/dlt_offline_logstorage.c
+++ b/src/offlinelogstorage/dlt_offline_logstorage.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
+#include <sys/syslog.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/stat.h>
@@ -73,6 +74,11 @@ DLT_STATIC void dlt_logstorage_filter_config_free(DltLogStorageFilterConfig *dat
if (data->log != NULL)
fclose(data->log);
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (data->gzlog != NULL)
+ gzclose(data->gzlog);
+#endif
+
if (data->cache != NULL) {
free(data->cache);
data->cache = NULL;
@@ -421,6 +427,34 @@ DLT_STATIC int dlt_logstorage_read_number(unsigned int *number, char *value)
}
/**
+ * dlt_logstorage_read_bool
+ *
+ * Evaluate a boolean config value. Values such as '1', 'on' or 'true' will be
+ * treated as true otherwise the config value will be interpreted as false.
+ *
+ * @param bool The boolean to populate
+ * @param value The string from the config file
+ * @returns 0 on success, -1 on error
+ */
+DLT_STATIC int dlt_logstorage_read_bool(unsigned int *boolean, char *value)
+{
+ int len = 0;
+ if (value == NULL)
+ return -1;
+
+ len = strnlen(value, 5);
+ *boolean = 0;
+ if (strncmp(value, "on", len) == 0) {
+ *boolean = 1;
+ } else if (strncmp(value, "true", len) == 0) {
+ *boolean = 1;
+ } else if (strncmp(value, "1", len) == 0) {
+ *boolean = 1;
+ }
+ return 0;
+}
+
+/**
* dlt_logstorage_get_keys_list
*
* Obtain key list and number of keys for id list passed
@@ -498,7 +532,7 @@ DLT_STATIC void dlt_logstorage_create_keys_only_ctid(char *ecuid, char *ctid,
int curr_len = 0;
if (ecuid != NULL) {
- strncpy(curr_str, ecuid, strlen(ecuid));
+ strncpy(curr_str, ecuid, DLT_ID_SIZE);
strncat(curr_str, "::", 2);
}
else {
@@ -530,7 +564,7 @@ DLT_STATIC void dlt_logstorage_create_keys_only_apid(char *ecuid, char *apid,
int curr_len = 0;
if (ecuid != NULL) {
- strncpy(curr_str, ecuid, strlen(ecuid));
+ strncpy(curr_str, ecuid, DLT_ID_SIZE);
strncat(curr_str, ":", 1);
}
else {
@@ -564,7 +598,7 @@ DLT_STATIC void dlt_logstorage_create_keys_multi(char *ecuid, char *apid,
int curr_len = 0;
if (ecuid != NULL) {
- strncpy(curr_str, ecuid, strlen(ecuid));
+ strncpy(curr_str, ecuid, DLT_ID_SIZE);
strncat(curr_str, ":", 1);
}
else {
@@ -595,7 +629,7 @@ DLT_STATIC void dlt_logstorage_create_keys_only_ecu(char *ecuid, char *key)
{
char curr_str[DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN + 1] = { 0 };
- strncpy(curr_str, ecuid, strlen(ecuid));
+ strncpy(curr_str, ecuid, DLT_ID_SIZE);
strncat(curr_str, "::", 2);
strncpy(key, curr_str, strlen(curr_str));
@@ -1052,6 +1086,20 @@ DLT_STATIC int dlt_logstorage_check_nofiles(DltLogStorageFilterConfig *config,
return dlt_logstorage_read_number(&config->num_files, value);
}
+DLT_STATIC int dlt_logstorage_check_gzip_compression(DltLogStorageFilterConfig *config,
+ char *value)
+{
+ if ((config == NULL) || (value == NULL))
+ return -1;
+
+ int result = dlt_logstorage_read_bool(&config->gzip_compression, value);
+#ifndef DLT_LOGSTORAGE_USE_GZIP
+ dlt_log(LOG_WARNING, "dlt-daemon not compiled with logstorage gzip support\n");
+ config->gzip_compression = 0;
+#endif
+ return result;
+}
+
DLT_STATIC int dlt_logstorage_check_specificsize(DltLogStorageFilterConfig *config,
char *value)
{
@@ -1195,6 +1243,11 @@ DLT_STATIC DltLogstorageFilterConf
.key = "SpecificSize",
.func = dlt_logstorage_check_specificsize,
.is_opt = 1
+ },
+ [DLT_LOGSTORAGE_FILTER_CONF_GZIP_COMPRESSION] = {
+ .key = "GzipCompression",
+ .func = dlt_logstorage_check_gzip_compression,
+ .is_opt = 1
}
};
@@ -1250,6 +1303,11 @@ DLT_STATIC DltLogstorageFilterConf
.key = NULL,
.func = dlt_logstorage_check_specificsize,
.is_opt = 1
+ },
+ [DLT_LOGSTORAGE_FILTER_CONF_GZIP_COMPRESSION] = {
+ .key = "GzipCompression",
+ .func = dlt_logstorage_check_gzip_compression,
+ .is_opt = 1
}
};
@@ -1304,6 +1362,11 @@ DLT_STATIC DltLogstorageFilterConf
.key = NULL,
.func = dlt_logstorage_check_specificsize,
.is_opt = 1
+ },
+ [DLT_LOGSTORAGE_FILTER_CONF_GZIP_COMPRESSION] = {
+ .key = "GzipCompression",
+ .func = dlt_logstorage_check_gzip_compression,
+ .is_opt = 1
}
};
/**
diff --git a/src/offlinelogstorage/dlt_offline_logstorage.h b/src/offlinelogstorage/dlt_offline_logstorage.h
index 16252bc..8f32a89 100644
--- a/src/offlinelogstorage/dlt_offline_logstorage.h
+++ b/src/offlinelogstorage/dlt_offline_logstorage.h
@@ -53,28 +53,30 @@
#include <search.h>
#include <stdbool.h>
+#include <zlib.h>
#include "dlt_common.h"
#include "dlt-daemon_cfg.h"
#include "dlt_config_file_parser.h"
-#define DLT_OFFLINE_LOGSTORAGE_MAXIDS 100 /* Maximum entries for each apids and ctids */
-#define DLT_OFFLINE_LOGSTORAGE_MAX_POSSIBLE_KEYS 7 /* Max number of possible keys when searching for */
+#define DLT_OFFLINE_LOGSTORAGE_MAXIDS 100 /* Maximum entries for each apids and ctids */
+#define DLT_OFFLINE_LOGSTORAGE_MAX_POSSIBLE_KEYS 7 /* Max number of possible keys when searching for */
-#define DLT_OFFLINE_LOGSTORAGE_INIT_DONE 1 /* For device configuration status */
-#define DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED 1
-#define DLT_OFFLINE_LOGSTORAGE_FREE 0
-#define DLT_OFFLINE_LOGSTORAGE_DEVICE_DISCONNECTED 0
-#define DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE 1
+#define DLT_OFFLINE_LOGSTORAGE_INIT_DONE 1 /* For device configuration status */
+#define DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED 1
+#define DLT_OFFLINE_LOGSTORAGE_FREE 0
+#define DLT_OFFLINE_LOGSTORAGE_DEVICE_DISCONNECTED 0
+#define DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE 1
-#define DLT_OFFLINE_LOGSTORAGE_SYNC_CACHES 2 /* sync logstorage caches */
+#define DLT_OFFLINE_LOGSTORAGE_SYNC_CACHES 2 /* sync logstorage caches */
-#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN 15 /* Maximum size for key */
-#define DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN 50 /* Maximum file name length of the log file */
+#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_LEN 15 /* Maximum size for key */
+#define DLT_OFFLINE_LOGSTORAGE_MAX_FILE_NAME_LEN 50 /* Maximum file name length of the log file */
-#define DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN 4
-#define DLT_OFFLINE_LOGSTORAGE_INDEX_LEN 3
-#define DLT_OFFLINE_LOGSTORAGE_MAX_INDEX 999
-#define DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN 16
+#define DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN 4
+#define DLT_OFFLINE_LOGSTORAGE_GZ_FILE_EXTENSION_LEN 7
+#define DLT_OFFLINE_LOGSTORAGE_INDEX_LEN 3
+#define DLT_OFFLINE_LOGSTORAGE_MAX_INDEX 999
+#define DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN 16
#define DLT_OFFLINE_LOGSTORAGE_INDEX_OFFSET (DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + \
DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + \
DLT_OFFLINE_LOGSTORAGE_INDEX_LEN)
@@ -169,6 +171,7 @@ struct DltLogStorageFilterConfig
unsigned int num_files; /* MAX number of storage files configured for filters */
int sync; /* Sync strategy */
char *ecuid; /* ECU identifier */
+ unsigned int gzip_compression; /* Toggle if log files should be gzip compressed */
/* callback function for filter configurations */
int (*dlt_logstorage_prepare)(DltLogStorageFilterConfig *config,
DltLogStorageUserConfig *file_config,
@@ -191,6 +194,10 @@ struct DltLogStorageFilterConfig
char *dev_path,
int status);
FILE *log; /* current open log file */
+ int fd; /* The file descriptor for the active log file */
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ gzFile gzlog; /* current open gz log file */
+#endif
void *cache; /* log data cache */
unsigned int specific_size; /* cache size used for specific_size sync strategy */
unsigned int current_write_file_offset; /* file offset for specific_size sync strategy */
@@ -248,6 +255,7 @@ typedef enum {
DLT_LOGSTORAGE_FILTER_CONF_SYNCBEHAVIOR,
DLT_LOGSTORAGE_FILTER_CONF_ECUID,
DLT_LOGSTORAGE_FILTER_CONF_SPECIFIC_SIZE,
+ DLT_LOGSTORAGE_FILTER_CONF_GZIP_COMPRESSION,
DLT_LOGSTORAGE_FILTER_CONF_COUNT
} DltLogstorageFilterConfType;
diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
index 35d8306..666a78b 100644
--- a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
+++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c
@@ -28,11 +28,38 @@
#include <stdlib.h>
#include <errno.h>
+#include "dlt_common.h"
#include "dlt_offline_logstorage.h"
#include "dlt_offline_logstorage_behavior.h"
#include "dlt_offline_logstorage_behavior_internal.h"
unsigned int g_logstorage_cache_size;
+
+/**
+ * dlt_logstorage_concat
+ *
+ * Concatenates two strings but keeps the size of the result less then dst_size.
+ *
+ * @param dst The destination string
+ * @param src The source string to concat
+ */
+DLT_STATIC void dlt_logstorage_concat_logfile_name(char *log_file_name, const char *append)
+{
+ size_t dst_len = strnlen(log_file_name, DLT_MOUNT_PATH_MAX);
+ size_t src_len = strlen(append);
+
+ if (dst_len < DLT_MOUNT_PATH_MAX) {
+ size_t rem_len = DLT_MOUNT_PATH_MAX - dst_len - 1;
+ strncat(log_file_name, append, rem_len);
+ } else {
+ dlt_vlog(LOG_ERR, "Log file name reached max len: %s [%d]\n", log_file_name, DLT_MOUNT_PATH_MAX);
+ }
+
+ if (src_len + dst_len >= DLT_MOUNT_PATH_MAX) {
+ dlt_vlog(LOG_ERR, "Log file path too long. Truncated: %s", log_file_name);
+ }
+}
+
/**
* dlt_logstorage_log_file_name
*
@@ -53,18 +80,18 @@ unsigned int g_logstorage_cache_size;
*/
void dlt_logstorage_log_file_name(char *log_file_name,
DltLogStorageUserConfig *file_config,
- char *name,
+ DltLogStorageFilterConfig *filter_config,
int idx)
{
- if ((log_file_name == NULL) || (file_config == NULL))
+ if ((log_file_name == NULL) || (file_config == NULL) || (filter_config == NULL))
return;
char file_index[10] = { '\0' };
/* create log file name */
- memset(log_file_name, 0, DLT_MOUNT_PATH_MAX * sizeof(char));
- strcat(log_file_name, name);
- strncat(log_file_name, &file_config->logfile_delimiter, 1);
+ memset(log_file_name, '\0', DLT_MOUNT_PATH_MAX * sizeof(char));
+ dlt_logstorage_concat_logfile_name(log_file_name, filter_config->file_name);
+ dlt_logstorage_concat_logfile_name(log_file_name, &file_config->logfile_delimiter);
snprintf(file_index, 10, "%d", idx);
@@ -78,11 +105,11 @@ void dlt_logstorage_log_file_name(char *log_file_name,
if (file_config->logfile_counteridxlen > digit_idx)
{
for (i = 0 ; i < (file_config->logfile_counteridxlen - digit_idx) ; i++)
- strcat(log_file_name, "0");
+ dlt_logstorage_concat_logfile_name(log_file_name, "0");
}
}
- strcat(log_file_name, file_index);
+ dlt_logstorage_concat_logfile_name(log_file_name, file_index);
/* Add time stamp if user has configured */
if (file_config->logfile_timestamp) {
@@ -106,10 +133,13 @@ void dlt_logstorage_log_file_name(char *log_file_name,
dlt_vlog(LOG_WARNING, "%s: snprintf truncation %s\n", __func__,
stamp);
}
- strcat(log_file_name, stamp);
+ dlt_logstorage_concat_logfile_name(log_file_name, stamp);
}
- strcat(log_file_name, ".dlt");
+ dlt_logstorage_concat_logfile_name(log_file_name, ".dlt");
+ if (filter_config->gzip_compression) {
+ dlt_logstorage_concat_logfile_name(log_file_name, ".gz");
+ }
}
/**
@@ -209,57 +239,35 @@ void dlt_logstorage_rearrange_file_name(DltLogStorageFileList **head)
*
* Extract index of log file name passed as input argument
*
- * @param file file name to extract the index from
* @param file_config User configurations for log file
+ * @param config Filter configurations for log file
+ * @param file file name to extract the index from
* @return index on success, -1 if no index is found
*/
-unsigned int dlt_logstorage_get_idx_of_log_file(DltLogStorageUserConfig *file_config,
- char *file)
+unsigned int
+dlt_logstorage_get_idx_of_log_file(DltLogStorageUserConfig *file_config,
+ DltLogStorageFilterConfig *config,
+ char *file)
{
- unsigned int idx = -1;
- char *endptr;
- char *filename;
- unsigned int filename_len = 0;
- unsigned int fileindex_len = 0;
-
- if ((file_config == NULL) || (file == NULL))
+ if (file_config == NULL || config == NULL || file == NULL)
return -1;
- /* Calculate actual file name length */
- filename = strchr(file, file_config->logfile_delimiter);
+ int idx = 0;
+ int basename_len;
+ char *sptr, *eptr;
- if (filename == NULL) {
- dlt_vlog(LOG_ERR, "Cannot extract filename from %s\n", file);
- return -1;
- }
-
- filename_len = strlen(file) - strlen(filename);
-
- /* index is retrived from file name */
- if (file_config->logfile_timestamp) {
- fileindex_len = strlen(file) -
- (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
- DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN +
- filename_len + 1);
-
- idx = (int)strtol(&file[strlen(file) -
- (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
- fileindex_len +
- DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN)],
- &endptr,
- 10);
- }
- else {
- fileindex_len = strlen(file) -
- (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN +
- filename_len + 1);
-
- idx = (int)strtol(&file[strlen(file) -
- (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN
- + fileindex_len)], &endptr, 10);
- }
+ /* Find the next delimiter after the first one:
+ * Eg. base-log-name_<idx>_<timestamp>.dlt
+ * ^ ^
+ * | |
+ * From here --+ +--- To this position
+ */
+ basename_len = strlen(config->file_name);
+ sptr = file + basename_len + 1;
+ eptr = strchr(file + basename_len + 1, file_config->logfile_delimiter);
+ idx = strtol(sptr, &eptr, 10);
- if ((endptr == file) || (idx == 0))
+ if (idx == 0)
dlt_log(LOG_ERR,
"Unable to calculate index from log file name. Reset to 001.\n");
@@ -322,15 +330,30 @@ int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config,
config->records = NULL;
}
+ char suffix[10];
+ int suffix_len;
+ memset(suffix, 0, 10);
+ if (config->gzip_compression) {
+ suffix_len = DLT_OFFLINE_LOGSTORAGE_GZ_FILE_EXTENSION_LEN;
+ strncpy(suffix, ".dlt.gz", suffix_len);
+ }
+ else {
+ suffix_len = DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN;
+ strncpy(suffix, ".dlt", suffix_len);
+ }
+
for (i = 0; i < cnt; i++) {
int len = 0;
+ int fname_len = 0;
len = strlen(config->file_name);
+ fname_len = strlen(files[i]->d_name);
if ((strncmp(files[i]->d_name, config->file_name, len) == 0) &&
- (files[i]->d_name[len] == file_config->logfile_delimiter)) {
+ (files[i]->d_name[len] == file_config->logfile_delimiter) &&
+ (fname_len > suffix_len && strncmp(&files[i]->d_name[fname_len - suffix_len], suffix, suffix_len) == 0))
+ {
DltLogStorageFileList **tmp = NULL;
- current_idx = dlt_logstorage_get_idx_of_log_file(file_config,
- files[i]->d_name);
+ current_idx = dlt_logstorage_get_idx_of_log_file(file_config, config, files[i]->d_name);
if (config->records == NULL) {
config->records = malloc(sizeof(DltLogStorageFileList));
@@ -394,6 +417,32 @@ int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config,
/**
* dlt_logstorage_open_log_file
*
+ * Open a handle to the logfile
+ *
+ * @param config A pointer to the current DltLogStorageFilterConfig
+ * @param fpath The file path
+ * @param mode The mode to open the file with
+ */
+DLT_STATIC void
+dlt_logstorage_open_log_output_file(DltLogStorageFilterConfig *config,
+ const char *fpath, const char *mode)
+{
+ FILE *file = fopen(fpath, mode);
+ config->fd = fileno(file);
+ if (config->gzip_compression) {
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ dlt_vlog(LOG_DEBUG, "%s: Opening GZIP log file\n", __func__);
+ config->gzlog = gzdopen(config->fd, mode);
+#endif
+ } else {
+ dlt_vlog(LOG_DEBUG, "%s: Opening log file\n", __func__);
+ config->log = file;
+ }
+}
+
+/**
+ * dlt_logstorage_open_log_file
+ *
* Open a log file. Check storage directory for already created files and open
* the oldest if there is enough space to store at least msg_size.
* Otherwise create a new file, but take configured max number of files into
@@ -451,16 +500,13 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
/* need new file*/
if (num_log_files == 0) {
- dlt_logstorage_log_file_name(file_name,
- file_config,
- config->file_name,
- 1);
+ dlt_logstorage_log_file_name(file_name, file_config, config, 1);
/* concatenate path and file and open absolute path */
strcat(absolute_file_path, storage_path);
strcat(absolute_file_path, file_name);
config->working_file_name = strdup(file_name);
- config->log = fopen(absolute_file_path, "a+");
+ dlt_logstorage_open_log_output_file(config, absolute_file_path, "a");
/* Add file to file list */
*tmp = malloc(sizeof(DltLogStorageFileList));
@@ -498,8 +544,8 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
ret = stat(absolute_file_path, &s);
/* if size is enough, open it */
- if ((ret == 0) && (s.st_size + msg_size <= (int) config->file_size)) {
- config->log = fopen(absolute_file_path, "a+");
+ if ((ret == 0) && (s.st_size + msg_size <= (int)config->file_size)) {
+ dlt_logstorage_open_log_output_file(config, absolute_file_path, "a");
config->current_write_file_offset = s.st_size;
}
else {
@@ -507,8 +553,7 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
unsigned int idx = 0;
/* get index of newest log file */
- idx = dlt_logstorage_get_idx_of_log_file(file_config,
- config->working_file_name);
+ idx = dlt_logstorage_get_idx_of_log_file(file_config, config, config->working_file_name);
idx += 1;
/* wrap around if max index is reached or an error occurred
@@ -518,10 +563,7 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
config->wrap_id += 1;
}
- dlt_logstorage_log_file_name(file_name,
- file_config,
- config->file_name,
- idx);
+ dlt_logstorage_log_file_name(file_name, file_config, config, idx);
/* concatenate path and file and open absolute path */
memset(absolute_file_path,
@@ -546,7 +588,7 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
__func__, absolute_file_path, num_log_files, config->num_files);
}
- config->log = fopen(absolute_file_path, "a+");
+ dlt_logstorage_open_log_output_file(config, absolute_file_path, "a");
dlt_vlog(LOG_DEBUG,
"%s: Filename and Index after updating [%s]-[%u]\n",
@@ -590,7 +632,11 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config,
}
}
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (config->gzlog == NULL && config->log == NULL) {
+#else
if (config->log == NULL) {
+#endif
if (*tmp != NULL) {
if ((*tmp)->name != NULL) {
free((*tmp)->name);
@@ -665,12 +711,36 @@ DLT_STATIC int dlt_logstorage_find_last_dlt_header(void *ptr,
}
/**
+ * dlt_logstorage_write_to_log
+ *
+ * Write logdata to log storage file
+ *
+ * @param ptr A pointer to the data to write
+ * @param size The size of the data blocks
+ * @param nmemb The number of blocks to write
+ * @param config A pointer to DltLogStorageFilterConfig
+ */
+DLT_STATIC int dlt_logstorage_write_to_log(void *ptr, size_t size, size_t nmemb,
+ DltLogStorageFilterConfig *config)
+{
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (config->gzip_compression) {
+ return gzfwrite(ptr, size, nmemb, config->gzlog);
+ } else {
+ return fwrite(ptr, size, nmemb, config->log);
+ }
+#else
+ return fwrite(ptr, size, nmemb, config->log);
+#endif
+}
+
+/**
* dlt_logstorage_check_write_ret
*
- * check the return value of fwrite
+ * check the return value of fwrite/gzfwrite
*
* @param config DltLogStorageFilterConfig
- * @param ret return value of fwrite call
+ * @param ret return value of fwrite/gzfwrite call
*/
DLT_STATIC void dlt_logstorage_check_write_ret(DltLogStorageFilterConfig *config,
int ret)
@@ -679,20 +749,60 @@ DLT_STATIC void dlt_logstorage_check_write_ret(DltLogStorageFilterConfig *config
dlt_vlog(LOG_ERR, "%s: cannot retrieve config information\n", __func__);
if (ret <= 0) {
- if (ferror(config->log) != 0)
- dlt_vlog(LOG_ERR, "%s: failed to write cache into log file\n", __func__);
+ if (config->gzip_compression) {
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ const char *msg = gzerror(config->gzlog, &ret);
+ if (msg != NULL) {
+ dlt_vlog(LOG_ERR, "%s: failed to write cache into log file: %s\n", __func__, msg);
+ }
+#endif
+ } else {
+ if (ferror(config->log) != 0)
+ dlt_vlog(LOG_ERR, "%s: failed to write cache into log file\n", __func__);
+ }
}
else {
/* force sync */
- if (fflush(config->log) != 0)
- dlt_vlog(LOG_ERR, "%s: failed to flush log file\n", __func__);
+ if (config->gzip_compression) {
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (gzflush(config->gzlog, Z_SYNC_FLUSH) != 0)
+ dlt_vlog(LOG_ERR, "%s: failed to gzflush log file\n", __func__);
+#endif
+ } else {
+ if (fflush(config->log) != 0)
+ dlt_vlog(LOG_ERR, "%s: failed to flush log file\n", __func__);
+ }
- if (fsync(fileno(config->log)) != 0)
+ if (fsync(config->fd) != 0) {
/* some filesystem doesn't support fsync() */
- if (errno != ENOSYS)
- {
- dlt_vlog(LOG_ERR, "%s: failed to sync log file\n", __func__);
+ if (errno != ENOSYS) {
+ dlt_vlog(LOG_ERR, "%s: failed to sync log file\n",
+ __func__);
}
+ }
+ }
+}
+
+/**
+ * dlt_logstorage_close_file
+ *
+ * Close open file handles if any exist in the provided
+ * DltLogStorageFilterConfig
+ *
+ * @param config The DltLogStorageFilterConfig to operate on
+ */
+DLT_STATIC void dlt_logstorage_close_file(DltLogStorageFilterConfig *config)
+{
+
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (config->gzlog) {
+ gzclose(config->gzlog);
+ config->gzlog = NULL;
+ }
+#endif
+ if (config->log) {
+ fclose(config->log);
+ config->log = NULL;
}
}
@@ -734,11 +844,8 @@ DLT_STATIC int dlt_logstorage_sync_to_file(DltLogStorageFilterConfig *config,
/* In case of cached-based strategy, the newest file information
* must be updated everytime of synchronization.
*/
- if (config->log) {
- fclose(config->log);
- config->log = NULL;
- config->current_write_file_offset = 0;
- }
+ dlt_logstorage_close_file(config);
+ config->current_write_file_offset = 0;
if (dlt_logstorage_open_log_file(config, file_config,
dev_path, count, true) != 0) {
@@ -761,13 +868,11 @@ DLT_STATIC int dlt_logstorage_sync_to_file(DltLogStorageFilterConfig *config,
if ((start_index >= 0) && (end_index > start_index) &&
(count > 0) && (count <= remain_file_size))
{
- ret = fwrite((uint8_t*)config->cache + start_offset + start_index,
- count, 1, config->log);
+ dlt_logstorage_write_to_log((uint8_t*)config->cache + start_offset + start_index, count, 1, config);
dlt_logstorage_check_write_ret(config, ret);
/* Close log file */
- fclose(config->log);
- config->log = NULL;
+ dlt_logstorage_close_file(config);
config->current_write_file_offset = 0;
footer->last_sync_offset = start_offset + count;
@@ -776,8 +881,7 @@ DLT_STATIC int dlt_logstorage_sync_to_file(DltLogStorageFilterConfig *config,
else
{
/* Close log file */
- fclose(config->log);
- config->log = NULL;
+ dlt_logstorage_close_file(config);
config->current_write_file_offset = 0;
}
}
@@ -798,8 +902,7 @@ DLT_STATIC int dlt_logstorage_sync_to_file(DltLogStorageFilterConfig *config,
}
}
- ret = fwrite((uint8_t*)config->cache + start_offset + start_index, count, 1,
- config->log);
+ ret = dlt_logstorage_write_to_log((uint8_t *)config->cache + start_offset + start_index, count, 1, config);
dlt_logstorage_check_write_ret(config, ret);
config->current_write_file_offset += count;
@@ -835,12 +938,16 @@ int dlt_logstorage_prepare_on_msg(DltLogStorageFilterConfig *config,
if ((config == NULL) || (file_config == NULL) || (dev_path == NULL) ||
(newest_file_info == NULL)) {
- dlt_vlog(LOG_INFO, "Wrong paratemters\n");
+ dlt_vlog(LOG_DEBUG, "Wrong paratemters\n");
return -1;
}
/* This is for ON_MSG/UNSET strategy */
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (config->log == NULL && config->gzlog == NULL) {
+#else
if (config->log == NULL) {
+#endif
/* Sync the wrap id and working file name before opening log file */
if (config->wrap_id < newest_file_info->wrap_id) {
config->wrap_id = newest_file_info->wrap_id;
@@ -859,17 +966,20 @@ int dlt_logstorage_prepare_on_msg(DltLogStorageFilterConfig *config,
true);
}
else { /* already open, check size and create a new file if needed */
- ret = fstat(fileno(config->log), &s);
+ ret = fstat(config->fd, &s);
if (ret == 0) {
- /* check if adding new data do not exceed max file size */
- /* Check if wrap id needs to be updated*/
+ /* Check if adding new data do not exceed max file size
+ *
+ * This is inaccurate for gz compressed files but as long as log
+ * messages aren't gigantic it should be negligeble
+ *
+ * Also check if wrap id needs to be updated */
if ((s.st_size + log_msg_size > (int)config->file_size) ||
(strcmp(config->working_file_name, newest_file_info->newest_file) != 0) ||
(config->wrap_id < newest_file_info->wrap_id)) {
- fclose(config->log);
- config->log = NULL;
+ dlt_logstorage_close_file(config);
/* Sync the wrap id and working file name before opening log file */
if (config->wrap_id <= newest_file_info->wrap_id) {
@@ -935,22 +1045,29 @@ int dlt_logstorage_write_on_msg(DltLogStorageFilterConfig *config,
return -1;
}
- ret = fwrite(data1, 1, size1, config->log);
+ ret = dlt_logstorage_write_to_log(data1, 1, size1, config);
if (ret != size1)
dlt_log(LOG_WARNING, "Wrote less data than specified\n");
- ret = fwrite(data2, 1, size2, config->log);
-
+ ret = dlt_logstorage_write_to_log(data2, 1, size2, config);
if (ret != size2)
dlt_log(LOG_WARNING, "Wrote less data than specified\n");
- ret = fwrite(data3, 1, size3, config->log);
-
+ ret = dlt_logstorage_write_to_log(data3, 1, size3, config);
if (ret != size3)
dlt_log(LOG_WARNING, "Wrote less data than specified\n");
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (config->gzip_compression) {
+ gzerror(config->gzlog, &ret);
+ return ret;
+ } else {
+ return ferror(config->log);
+ }
+#else
return ferror(config->log);
+#endif
}
/**
@@ -969,8 +1086,6 @@ int dlt_logstorage_sync_on_msg(DltLogStorageFilterConfig *config,
char *dev_path,
int status)
{
- int ret;
-
(void)file_config; /* satisfy compiler */
(void)dev_path;
@@ -978,10 +1093,15 @@ int dlt_logstorage_sync_on_msg(DltLogStorageFilterConfig *config,
return -1;
if (status == DLT_LOGSTORAGE_SYNC_ON_MSG) { /* sync on every message */
- ret = fflush(config->log);
-
- if (ret != 0)
- dlt_log(LOG_ERR, "fflush failed\n");
+ if (config->gzip_compression) {
+#ifdef DLT_LOGSTORAGE_USE_GZIP
+ if (gzflush(config->gzlog, Z_SYNC_FLUSH) != 0)
+ dlt_vlog(LOG_ERR, "%s: failed to gzflush log file\n", __func__);
+#endif
+ } else {
+ if (fflush(config->log) != 0)
+ dlt_vlog(LOG_ERR, "%s: failed to flush log file\n", __func__);
+ }
}
return 0;
@@ -1234,7 +1354,7 @@ int dlt_logstorage_write_msg_cache(DltLogStorageFilterConfig *config,
memcpy(curr_write_addr, data2, size2);
curr_write_addr += size2;
memcpy(curr_write_addr, data3, size3);
- }
+ }
}
@@ -1335,8 +1455,7 @@ int dlt_logstorage_sync_msg_cache(DltLogStorageFilterConfig *config,
if (status == DLT_LOGSTORAGE_SYNC_ON_FILE_SIZE)
{
/* Close log file */
- fclose(config->log);
- config->log = NULL;
+ dlt_logstorage_close_file(config);
config->current_write_file_offset = 0;
}
}
diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h b/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h
index b493db4..fd23bb8 100644
--- a/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h
+++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h
@@ -51,15 +51,17 @@
void dlt_logstorage_log_file_name(char *log_file_name,
DltLogStorageUserConfig *file_config,
- char *name,
+ DltLogStorageFilterConfig *filter_config,
int idx);
unsigned int dlt_logstorage_sort_file_name(DltLogStorageFileList **head);
void dlt_logstorage_rearrange_file_name(DltLogStorageFileList **head);
-unsigned int dlt_logstorage_get_idx_of_log_file(DltLogStorageUserConfig *file_config,
- char *file);
+unsigned int
+dlt_logstorage_get_idx_of_log_file(DltLogStorageUserConfig *file_config,
+ DltLogStorageFilterConfig *config,
+ char *file);
int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config,
char *path,
diff --git a/src/offlinelogstorage/dlt_offline_logstorage_internal.h b/src/offlinelogstorage/dlt_offline_logstorage_internal.h
index d150b6f..ed126eb 100644
--- a/src/offlinelogstorage/dlt_offline_logstorage_internal.h
+++ b/src/offlinelogstorage/dlt_offline_logstorage_internal.h
@@ -68,6 +68,8 @@ DLT_STATIC int dlt_logstorage_count_ids(const char *str);
DLT_STATIC int dlt_logstorage_read_number(unsigned int *number, char *value);
+DLT_STATIC int dlt_logstorage_read_bool(unsigned int *boolean, char *value);
+
DLT_STATIC int dlt_logstorage_read_list_of_names(char **names, char *value);
DLT_STATIC int dlt_logstorage_check_apids(DltLogStorageFilterConfig *config, char *value);
@@ -76,6 +78,8 @@ DLT_STATIC int dlt_logstorage_check_ctids(DltLogStorageFilterConfig *config, cha
DLT_STATIC int dlt_logstorage_check_loglevel(DltLogStorageFilterConfig *config, char *value);
+DLT_STATIC int dlt_logstorage_check_gzip_compression(DltLogStorageFilterConfig *config, char *value);
+
DLT_STATIC int dlt_logstorage_check_filename(DltLogStorageFilterConfig *config, char *value);
DLT_STATIC int dlt_logstorage_check_filesize(DltLogStorageFilterConfig *config, char *value);
diff --git a/src/shared/dlt_common.c b/src/shared/dlt_common.c
index 427044b..cbbe99a 100644
--- a/src/shared/dlt_common.c
+++ b/src/shared/dlt_common.c
@@ -31,6 +31,7 @@
#include <time.h> /* for localtime_r(), strftime() */
#include <limits.h> /* for NAME_MAX */
#include <inttypes.h> /* for PRI formatting macro */
+#include <libgen.h> /* dirname */
#include <stdarg.h>
#include <err.h>
@@ -41,6 +42,7 @@
#include "dlt_user_shared.h"
#include "dlt_common.h"
#include "dlt_common_cfg.h"
+#include "dlt_multiple_files.h"
#include "dlt_version.h"
@@ -81,9 +83,20 @@ char dltShmName[NAME_MAX + 1] = "/dlt-shm";
static int logging_level = LOG_INFO;
static char logging_filename[NAME_MAX + 1] = "";
static bool print_with_attributes = false;
-int logging_mode = DLT_LOG_TO_CONSOLE;
+int logging_mode = DLT_LOG_TO_STDERR;
FILE *logging_handle = NULL;
+//use ohandle as an indicator that multiple files logging is active
+MultipleFilesRingBuffer multiple_files_ring_buffer = {
+ .directory={0},
+ .filename={0},
+ .fileSize=0,
+ .maxSize=0,
+ .filenameTimestampBased=false,
+ .filenameBase={0},
+ .filenameExt={0},
+ .ohandle=-1};
+
char *message_type[] = { "log", "app_trace", "nw_trace", "control", "", "", "", "" };
char *log_info[] = { "", "fatal", "error", "warn", "info", "debug", "verbose", "", "", "", "", "", "", "", "", "" };
char *trace_type[] = { "", "variable", "func_in", "func_out", "state", "vfb", "", "", "", "", "", "", "", "", "", "" };
@@ -202,7 +215,10 @@ DltReturnValue dlt_print_mixed_string(char *text, int textlength, uint8_t *ptr,
/* Hex-Output */
/* It is not required to decrement textlength, as it was already checked, that
* there is enough space for the complete output */
- dlt_print_hex_string(text, textlength, (uint8_t *)(ptr + (lines * DLT_COMMON_HEX_CHARS)), DLT_COMMON_HEX_CHARS);
+ if (dlt_print_hex_string(text, textlength,
+ (uint8_t *)(ptr + (lines * DLT_COMMON_HEX_CHARS)),
+ DLT_COMMON_HEX_CHARS) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
text += ((2 * DLT_COMMON_HEX_CHARS) + (DLT_COMMON_HEX_CHARS - 1)); /* 32 characters + 15 spaces */
snprintf(text, 2, " ");
@@ -211,8 +227,10 @@ DltReturnValue dlt_print_mixed_string(char *text, int textlength, uint8_t *ptr,
/* Char-Output */
/* It is not required to decrement textlength, as it was already checked, that
* there is enough space for the complete output */
- dlt_print_char_string(&text, textlength, (uint8_t *)(ptr + (lines * DLT_COMMON_HEX_CHARS)),
- DLT_COMMON_HEX_CHARS);
+ if (dlt_print_char_string(&text, textlength,
+ (uint8_t *)(ptr + (lines * DLT_COMMON_HEX_CHARS)),
+ DLT_COMMON_HEX_CHARS) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
if (html == 0) {
snprintf(text, 2, "\n");
@@ -240,10 +258,11 @@ DltReturnValue dlt_print_mixed_string(char *text, int textlength, uint8_t *ptr,
/* Hex-Output */
/* It is not required to decrement textlength, as it was already checked, that
* there is enough space for the complete output */
- dlt_print_hex_string(text,
+ if (dlt_print_hex_string(text,
textlength,
(uint8_t *)(ptr + ((size / DLT_COMMON_HEX_CHARS) * DLT_COMMON_HEX_CHARS)),
- rest);
+ rest) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
text += 2 * rest + (rest - 1);
for (i = 0; i < (DLT_COMMON_HEX_CHARS - rest); i++) {
@@ -257,8 +276,10 @@ DltReturnValue dlt_print_mixed_string(char *text, int textlength, uint8_t *ptr,
/* Char-Output */
/* It is not required to decrement textlength, as it was already checked, that
* there is enough space for the complete output */
- dlt_print_char_string(&text, textlength,
- (uint8_t *)(ptr + ((size / DLT_COMMON_HEX_CHARS) * DLT_COMMON_HEX_CHARS)), rest);
+ if (dlt_print_char_string(&text, textlength,
+ (uint8_t *)(ptr + ((size / DLT_COMMON_HEX_CHARS) * DLT_COMMON_HEX_CHARS)),
+ rest) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
}
return DLT_RETURN_OK;
@@ -672,6 +693,9 @@ DltReturnValue dlt_message_header_flags(DltMessage *msg, char *text, size_t text
if ((msg == NULL) || (text == NULL) || (textlength <= 0))
return DLT_RETURN_WRONG_PARAMETER;
+ if ((DLT_IS_HTYP_UEH(msg->standardheader->htyp)) && (msg->extendedheader == NULL))
+ return DLT_RETURN_WRONG_PARAMETER;
+
if ((flags < DLT_HEADER_SHOW_NONE) || (flags > DLT_HEADER_SHOW_ALL))
return DLT_RETURN_WRONG_PARAMETER;
@@ -1707,7 +1731,7 @@ DltReturnValue dlt_file_message(DltFile *file, int index, int verbose)
return DLT_RETURN_WRONG_PARAMETER;
/* check if message is in range */
- if (index >= file->counter) {
+ if (index < 0 || index >= file->counter) {
dlt_vlog(LOG_WARNING, "Message %d out of range!\r\n", index);
return DLT_RETURN_WRONG_PARAMETER;
}
@@ -1803,34 +1827,116 @@ void dlt_print_with_attributes(bool state)
print_with_attributes = state;
}
-void dlt_log_init(int mode)
+DltReturnValue dlt_log_init(int mode)
+{
+ return dlt_log_init_multiple_logfiles_support((DltLoggingMode)mode, false, 0, 0);
+}
+
+DltReturnValue dlt_log_init_multiple_logfiles_support(const DltLoggingMode mode, const bool enable_multiple_logfiles,
+ const int logging_file_size, const int logging_files_max_size)
{
if ((mode < DLT_LOG_TO_CONSOLE) || (mode > DLT_LOG_DROPPED)) {
dlt_vlog(LOG_WARNING, "Wrong parameter for mode: %d\n", mode);
- return;
+ return DLT_RETURN_WRONG_PARAMETER;
}
logging_mode = mode;
- if (logging_mode == DLT_LOG_TO_FILE) {
- /* internal logging to file */
- logging_handle = fopen(logging_filename, "a");
+ if (logging_mode != DLT_LOG_TO_FILE) {
+ return DLT_RETURN_OK;
+ }
- if (logging_handle == NULL) {
- dlt_user_printf("Internal log file %s cannot be opened!\n", logging_filename);
- return;
+ if (enable_multiple_logfiles) {
+ dlt_user_printf("configure dlt logging using file limits\n");
+ int result = dlt_log_init_multiple_logfiles(logging_file_size, logging_files_max_size);
+ if (result == DLT_RETURN_OK) {
+ return DLT_RETURN_OK;
}
+ dlt_user_printf("dlt logging for limits fails with error code=%d, use logging without limits as fallback\n", result);
+ return dlt_log_init_single_logfile();
+ } else {
+ dlt_user_printf("configure dlt logging without file limits\n");
+ return dlt_log_init_single_logfile();
+ }
+}
+
+DltReturnValue dlt_log_init_single_logfile()
+{
+ /* internal logging to file */
+ errno = 0;
+ logging_handle = fopen(logging_filename, "a");
+
+ if (logging_handle == NULL) {
+ dlt_user_printf("Internal log file %s cannot be opened, error: %s\n", logging_filename, strerror(errno));
+ return DLT_RETURN_ERROR;
}
+ return DLT_RETURN_OK;
+}
+
+DltReturnValue dlt_log_init_multiple_logfiles(const int logging_file_size, const int logging_files_max_size)
+{
+ char path_logging_filename[PATH_MAX + 1];
+ strncpy(path_logging_filename, logging_filename, PATH_MAX);
+ path_logging_filename[PATH_MAX] = 0;
+
+ const char *directory = dirname(path_logging_filename);
+ if (directory[0]) {
+ char basename_logging_filename[NAME_MAX + 1];
+ strncpy(basename_logging_filename, logging_filename, NAME_MAX);
+ basename_logging_filename[NAME_MAX] = 0;
+
+ const char *file_name = basename(basename_logging_filename);
+ char filename_base[NAME_MAX];
+ if (!dlt_extract_base_name_without_ext(file_name, filename_base, sizeof(filename_base))) return DLT_RETURN_ERROR;
+
+ const char *filename_ext = get_filename_ext(file_name);
+ if (!filename_ext) return DLT_RETURN_ERROR;
+
+ DltReturnValue result = multiple_files_buffer_init(
+ &multiple_files_ring_buffer,
+ directory,
+ logging_file_size,
+ logging_files_max_size,
+ false,
+ true,
+ filename_base,
+ filename_ext);
+
+ return result;
+ }
+
+ return DLT_RETURN_ERROR;
}
void dlt_log_free(void)
{
- if (logging_mode == DLT_LOG_TO_FILE)
+ if (logging_mode == DLT_LOG_TO_FILE) {
+ if (dlt_is_log_in_multiple_files_active()) {
+ dlt_log_free_multiple_logfiles();
+ } else {
+ dlt_log_free_single_logfile();
+ }
+ }
+}
+
+void dlt_log_free_single_logfile()
+{
+ if (logging_handle)
fclose(logging_handle);
}
+void dlt_log_free_multiple_logfiles()
+{
+ if (DLT_RETURN_ERROR == multiple_files_buffer_free(&multiple_files_ring_buffer)) return;
+
+ // reset indicator of multiple files usage
+ multiple_files_ring_buffer.ohandle = -1;
+}
+
int dlt_user_printf(const char *format, ...)
{
+ if (format == NULL) return -1;
+
va_list args;
va_start(args, format);
@@ -1909,9 +2015,13 @@ DltReturnValue dlt_log(int prio, char *s)
#endif
break;
case DLT_LOG_TO_FILE:
-
/* log to file */
- if (logging_handle) {
+
+ if (dlt_is_log_in_multiple_files_active()) {
+ dlt_log_multiple_files_write(sFormatString, (unsigned int)sTimeSpec.tv_sec,
+ (unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s);
+ }
+ else if (logging_handle) {
fprintf(logging_handle, sFormatString, (unsigned int)sTimeSpec.tv_sec,
(unsigned int)(sTimeSpec.tv_nsec / 1000), getpid(), asSeverity[prio], s);
fflush(logging_handle);
@@ -3239,7 +3349,8 @@ DltReturnValue dlt_message_print_header(DltMessage *message, char *text, uint32_
if ((message == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- dlt_message_header(message, text, size, verbose);
+ if (dlt_message_header(message, text, size, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("%s\n", text);
return DLT_RETURN_OK;
@@ -3250,9 +3361,12 @@ DltReturnValue dlt_message_print_hex(DltMessage *message, char *text, uint32_t s
if ((message == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- dlt_message_header(message, text, size, verbose);
+ if (dlt_message_header(message, text, size, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("%s ", text);
- dlt_message_payload(message, text, size, DLT_OUTPUT_HEX, verbose);
+
+ if (dlt_message_payload(message, text, size, DLT_OUTPUT_HEX, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("[%s]\n", text);
return DLT_RETURN_OK;
@@ -3263,9 +3377,12 @@ DltReturnValue dlt_message_print_ascii(DltMessage *message, char *text, uint32_t
if ((message == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- dlt_message_header(message, text, size, verbose);
+ if (dlt_message_header(message, text, size, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("%s ", text);
- dlt_message_payload(message, text, size, DLT_OUTPUT_ASCII, verbose);
+
+ if (dlt_message_payload(message, text, size, DLT_OUTPUT_ASCII, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("[%s]\n", text);
return DLT_RETURN_OK;
@@ -3276,9 +3393,12 @@ DltReturnValue dlt_message_print_mixed_plain(DltMessage *message, char *text, ui
if ((message == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- dlt_message_header(message, text, size, verbose);
+ if (dlt_message_header(message, text, size, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("%s \n", text);
- dlt_message_payload(message, text, size, DLT_OUTPUT_MIXED_FOR_PLAIN, verbose);
+
+ if (dlt_message_payload(message, text, size, DLT_OUTPUT_MIXED_FOR_PLAIN, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("[%s]\n", text);
return DLT_RETURN_OK;
@@ -3289,9 +3409,13 @@ DltReturnValue dlt_message_print_mixed_html(DltMessage *message, char *text, uin
if ((message == NULL) || (text == NULL))
return DLT_RETURN_WRONG_PARAMETER;
- dlt_message_header(message, text, size, verbose);
+ if (dlt_message_header(message, text, size, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
dlt_user_printf("%s \n", text);
- dlt_message_payload(message, text, size, DLT_OUTPUT_MIXED_FOR_HTML, verbose);
+
+ if (dlt_message_payload(message, text, size, DLT_OUTPUT_MIXED_FOR_HTML, verbose) < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
+
dlt_user_printf("[%s]\n", text);
return DLT_RETURN_OK;
@@ -3901,7 +4025,8 @@ DltReturnValue dlt_message_argument_print(DltMessage *msg,
if ((*datalength) < length)
return DLT_RETURN_ERROR;
- dlt_print_hex_string_delim(value_text, (int) textlength, *ptr, length, '\'');
+ if (dlt_print_hex_string_delim(value_text, (int) textlength, *ptr, length, '\'') < DLT_RETURN_OK)
+ return DLT_RETURN_ERROR;
*ptr += length;
*datalength -= length;
}
@@ -4034,7 +4159,7 @@ int16_t dlt_getloginfo_conv_ascii_to_uint16_t(char *rp, int *rp_count)
num_work[4] = 0;
*rp_count += 6;
- return (unsigned char)strtol(num_work, &endptr, 16);
+ return (uint16_t)strtol(num_work, &endptr, 16);
}
int16_t dlt_getloginfo_conv_ascii_to_int16_t(char *rp, int *rp_count)
@@ -4056,17 +4181,31 @@ int16_t dlt_getloginfo_conv_ascii_to_int16_t(char *rp, int *rp_count)
return (signed char)strtol(num_work, &endptr, 16);
}
-void dlt_getloginfo_conv_ascii_to_id(char *rp, int *rp_count, char *wp, int len)
+void dlt_getloginfo_conv_ascii_to_string(char *rp, int *rp_count, char *wp, int len)
+{
+ if ((rp == NULL ) || (rp_count == NULL ) || (wp == NULL ))
+ return;
+ /* ------------------------------------------------------
+ * from: [72 65 6d 6f ] -> to: [0x72,0x65,0x6d,0x6f,0x00]
+ * ------------------------------------------------------ */
+
+ int count = dlt_getloginfo_conv_ascii_to_id(rp, rp_count, wp, len);
+ *(wp + count) = '\0';
+
+ return;
+}
+
+int dlt_getloginfo_conv_ascii_to_id(char *rp, int *rp_count, char *wp, int len)
{
char number16[3] = { 0 };
char *endptr;
int count;
if ((rp == NULL) || (rp_count == NULL) || (wp == NULL))
- return;
+ return 0;
/* ------------------------------------------------------
- * from: [72 65 6d 6f ] -> to: [0x72,0x65,0x6d,0x6f,0x00]
+ * from: [72 65 6d 6f ] -> to: [0x72,0x65,0x6d,0x6f]
* ------------------------------------------------------ */
for (count = 0; count < len; count++) {
number16[0] = *(rp + *rp_count + 0);
@@ -4075,8 +4214,7 @@ void dlt_getloginfo_conv_ascii_to_id(char *rp, int *rp_count, char *wp, int len)
*rp_count += 3;
}
- *(wp + count) = 0;
- return;
+ return count;
}
void dlt_hex_ascii_to_binary(const char *ptr, uint8_t *binary, int *size)
@@ -4267,3 +4405,42 @@ int dlt_execute_command(char *filename, char *command, ...)
free(args);
return ret;
}
+
+char *get_filename_ext(const char *filename)
+{
+ if (filename == NULL) {
+ fprintf(stderr, "ERROR: %s: invalid arguments\n", __FUNCTION__);
+ return NULL;
+ }
+
+ char *dot = strrchr(filename, '.');
+ return (!dot || dot == filename) ? NULL : dot;
+}
+
+bool dlt_extract_base_name_without_ext(const char* const abs_file_name, char* base_name, long base_name_len) {
+ if (abs_file_name == NULL || base_name == NULL) return false;
+
+ const char* last_separator = strrchr(abs_file_name, '.');
+ if (!last_separator) return false;
+ long length = last_separator - abs_file_name;
+ length = length > base_name_len ? base_name_len : length;
+
+ strncpy(base_name, abs_file_name, length);
+ base_name[length] = '\0';
+ return true;
+}
+
+void dlt_log_multiple_files_write(const char* format, ...)
+{
+ char output_string[2048] = { 0 };
+ va_list args;
+ va_start (args, format);
+ vsnprintf(output_string, 2047, format, args);
+ va_end (args);
+ multiple_files_buffer_write(&multiple_files_ring_buffer, (unsigned char*)output_string, strlen(output_string));
+}
+
+bool dlt_is_log_in_multiple_files_active()
+{
+ return multiple_files_ring_buffer.ohandle > -1;
+}
diff --git a/src/shared/dlt_config_file_parser.c b/src/shared/dlt_config_file_parser.c
index 009a093..72c57ab 100644
--- a/src/shared/dlt_config_file_parser.c
+++ b/src/shared/dlt_config_file_parser.c
@@ -148,6 +148,7 @@ static int dlt_config_file_set_section(DltConfigFile *file, char *name)
if (s->keys == NULL) {
free(s->name);
+ s->name = NULL;
dlt_log(LOG_ERR, "Cannot allocate memory for internal data structure\n");
return -1;
}
@@ -495,6 +496,7 @@ int dlt_config_file_get_section_name(const DltConfigFile *file,
return -1;
strncpy(name, (file->sections + num)->name, DLT_CONFIG_FILE_ENTRY_MAX_LEN);
+ name[DLT_CONFIG_FILE_ENTRY_MAX_LEN - 1] = '\0';
return 0;
}
diff --git a/src/shared/dlt_multiple_files.c b/src/shared/dlt_multiple_files.c
new file mode 100644
index 0000000..0142505
--- /dev/null
+++ b/src/shared/dlt_multiple_files.c
@@ -0,0 +1,498 @@
+/*
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2022, Daimler TSS GmbH
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see https://www.covesa.global/.
+ */
+
+/*!
+ * \author
+ * Oleg Tropmann <oleg.tropmann@daimler.com>
+ * Daniel Weber <daniel.w.weber@daimler.com>
+ *
+ * \copyright Copyright © 2022 Daimler TSS GmbH. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_log.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "dlt_multiple_files.h"
+#include "dlt_common.h"
+
+unsigned int multiple_files_buffer_storage_dir_info(const char *path, const char *file_name,
+ char *newest, char *oldest)
+{
+ int i = 0;
+ unsigned int num_log_files = 0;
+ struct dirent **files = { 0 };
+ char *tmp_old = NULL;
+ char *tmp_new = NULL;
+
+ if ((path == NULL) || (file_name == NULL) || (newest == NULL) || (oldest == NULL)) {
+ fprintf(stderr, "multiple_files_buffer_storage_dir_info: Invalid parameter(s)");
+ return 0;
+ }
+
+ const int file_cnt = scandir(path, &files, NULL, alphasort);
+ if (file_cnt <= 0) return 0;
+
+ for (i = 0; i < file_cnt; i++) {
+ int len = 0;
+ len = strlen(file_name);
+
+ if ((strncmp(files[i]->d_name, file_name, len) == 0) &&
+ (files[i]->d_name[len] == MULTIPLE_FILES_FILENAME_INDEX_DELIM[0])) {
+ num_log_files++;
+
+ if ((tmp_old == NULL) || (strlen(tmp_old) >= strlen(files[i]->d_name))) {
+ if (tmp_old == NULL) {
+ tmp_old = files[i]->d_name;
+ } else if (strlen(tmp_old) > strlen(files[i]->d_name)) {
+ /* when file name is smaller, it is older */
+ tmp_old = files[i]->d_name;
+ } else if (strcmp(tmp_old, files[i]->d_name) > 0) {
+ /* filename length is equal, do a string compare */
+ tmp_old = files[i]->d_name;
+ }
+ }
+
+ if ((tmp_new == NULL) || (strlen(tmp_new) <= strlen(files[i]->d_name))) {
+ if (tmp_new == NULL) {
+ tmp_new = files[i]->d_name;
+ } else if (strlen(tmp_new) < strlen(files[i]->d_name)) {
+ /* when file name is longer, it is younger */
+ tmp_new = files[i]->d_name;
+ } else if (strcmp(tmp_new, files[i]->d_name) < 0) {
+ tmp_new = files[i]->d_name;
+ }
+ }
+ }
+ }
+
+ if (num_log_files > 0) {
+ if ((tmp_old != NULL) && (strlen(tmp_old) < NAME_MAX)) {
+ strncpy(oldest, tmp_old, NAME_MAX);
+ oldest[NAME_MAX] = '\0';
+ } else if ((tmp_old != NULL) && (strlen(tmp_old) >= NAME_MAX)) {
+ printf("length mismatch of file %s\n", tmp_old);
+ }
+
+ if ((tmp_new != NULL) && (strlen(tmp_new) < NAME_MAX)) {
+ strncpy(newest, tmp_new, NAME_MAX);
+ oldest[NAME_MAX] = '\0';
+ } else if ((tmp_new != NULL) && (strlen(tmp_new) >= NAME_MAX)) {
+ printf("length mismatch of file %s\n", tmp_new);
+ }
+ }
+
+ /* free scandir result */
+ for (i = 0; i < file_cnt; i++) free(files[i]);
+
+ free(files);
+
+ return num_log_files;
+}
+
+void multiple_files_buffer_file_name(MultipleFilesRingBuffer *files_buffer, const size_t length, const unsigned int idx)
+{
+ char file_index[11]; /* UINT_MAX = 4294967295 -> 10 digits */
+ snprintf(file_index, sizeof(file_index), "%010u", idx);
+
+ /* create log file name */
+ char* file_name = files_buffer->filename;
+ memset(file_name, 0, length * sizeof(char));
+
+ const size_t size = length - strlen(file_name) - 1;
+ strncat(file_name, files_buffer->filenameBase, size);
+ strncat(file_name, MULTIPLE_FILES_FILENAME_INDEX_DELIM, size);
+ strncat(file_name, file_index, size);
+ strncat(file_name, files_buffer->filenameExt, size);
+}
+
+unsigned int multiple_files_buffer_get_idx_of_log_file(char *file)
+{
+ if ((file == NULL) || (file[0] == '\0')) return 0;
+
+ const char d[2] = MULTIPLE_FILES_FILENAME_INDEX_DELIM;
+ char *token;
+
+ token = strtok(file, d);
+ /* we are interested in 2. token because of log file name */
+ token = strtok(NULL, d);
+
+ return token != NULL ? strtol(token, NULL, 10) : 0;
+}
+
+DltReturnValue multiple_files_buffer_create_new_file(MultipleFilesRingBuffer *files_buffer)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ time_t t;
+ struct tm tmp;
+ char file_path[PATH_MAX + 1];
+ unsigned int idx = 0;
+ int ret = 0;
+
+ /* set filename */
+ if (files_buffer->filenameTimestampBased) {
+ /* timestamp format: "yyyymmdd_hhmmss" */
+ char timestamp[16];
+ t = time(NULL);
+ tzset();
+ localtime_r(&t, &tmp);
+
+ strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", &tmp);
+
+ ret = snprintf(files_buffer->filename, sizeof(files_buffer->filename), "%s%s%s%s",
+ files_buffer->filenameBase,
+ MULTIPLE_FILES_FILENAME_TIMESTAMP_DELIM, timestamp,
+ files_buffer->filenameExt);
+
+ if ((ret < 0) || ((size_t)ret >= (int)sizeof(files_buffer->filename))) {
+ fprintf(stderr, "filename cannot be concatenated\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ ret = snprintf(file_path, sizeof(file_path), "%s/%s",
+ files_buffer->directory, files_buffer->filename);
+
+ if ((ret < 0) || ((size_t)ret >= (int)sizeof(file_path))) {
+ fprintf(stderr, "file path cannot be concatenated\n");
+ return DLT_RETURN_ERROR;
+ }
+ }
+ else {
+ char newest[NAME_MAX + 1] = { 0 };
+ char oldest[NAME_MAX + 1] = { 0 };
+ /* targeting newest file, ignoring number of files in dir returned */
+ if (0 == multiple_files_buffer_storage_dir_info(files_buffer->directory,
+ files_buffer->filenameBase,
+ newest,
+ oldest)) {
+ printf("No multiple files found\n");
+ }
+
+ idx = multiple_files_buffer_get_idx_of_log_file(newest) + 1;
+
+ multiple_files_buffer_file_name(files_buffer, sizeof(files_buffer->filename), idx);
+ ret = snprintf(file_path, sizeof(file_path), "%s/%s",
+ files_buffer->directory, files_buffer->filename);
+
+ if ((ret < 0) || (ret >= NAME_MAX)) {
+ fprintf(stderr, "filename cannot be concatenated\n");
+ return DLT_RETURN_ERROR;
+ }
+ }
+
+ /* open DLT output file */
+ errno = 0;
+ files_buffer->ohandle = open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
+ S_IRGRP | S_IROTH); /* mode: wb */
+
+ if (files_buffer->ohandle == -1) {
+ /* file cannot be opened */
+ fprintf(stderr, "file %s cannot be created, error: %s\n", file_path, strerror(errno));
+ return DLT_RETURN_ERROR;
+ }
+
+ return DLT_RETURN_OK;
+}
+
+ssize_t multiple_files_buffer_get_total_size(const MultipleFilesRingBuffer *files_buffer)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return -1;
+ }
+
+ struct dirent *dp;
+ char filename[PATH_MAX + 1];
+ ssize_t size = 0;
+ struct stat status;
+
+ /* go through all dlt files in directory */
+ DIR *dir = opendir(files_buffer->directory);
+ if (!dir) {
+ fprintf(stderr, "directory %s cannot be opened, error=%s\n", files_buffer->directory, strerror(errno));
+ return -1;
+ }
+
+ while ((dp = readdir(dir)) != NULL) {
+ // consider files matching with a specific base name and a particular extension
+ if (strstr(dp->d_name, files_buffer->filenameBase) && strstr(dp->d_name, files_buffer->filenameExt)) {
+ int res = snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name);
+
+ /* if the total length of the string is greater than the buffer, silently forget it. */
+ /* snprintf: a return value of size or more means that the output was truncated */
+ /* if an output error is encountered, a negative value is returned. */
+ if (((unsigned int)res < sizeof(filename)) && (res > 0)) {
+ errno = 0;
+ if (0 == stat(filename, &status))
+ size += status.st_size;
+ else
+ fprintf(stderr, "file %s cannot be stat-ed, error=%s\n", filename, strerror(errno));
+ }
+ }
+ }
+
+ closedir(dir);
+
+ /* return size */
+ return size;
+}
+
+int multiple_files_buffer_delete_oldest_file(MultipleFilesRingBuffer *files_buffer)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return -1; /* ERROR */
+ }
+
+ struct dirent *dp;
+ char filename[PATH_MAX + 1];
+ char filename_oldest[PATH_MAX + 1];
+ unsigned long size_oldest = 0;
+ struct stat status;
+ time_t time_oldest = 0;
+ int index_oldest = INT_MAX;
+
+ filename[0] = 0;
+ filename_oldest[0] = 0;
+
+ /* go through all dlt files in directory */
+ DIR *dir = opendir(files_buffer->directory);
+
+ if(!dir)
+ return -1;
+
+ while ((dp = readdir(dir)) != NULL) {
+ if (strstr(dp->d_name, files_buffer->filenameBase) && strstr(dp->d_name, files_buffer->filenameExt)) {
+ int res = snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name);
+
+ /* if the total length of the string is greater than the buffer, silently forget it. */
+ /* snprintf: a return value of size or more means that the output was truncated */
+ /* if an output error is encountered, a negative value is returned. */
+ if (((unsigned int) res >= sizeof(filename)) || (res <= 0)) {
+ printf("Filename for delete oldest too long. Skip file.\n");
+ continue;
+ }
+
+ if (files_buffer->filenameTimestampBased) {
+ errno = 0;
+ if (0 == stat(filename, &status)) {
+ if ((time_oldest == 0) || (status.st_mtime < time_oldest)) {
+ time_oldest = status.st_mtime;
+ size_oldest = status.st_size;
+ strncpy(filename_oldest, filename, PATH_MAX);
+ filename_oldest[PATH_MAX] = 0;
+ }
+ } else {
+ printf("Old file %s cannot be stat-ed, error=%s\n", filename, strerror(errno));
+ }
+ } else {
+ //index based
+ const int index = multiple_files_buffer_get_idx_of_log_file(filename);
+ if (index < index_oldest) {
+ index_oldest = index;
+ snprintf(filename, sizeof(filename), "%s/%s", files_buffer->directory, dp->d_name);
+ strncpy(filename_oldest, filename, PATH_MAX);
+ filename_oldest[PATH_MAX] = 0;
+ }
+ }
+ }
+ }
+
+ closedir(dir);
+
+ /* delete file */
+ if (filename_oldest[0]) {
+ if (remove(filename_oldest)) {
+ fprintf(stderr, "Remove file %s failed! error=%s\n", filename_oldest, strerror(errno));
+ return -1; /* ERROR */
+ }
+ } else {
+ fprintf(stderr, "No file to be removed!\n");
+ return -1; /* ERROR */
+ }
+
+ /* return size of deleted file*/
+ return size_oldest;
+}
+
+DltReturnValue multiple_files_buffer_check_size(MultipleFilesRingBuffer *files_buffer)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ struct stat status;
+
+ /* check for existence of buffer files directory */
+ errno = 0;
+ if (stat(files_buffer->directory, &status) == -1) {
+ fprintf(stderr, "Buffer files directory: %s doesn't exist, error=%s\n", files_buffer->directory, strerror(errno));
+ return DLT_RETURN_ERROR;
+ }
+ /* check for accessibility of buffer files directory */
+ else if (access(files_buffer->directory, W_OK) != 0) {
+ fprintf(stderr, "Buffer files directory: %s doesn't have the write access \n", files_buffer->directory);
+ return DLT_RETURN_ERROR;
+ }
+
+ ssize_t total_size = 0;
+ /* check size of complete buffer file */
+ while ((total_size = multiple_files_buffer_get_total_size(files_buffer)) > (files_buffer->maxSize - files_buffer->fileSize)) {
+ /* remove the oldest files as long as new file will not fit in completely into complete multiple files buffer */
+ if (multiple_files_buffer_delete_oldest_file(files_buffer) < 0) return DLT_RETURN_ERROR;
+ }
+
+ return total_size == -1 ? DLT_RETURN_ERROR : DLT_RETURN_OK;
+}
+
+DltReturnValue multiple_files_buffer_open_file_for_append(MultipleFilesRingBuffer *files_buffer) {
+ if (files_buffer == NULL || files_buffer->filenameTimestampBased) return DLT_RETURN_ERROR;
+
+ char newest[NAME_MAX + 1] = {0};
+ char oldest[NAME_MAX + 1] = {0};
+ /* targeting the newest file, ignoring number of files in dir returned */
+
+ if (0 == multiple_files_buffer_storage_dir_info(files_buffer->directory,
+ files_buffer->filenameBase, newest, oldest) ) {
+ // no file for appending found. Create a new one
+ printf("No multiple files for appending found. Create a new one\n");
+ return multiple_files_buffer_create_new_file(files_buffer);
+ }
+
+ char file_path[PATH_MAX + 1];
+ int ret = snprintf(file_path, sizeof(file_path), "%s/%s",
+ files_buffer->directory, newest);
+
+ if ((ret < 0) || (ret >= NAME_MAX)) {
+ fprintf(stderr, "filename cannot be concatenated\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ /* open DLT output file */
+ errno = 0;
+ files_buffer->ohandle = open(file_path, O_WRONLY | O_APPEND); /* mode: wb */
+
+ return files_buffer->ohandle == -1 ? DLT_RETURN_ERROR : DLT_RETURN_OK;
+}
+
+DltReturnValue multiple_files_buffer_init(MultipleFilesRingBuffer *files_buffer,
+ const char *directory,
+ const int file_size,
+ const int max_size,
+ const bool filename_timestamp_based,
+ const bool append,
+ const char *filename_base,
+ const char *filename_ext)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ /* init parameters */
+ strncpy(files_buffer->directory, directory, NAME_MAX);
+ files_buffer->directory[NAME_MAX] = 0;
+ files_buffer->fileSize = file_size;
+ files_buffer->maxSize = max_size;
+ files_buffer->filenameTimestampBased = filename_timestamp_based;
+ strncpy(files_buffer->filenameBase, filename_base, NAME_MAX);
+ files_buffer->filenameBase[NAME_MAX] = 0;
+ strncpy(files_buffer->filenameExt, filename_ext, NAME_MAX);
+ files_buffer->filenameExt[NAME_MAX] = 0;
+
+ if (DLT_RETURN_ERROR == multiple_files_buffer_check_size(files_buffer)) return DLT_RETURN_ERROR;
+
+ return (!files_buffer->filenameTimestampBased && append)
+ ? multiple_files_buffer_open_file_for_append(files_buffer)
+ : multiple_files_buffer_create_new_file(files_buffer);
+}
+
+void multiple_files_buffer_rotate_file(MultipleFilesRingBuffer *files_buffer, const int size)
+{
+ /* check file size here */
+ if ((lseek(files_buffer->ohandle, 0, SEEK_CUR) + size) < files_buffer->fileSize) return;
+
+ /* close old file */
+ close(files_buffer->ohandle);
+ files_buffer->ohandle = -1;
+
+ /* check complete files size, remove old logs if needed */
+ if (DLT_RETURN_ERROR == multiple_files_buffer_check_size(files_buffer)) return;
+
+ /* create new file */
+ multiple_files_buffer_create_new_file(files_buffer);
+}
+
+DltReturnValue multiple_files_buffer_write_chunk(const MultipleFilesRingBuffer *files_buffer,
+ const unsigned char *data,
+ const int size)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ if (data && (files_buffer->ohandle >= 0)) {
+ if (write(files_buffer->ohandle, data, size) != size) {
+ fprintf(stderr, "file write failed!\n");
+ return DLT_RETURN_ERROR;
+ }
+ }
+ return DLT_RETURN_OK;
+}
+
+DltReturnValue multiple_files_buffer_write(MultipleFilesRingBuffer *files_buffer,
+ const unsigned char *data,
+ const int size)
+{
+ if (files_buffer->ohandle < 0) return DLT_RETURN_ERROR;
+
+ multiple_files_buffer_rotate_file(files_buffer, size);
+
+ /* write data into log file */
+ return multiple_files_buffer_write_chunk(files_buffer, data, size);
+}
+
+DltReturnValue multiple_files_buffer_free(const MultipleFilesRingBuffer *files_buffer)
+{
+ if (files_buffer == NULL) {
+ fprintf(stderr, "multiple files buffer not set\n");
+ return DLT_RETURN_ERROR;
+ }
+
+ if (files_buffer->ohandle < 0) return DLT_RETURN_ERROR;
+
+ /* close last used log file */
+ close(files_buffer->ohandle);
+
+ return DLT_RETURN_OK;
+}
diff --git a/src/shared/dlt_offline_trace.c b/src/shared/dlt_offline_trace.c
index 2d70a77..b8b9a85 100644
--- a/src/shared/dlt_offline_trace.c
+++ b/src/shared/dlt_offline_trace.c
@@ -61,390 +61,28 @@
#include <unistd.h>
#include <dirent.h>
#include <syslog.h>
+#include <errno.h>
#include <dlt_offline_trace.h>
-#include "dlt_common.h"
-
-unsigned int dlt_offline_trace_storage_dir_info(char *path, char *file_name, char *newest, char *oldest)
-{
- int i = 0;
- unsigned int num = 0;
- int cnt = 0;
- struct dirent **files = { 0 };
- char *tmp_old = NULL;
- char *tmp_new = NULL;
-
- if ((path == NULL) || (file_name == NULL) || (newest == NULL) || (oldest == NULL)) {
- printf("dlt_offline_trace_storage_dir_info: Invalid parameter(s)");
- return 0;
- }
-
- cnt = scandir(path, &files, NULL, alphasort);
-
- if (cnt < 0)
- return 0;
-
- for (i = 0; i < cnt; i++) {
- int len = 0;
- len = strlen(file_name);
-
- if ((strncmp(files[i]->d_name, file_name, len) == 0) &&
- (files[i]->d_name[len] == DLT_OFFLINETRACE_FILENAME_INDEX_DELI[0])) {
- num++;
-
- if ((tmp_old == NULL) || (strlen(tmp_old) >= strlen(files[i]->d_name))) {
- if (tmp_old == NULL)
- tmp_old = files[i]->d_name;
- /* when file name is smaller, it is older */
- else if (strlen(tmp_old) > strlen(files[i]->d_name))
- tmp_old = files[i]->d_name;
- else /* filename is equal, do a string compare */
- if (strcmp(tmp_old, files[i]->d_name) > 0)
- tmp_old = files[i]->d_name;
- }
-
- if ((tmp_new == NULL) || (strlen(tmp_new) <= strlen(files[i]->d_name))) {
- if (tmp_new == NULL)
- tmp_new = files[i]->d_name;
- /* when file name is longer, it is younger */
- else if (strlen(tmp_new) < strlen(files[i]->d_name))
- tmp_new = files[i]->d_name;
- else if (strcmp(tmp_new, files[i]->d_name) < 0)
- tmp_new = files[i]->d_name;
- }
- }
- }
-
- if (num > 0) {
- if ((tmp_old != NULL) && (strlen(tmp_old) < NAME_MAX)) {
- strncpy(oldest, tmp_old, NAME_MAX);
- oldest[NAME_MAX] = '\0';
- }
-
- if ((tmp_new != NULL) && (strlen(tmp_old) < NAME_MAX)) {
- strncpy(newest, tmp_new, NAME_MAX);
- oldest[NAME_MAX] = '\0';
- }
- }
-
- /* free scandir result */
- for (i = 0; i < cnt; i++)
- free(files[i]);
-
- free(files);
-
- return num;
-}
-
-void dlt_offline_trace_file_name(char *log_file_name, size_t length,
- char *name, unsigned int idx)
-{
- char file_index[11]; /* UINT_MAX = 4294967295 -> 10 digits */
- snprintf(file_index, sizeof(file_index), "%010u", idx);
-
- /* create log file name */
- memset(log_file_name, 0, length * sizeof(char));
- strncat(log_file_name, name, length - strlen(log_file_name) - 1);
- strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_INDEX_DELI,
- length - strlen(log_file_name) - 1);
- strncat(log_file_name, file_index, length - strlen(log_file_name) - 1);
- strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_EXT,
- length - strlen(log_file_name) - 1);
-}
-
-unsigned int dlt_offline_trace_get_idx_of_log_file(char *file)
-{
- const char d[2] = DLT_OFFLINETRACE_FILENAME_INDEX_DELI;
- char *token;
- unsigned int idx = 0;
-
- if (file[0] == '\0')
- return 0;
-
- token = strtok(file, d);
- /* we are interested in 2. token because of log file name */
- token = strtok(NULL, d);
-
- if (token != NULL)
- idx = strtol(token, NULL, 10);
- else
- idx = 0;
-
- return idx;
-}
-
-
-DltReturnValue dlt_offline_trace_create_new_file(DltOfflineTrace *trace)
-{
- time_t t;
- struct tm tmp;
- char file_path[PATH_MAX + 1];
- unsigned int idx = 0;
- int ret = 0;
-
- /* set filename */
- if (trace->filenameTimestampBased) {
- /* timestamp format: "yyyymmdd_hhmmss" */
- char timestamp[16];
- t = time(NULL);
- tzset();
- localtime_r(&t, &tmp);
-
- strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", &tmp);
-
- ret = snprintf(trace->filename, sizeof(trace->filename), "%s%s%s%s",
- DLT_OFFLINETRACE_FILENAME_BASE,
- DLT_OFFLINETRACE_FILENAME_TIMESTAMP_DELI, timestamp,
- DLT_OFFLINETRACE_FILENAME_EXT);
-
- if ((ret < 0) || ((size_t)ret >= (int)sizeof(trace->filename))) {
- printf("dlt_offlinetrace filename cannot be concatenated\n");
- return DLT_RETURN_ERROR;
- }
-
- ret = snprintf(file_path, sizeof(file_path), "%s/%s",
- trace->directory, trace->filename);
-
- if ((ret < 0) || ((size_t)ret >= (int)sizeof(file_path))) {
- printf("dlt_offlinetrace file path cannot be concatenated\n");
- return DLT_RETURN_ERROR;
- }
- }
- else {
- char newest[NAME_MAX + 1] = { 0 };
- char oldest[NAME_MAX + 1] = { 0 };
- /* targeting newest file, ignoring number of files in dir returned */
- dlt_offline_trace_storage_dir_info(trace->directory,
- DLT_OFFLINETRACE_FILENAME_BASE, newest, oldest);
- idx = dlt_offline_trace_get_idx_of_log_file(newest) + 1;
-
- dlt_offline_trace_file_name(trace->filename, sizeof(trace->filename),
- DLT_OFFLINETRACE_FILENAME_BASE, idx);
- ret = snprintf(file_path, sizeof(file_path), "%s/%s",
- trace->directory, trace->filename);
-
- if ((ret < 0) || (ret >= NAME_MAX)) {
- printf("filename cannot be concatenated\n");
- return DLT_RETURN_ERROR;
- }
- }
-
- /* open DLT output file */
- trace->ohandle = open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
- S_IRGRP | S_IROTH); /* mode: wb */
-
- if (trace->ohandle == -1) {
- /* trace file cannot be opened */
- printf("Offline trace file %s cannot be created\n", file_path);
- return DLT_RETURN_ERROR;
- } /* if */
-
- return DLT_RETURN_OK; /* OK */
-}
-
-ssize_t dlt_offline_trace_get_total_size(DltOfflineTrace *trace)
+#include <dlt_multiple_files.h>
+
+DltReturnValue dlt_offline_trace_write(MultipleFilesRingBuffer *trace,
+ const unsigned char *data1,
+ const int size1,
+ const unsigned char *data2,
+ const int size2,
+ const unsigned char *data3,
+ const int size3)
{
- struct dirent *dp;
- char filename[PATH_MAX + 1];
- ssize_t size = 0;
- struct stat status;
-
- /* go through all dlt files in directory */
- DIR *dir = opendir(trace->directory);
-
- if (!dir)
- return -1;
- while ((dp = readdir(dir)) != NULL)
- if (strstr(dp->d_name, DLT_OFFLINETRACE_FILENAME_BASE)) {
- int res = snprintf(filename, sizeof(filename), "%s/%s", trace->directory, dp->d_name);
+ if (trace->ohandle < 0) return DLT_RETURN_ERROR;
- /* if the total length of the string is greater than the buffer, silently forget it. */
- /* snprintf: a return value of size or more means that the output was truncated */
- /* if an output error is encountered, a negative value is returned. */
- if (((unsigned int)res < sizeof(filename)) && (res > 0)) {
- if (0 == stat(filename, &status))
- size += status.st_size;
- else
- printf("Offline trace file %s cannot be stat-ed", filename);
- }
-
- /*else */
- /*{ */
- /* dlt_log(3, "dlt_offline_trace_get_total_size: long filename ignored"); */
- /*} */
- }
-
- closedir(dir);
-
- /* return size */
- return size;
-}
-
-int dlt_offline_trace_delete_oldest_file(DltOfflineTrace *trace)
-{
- struct dirent *dp;
- char filename[PATH_MAX + 1];
- char filename_oldest[PATH_MAX + 1];
- unsigned long size_oldest = 0;
- struct stat status;
- time_t time_oldest = 0;
-
- filename[0] = 0;
- filename_oldest[0] = 0;
-
- /* go through all dlt files in directory */
- DIR *dir = opendir(trace->directory);
-
- while ((dp = readdir(dir)) != NULL)
- if (strstr(dp->d_name, DLT_OFFLINETRACE_FILENAME_BASE)) {
- int res = snprintf(filename, sizeof(filename), "%s/%s", trace->directory, dp->d_name);
-
- /* if the total length of the string is greater than the buffer, silently forget it. */
- /* snprintf: a return value of size or more means that the output was truncated */
- /* if an output error is encountered, a negative value is returned. */
- if (((unsigned int)res < sizeof(filename)) && (res > 0)) {
- if (0 == stat(filename, &status)) {
- if ((time_oldest == 0) || (status.st_mtime < time_oldest)) {
- time_oldest = status.st_mtime;
- size_oldest = status.st_size;
- strncpy(filename_oldest, filename, PATH_MAX);
- filename_oldest[PATH_MAX] = 0;
- }
- }
- else {
- printf("Old offline trace file %s cannot be stat-ed", filename);
- }
- }
- }
-
- closedir(dir);
-
- /* delete file */
- if (filename_oldest[0]) {
- if (remove(filename_oldest)) {
- printf("Remove file %s failed!\n", filename_oldest);
- return -1; /* ERROR */
- }
- }
- else {
- printf("No file to be removed!\n");
- return -1; /* ERROR */
- }
-
- /* return size of deleted file*/
- return size_oldest;
-}
-
-DltReturnValue dlt_offline_trace_check_size(DltOfflineTrace *trace)
-{
-
- struct stat status;
-
- /* check for existence of offline trace directory */
- if (stat(trace->directory, &status) == -1) {
- dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't exist \n", trace->directory);
- return DLT_RETURN_ERROR;
- }
-
- /* check for accesibilty of offline trace directory */
- else if (access(trace->directory, W_OK) != 0)
- {
- dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't have the write access \n", trace->directory);
- return DLT_RETURN_ERROR;
- }
-
- ssize_t s = 0;
-
- /* check size of complete offline trace */
- while ((s = dlt_offline_trace_get_total_size(trace)) > (trace->maxSize - trace->fileSize))
- /* remove oldest files as long as new file will not fit in completely into complete offline trace */
- if (dlt_offline_trace_delete_oldest_file(trace) < 0)
- return DLT_RETURN_ERROR;
-
- if (s == -1)
- return DLT_RETURN_ERROR;
-
- return DLT_RETURN_OK; /* OK */
-}
-
-DltReturnValue dlt_offline_trace_init(DltOfflineTrace *trace,
- const char *directory,
- int fileSize,
- int maxSize,
- int filenameTimestampBased)
-{
-
- /* init parameters */
- strncpy(trace->directory, directory, NAME_MAX);
- trace->directory[NAME_MAX] = 0;
- trace->fileSize = fileSize;
- trace->maxSize = maxSize;
- trace->filenameTimestampBased = filenameTimestampBased;
- /* check complete offlien trace size, remove old logs if needed */
- dlt_offline_trace_check_size(trace);
-
- return dlt_offline_trace_create_new_file(trace);
-}
-
-DltReturnValue dlt_offline_trace_write(DltOfflineTrace *trace,
- unsigned char *data1,
- int size1,
- unsigned char *data2,
- int size2,
- unsigned char *data3,
- int size3)
-{
-
- if (trace->ohandle < 0)
- return DLT_RETURN_ERROR;
-
- /* check file size here */
- if ((lseek(trace->ohandle, 0, SEEK_CUR) + size1 + size2 + size3) >= trace->fileSize) {
- /* close old file */
- close(trace->ohandle);
- trace->ohandle = -1;
-
- /* check complete offline trace size, remove old logs if needed */
- dlt_offline_trace_check_size(trace);
-
- /* create new file */
- dlt_offline_trace_create_new_file(trace);
- }
+ multiple_files_buffer_rotate_file(trace, size1 + size2 + size3);
/* write data into log file */
- if (data1 && (trace->ohandle >= 0)) {
- if (write(trace->ohandle, data1, size1) != size1) {
- printf("Offline trace write failed!\n");
- return DLT_RETURN_ERROR;
- }
- }
-
- if (data2 && (trace->ohandle >= 0)) {
- if (write(trace->ohandle, data2, size2) != size2) {
- printf("Offline trace write failed!\n");
- return DLT_RETURN_ERROR;
- }
- }
-
- if (data3 && (trace->ohandle >= 0)) {
- if (write(trace->ohandle, data3, size3) != size3) {
- printf("Offline trace write failed!\n");
- return DLT_RETURN_ERROR;
- }
- }
-
- return DLT_RETURN_OK; /* OK */
-}
-
-DltReturnValue dlt_offline_trace_free(DltOfflineTrace *trace)
-{
-
- if (trace->ohandle < 0)
- return DLT_RETURN_ERROR;
-
- /* close last used log file */
- close(trace->ohandle);
+ if (multiple_files_buffer_write_chunk(trace, data1, size1) != DLT_RETURN_OK) return DLT_RETURN_ERROR;
+ if (multiple_files_buffer_write_chunk(trace, data2, size2) != DLT_RETURN_OK) return DLT_RETURN_ERROR;
+ if (multiple_files_buffer_write_chunk(trace, data3, size3) != DLT_RETURN_OK) return DLT_RETURN_ERROR;
- return DLT_RETURN_OK; /* OK */
+ return DLT_RETURN_OK;
}
diff --git a/src/shared/dlt_user_shared.c b/src/shared/dlt_user_shared.c
index 90b2623..c6bc496 100644
--- a/src/shared/dlt_user_shared.c
+++ b/src/shared/dlt_user_shared.c
@@ -71,6 +71,7 @@
#include <errno.h>
#include <sys/uio.h> /* writev() */
+#include <sys/time.h> /* timeval */
#include "dlt_user_shared.h"
#include "dlt_user_shared_cfg.h"
@@ -125,6 +126,28 @@ DltReturnValue dlt_user_log_out2(int handle, void *ptr1, size_t len1, void *ptr2
return DLT_RETURN_OK;
}
+DltReturnValue dlt_user_log_out2_with_timeout(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2)
+{
+ if (handle < 0)
+ /* Invalid handle */
+ return DLT_RETURN_ERROR;
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(handle, &fds);
+
+ struct timeval tv = { DLT_WRITEV_TIMEOUT_SEC, DLT_WRITEV_TIMEOUT_USEC };
+ if (select(handle+1, NULL, &fds, NULL, &tv) < 0) {
+ return DLT_RETURN_ERROR;
+ }
+
+ if (FD_ISSET(handle, &fds)) {
+ return dlt_user_log_out2(handle, ptr1, len1, ptr2, len2);
+ } else {
+ return DLT_RETURN_ERROR;
+ }
+}
+
DltReturnValue dlt_user_log_out3(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3, size_t len3)
{
struct iovec iov[3];
@@ -175,4 +198,26 @@ DltReturnValue dlt_user_log_out3(int handle, void *ptr1, size_t len1, void *ptr2
}
return DLT_RETURN_OK;
-} \ No newline at end of file
+}
+
+DltReturnValue dlt_user_log_out3_with_timeout(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3, size_t len3)
+{
+ if (handle < 0)
+ /* Invalid handle */
+ return DLT_RETURN_ERROR;
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(handle, &fds);
+
+ struct timeval tv = { DLT_WRITEV_TIMEOUT_SEC, DLT_WRITEV_TIMEOUT_USEC };
+ if (select(handle+1, NULL, &fds, NULL, &tv) < 0) {
+ return DLT_RETURN_ERROR;
+ }
+
+ if (FD_ISSET(handle, &fds)) {
+ return dlt_user_log_out3(handle, ptr1, len1, ptr2, len2, ptr3, len3);
+ } else {
+ return DLT_RETURN_ERROR;
+ }
+}
diff --git a/src/shared/dlt_user_shared.h b/src/shared/dlt_user_shared.h
index 5a82cee..4417894 100644
--- a/src/shared/dlt_user_shared.h
+++ b/src/shared/dlt_user_shared.h
@@ -212,6 +212,17 @@ int dlt_user_check_userheader(DltUserHeader *userheader);
DltReturnValue dlt_user_log_out2(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2);
/**
+ * Atomic write to file descriptor, using vector of 2 elements with a timeout of 1s
+ * @param handle file descriptor
+ * @param ptr1 generic pointer to first segment of data to be written
+ * @param len1 length of first segment of data to be written
+ * @param ptr2 generic pointer to second segment of data to be written
+ * @param len2 length of second segment of data to be written
+ * @return Value from DltReturnValue enum
+ */
+DltReturnValue dlt_user_log_out2_with_timeout(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2);
+
+/**
* Atomic write to file descriptor, using vector of 3 elements
* @param handle file descriptor
* @param ptr1 generic pointer to first segment of data to be written
@@ -224,4 +235,18 @@ DltReturnValue dlt_user_log_out2(int handle, void *ptr1, size_t len1, void *ptr2
*/
DltReturnValue dlt_user_log_out3(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3, size_t len3);
+/**
+ * Atomic write to file descriptor, using vector of 3 elements with a timeout of 1s
+ * @param handle file descriptor
+ * @param ptr1 generic pointer to first segment of data to be written
+ * @param len1 length of first segment of data to be written
+ * @param ptr2 generic pointer to second segment of data to be written
+ * @param len2 length of second segment of data to be written
+ * @param ptr3 generic pointer to third segment of data to be written
+ * @param len3 length of third segment of data to be written
+ * @return Value from DltReturnValue enum
+ */
+DltReturnValue dlt_user_log_out3_with_timeout(int handle, void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3, size_t len3);
+
+
#endif /* DLT_USER_SHARED_H */
diff --git a/src/system/dlt-system-process-handling.c b/src/system/dlt-system-process-handling.c
index 84259cc..9180680 100644
--- a/src/system/dlt-system-process-handling.c
+++ b/src/system/dlt-system-process-handling.c
@@ -312,22 +312,14 @@ void start_dlt_system_processes(DltSystemConfiguration *config)
void dlt_system_signal_handler(int sig)
{
- DLT_LOG(dltsystem, DLT_LOG_DEBUG,
- DLT_STRING("dlt-system-process-handling, signal handler"));
-
switch (sig) {
case SIGHUP:
case SIGTERM:
case SIGINT:
case SIGQUIT:
- DLT_LOG(dltsystem, DLT_LOG_DEBUG,
- DLT_STRING("dlt-system-process-handling, exit, signal: "),
- DLT_INT(sig));
quit = 1;
break;
default:
- DLT_LOG(dltsystem, DLT_LOG_WARN,
- DLT_STRING("dlt-system-process-handling, unknown signal!"));
break;
}
-} \ No newline at end of file
+}
diff --git a/src/system/dlt-system-watchdog.c b/src/system/dlt-system-watchdog.c
index a2b01de..cfb5b76 100644
--- a/src/system/dlt-system-watchdog.c
+++ b/src/system/dlt-system-watchdog.c
@@ -109,8 +109,8 @@ int register_watchdog_fd(struct pollfd *pollfd, int fdcnt)
void watchdog_fd_handler(int fd)
{
- long int timersElapsed = 0;
- int r = read(fd, &timersElapsed, 8); // only needed to reset fd event
+ uint64_t timersElapsed = 0ULL;
+ int r = read(fd, &timersElapsed, 8U); // only needed to reset fd event
if(r < 0)
DLT_LOG(watchdogContext, DLT_LOG_ERROR, DLT_STRING("Could not reset systemd watchdog. Exit with: "),
DLT_STRING(strerror(r)));
@@ -120,4 +120,5 @@ void watchdog_fd_handler(int fd)
DLT_LOG(watchdogContext, DLT_LOG_DEBUG, DLT_STRING("systemd watchdog waited periodic\n"));
}
-#endif \ No newline at end of file
+#endif
+
diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt
index 4586a05..bfd4cd9 100644
--- a/systemd/CMakeLists.txt
+++ b/systemd/CMakeLists.txt
@@ -53,7 +53,7 @@ if(WITH_SYSTEMD)
install(FILES ${PROJECT_BINARY_DIR}/systemd/dlt-example-user.service DESTINATION ${SYSTEMD_CONFIGURATIONS_FILES_DIR} )
endif(WITH_DLT_EXAMPLES)
- if(WITH_DLT_ADAPTOR)
+ if(WITH_DLT_ADAPTOR_UDP OR WITH_DLT_ADAPTOR)
set( DLT_ADAPTOR_UDP_APPID "DUDP" )
set( DLT_ADAPTOR_UDP_CTID "DCTI" )
set( DLT_ADAPTOR_UDP_PORT 4712 )
@@ -61,7 +61,13 @@ if(WITH_SYSTEMD)
message( STATUS "Configured systemd unit file:dlt-adaptor-udp.service" )
message(STATUS "DLT adaptor udp configuration: APPID=${DLT_ADAPTOR_UDP_APPID} CTID=${DLT_ADAPTOR_UDP_CTID} PORT=${DLT_ADAPTOR_UDP_PORT}" )
install(FILES ${PROJECT_BINARY_DIR}/systemd/dlt-adaptor-udp.service DESTINATION ${SYSTEMD_CONFIGURATIONS_FILES_DIR} )
- endif(WITH_DLT_ADAPTOR)
+ endif(WITH_DLT_ADAPTOR_UDP)
+
+ if (WITH_SYSTEMD_SOCKET_ACTIVATION)
+ configure_file(${PROJECT_SOURCE_DIR}/systemd/dlt.socket.cmake ${PROJECT_BINARY_DIR}/systemd/dlt.socket)
+ message( STATUS "Configured systemd socket file:dlt.socket" )
+ install(FILES ${PROJECT_BINARY_DIR}/systemd/dlt.socket DESTINATION ${SYSTEMD_CONFIGURATIONS_FILES_DIR} )
+ endif()
message(STATUS "Unit files will be installed to ${SYSTEMD_CONFIGURATIONS_FILES_DIR} after make install" )
diff --git a/systemd/dlt.socket.cmake b/systemd/dlt.socket.cmake
new file mode 100755
index 0000000..9764c0f
--- /dev/null
+++ b/systemd/dlt.socket.cmake
@@ -0,0 +1,8 @@
+[Socket]
+ListenStream=@DLT_USER_IPC_PATH@/dlt
+FileDescriptorName=@DLT_USER_IPC_PATH@/dlt
+SocketGroup=dlt
+SocketMode=0666
+
+[Install]
+WantedBy=sockets.target \ No newline at end of file
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b3a9339..d627ed2 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -21,8 +21,12 @@ else()
set(LIBRARIES socket)
endif()
+if(WITH_SYSTEMD)
+ set(SYSTEMD_LIBS systemd)
+endif(WITH_SYSTEMD)
+
set(DLT_LIBRARIES dlt ${GTEST_LIBS} ${LIBRARIES})
-set(DLT_DAEMON_LIBRARIES dlt_daemon ${GTEST_LIBS} ${LIBRARIES})
+set(DLT_DAEMON_LIBRARIES dlt_daemon ${GTEST_LIBS} ${LIBRARIES} ${SYSTEMD_LIBS})
set(DLT_CONTROL_LIBRARIES dlt dlt_control_common_lib ${GTEST_LIBS})
#Receiver used for QTs. add_test() is not required
@@ -54,8 +58,8 @@ endforeach()
###################
set(TARGET_LIST gtest_dlt_daemon_gateway
gtest_dlt_daemon_offline_log
- gtest_dlt_daemon_filter
gtest_dlt_daemon_event_handler
+ gtest_dlt_daemon_multiple_files_logging
)
if(WITH_DLT_SHM_ENABLE)
list(APPEND TARGET_LIST gtest_dlt_shm)
@@ -64,9 +68,10 @@ endif()
foreach(target IN LISTS TARGET_LIST)
set(target_SRCS ${target})
add_executable(${target} ${target_SRCS} ${systemd_SRCS})
- target_link_libraries(${target} ${DLT_DAEMON_LIBRARIES})
- if(${target} STREQUAL "gtest_dlt_daemon_event_handler" OR
- ${target} STREQUAL "gtest_dlt_shm")
+ target_link_libraries(${target} ${DLT_DAEMON_LIBRARIES} ${ZLIB_LIBRARY})
+ if(${target} STREQUAL "gtest_dlt_daemon_event_handler"
+ OR ${target} STREQUAL "gtest_dlt_shm"
+ OR ${target} STREQUAL "gtest_dlt_daemon_multiple_files_logging")
add_test(NAME ${target}
COMMAND ${target})
else()
diff --git a/tests/gtest_dlt_common.cpp b/tests/gtest_dlt_common.cpp
index 9a375ce..18830be 100644
--- a/tests/gtest_dlt_common.cpp
+++ b/tests/gtest_dlt_common.cpp
@@ -34,6 +34,8 @@ extern "C"
#include "dlt-daemon_cfg.h"
#include "dlt_user_cfg.h"
#include "dlt_version.h"
+#include "dlt_client.h"
+#include "dlt_protocol.h"
int dlt_buffer_increase_size(DltBuffer *);
int dlt_buffer_minimize_size(DltBuffer *);
@@ -4260,7 +4262,97 @@ TEST(dlt_get_minor_version, nullpointer)
/* End Method:dlt_common::dlt_get_minor_version */
+TEST(dlt_client_parse_get_log_info_resp_text, normal)
+{
+ char input[] = "get_log_info, 07, 02 00 4c 4f 47 00 03 00 54 45 53 54 ff ff 18 00 54 65 73 74 20 43 6f 6e 74 65 78 74 20 66 6f 72 20 4c 6f 67 67 69 6e 67 54 53 31 00 ff ff 1b 00 54 65 73 74 20 43 6f 6e 74 65 78 74 31 20 66 6f 72 20 69 6e 6a 65 63 74 69 6f 6e 54 53 32 00 ff ff 1b 00 54 65 73 74 20 43 6f 6e 74 65 78 74 32 20 66 6f 72 20 69 6e 6a 65 63 74 69 6f 6e 1c 00 54 65 73 74 20 41 70 70 6c 69 63 61 74 69 6f 6e 20 66 6f 72 20 4c 6f 67 67 69 6e 67 53 59 53 00 02 00 4a 4f 55 52 ff ff 0f 00 4a 6f 75 72 6e 61 6c 20 41 64 61 70 74 65 72 4d 47 52 00 ff ff 22 00 43 6f 6e 74 65 78 74 20 6f 66 20 6d 61 69 6e 20 64 6c 74 20 73 79 73 74 65 6d 20 6d 61 6e 61 67 65 72 12 00 44 4c 54 20 53 79 73 74 65 6d 20 4d 61 6e 61 67 65 72 72 65 6d 6f";
+ /* expected output:
+ * APID:LOG- Test Application for Logging
+ * CTID:TEST -1 -1 Test Context for Logging
+ * CTID:TS1- -1 -1 Test Context1 for injection
+ * CTID:TS2- -1 -1 Test Context2 for injection
+ * APID:SYS- DLT System Manager
+ * CTID:JOUR -1 -1 Journal Adapter
+ * CTID:MGR- -1 -1 Context of main dlt system manager
+ */
+
+ DltServiceGetLogInfoResponse * resp = (DltServiceGetLogInfoResponse *)malloc(sizeof(DltServiceGetLogInfoResponse ));
+ DltReturnValue ret = (DltReturnValue) dlt_set_loginfo_parse_service_id(
+ input, &resp->service_id, &resp->status);
+ EXPECT_EQ(DLT_RETURN_OK, ret);
+ EXPECT_EQ(DLT_SERVICE_ID_GET_LOG_INFO, resp->service_id);
+ EXPECT_EQ(GET_LOG_INFO_STATUS_MAX, resp->status);
+
+ ret = dlt_client_parse_get_log_info_resp_text(resp, input);
+ EXPECT_EQ(DLT_RETURN_OK, ret);
+
+ EXPECT_EQ(2,resp->log_info_type.count_app_ids);
+
+ EXPECT_EQ(0, memcmp( "LOG", resp->log_info_type.app_ids[0].app_id,4));
+ EXPECT_EQ(0, strcmp("Test Application for Logging", resp->log_info_type.app_ids[0].app_description));
+ EXPECT_EQ(28, resp->log_info_type.app_ids[0].len_app_description);
+
+ EXPECT_EQ(3, resp->log_info_type.app_ids[0].count_context_ids);
+
+ EXPECT_EQ(0, memcmp( "TEST", resp->log_info_type.app_ids[0].context_id_info[0].context_id,4));
+ EXPECT_EQ(0, strcmp( "Test Context for Logging",resp->log_info_type.app_ids[0].context_id_info[0].context_description ));
+ EXPECT_EQ(24,resp->log_info_type.app_ids[0].context_id_info[0].len_context_description);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[0].log_level);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[0].trace_status);
+
+ EXPECT_EQ(0, memcmp( "TS1", resp->log_info_type.app_ids[0].context_id_info[1].context_id,4));
+ EXPECT_EQ(0, strcmp( "Test Context1 for injection",resp->log_info_type.app_ids[0].context_id_info[1].context_description ));
+ EXPECT_EQ(27,resp->log_info_type.app_ids[0].context_id_info[1].len_context_description);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[1].log_level);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[1].trace_status);
+
+ EXPECT_EQ(0, memcmp( "TS2", resp->log_info_type.app_ids[0].context_id_info[2].context_id,4));
+ EXPECT_EQ(0, strcmp( "Test Context2 for injection",resp->log_info_type.app_ids[0].context_id_info[2].context_description ));
+ EXPECT_EQ(27,resp->log_info_type.app_ids[0].context_id_info[2].len_context_description);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[2].log_level);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[0].context_id_info[2].trace_status);
+
+ EXPECT_EQ(0, memcmp( "SYS", resp->log_info_type.app_ids[1].app_id,4));
+ EXPECT_EQ(0, strcmp("DLT System Manager", resp->log_info_type.app_ids[1].app_description));
+ EXPECT_EQ(18, resp->log_info_type.app_ids[1].len_app_description);
+
+ EXPECT_EQ(2, resp->log_info_type.app_ids[1].count_context_ids);
+ EXPECT_EQ(0, memcmp( "JOUR", resp->log_info_type.app_ids[1].context_id_info[0].context_id,4));
+ EXPECT_EQ(0, strcmp( "Journal Adapter",resp->log_info_type.app_ids[1].context_id_info[0].context_description ));
+ EXPECT_EQ(15,resp->log_info_type.app_ids[1].context_id_info[0].len_context_description);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[1].context_id_info[0].log_level);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[1].context_id_info[0].trace_status);
+
+ EXPECT_EQ(0, memcmp( "MGR", resp->log_info_type.app_ids[1].context_id_info[1].context_id,4));
+ EXPECT_EQ(0, strcmp( "Context of main dlt system manager",resp->log_info_type.app_ids[1].context_id_info[1].context_description ));
+ EXPECT_EQ(34,resp->log_info_type.app_ids[1].context_id_info[1].len_context_description);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[1].context_id_info[1].log_level);
+ EXPECT_EQ(-1,resp->log_info_type.app_ids[1].context_id_info[1].trace_status);
+
+ ret = (DltReturnValue)dlt_client_cleanup_get_log_info(resp);
+ EXPECT_EQ(DLT_RETURN_OK,ret);
+}
+
+TEST(dlt_getloginfo_conv_ascii_to_string, normal)
+{
+ /* NULL-Pointer, expect exeption */
+ char rp_1[] = "72 65 6d 6f";
+ char rp_2[] = "123456789 72 65 6d 6f";
+ int rp_count = 0;
+ char rp_str[] =
+ { 0x72, 0x65, 0x6d, 0x6f, 0x00 };
+ char wp[5];
+
+ dlt_getloginfo_conv_ascii_to_string(rp_1, &rp_count, wp, 4);
+ EXPECT_EQ(0, strcmp(rp_str, wp));
+ EXPECT_EQ(12, rp_count);
+
+ rp_count = 10;
+ dlt_getloginfo_conv_ascii_to_string(rp_2, &rp_count, wp, 4);
+ EXPECT_EQ(0, strcmp(rp_str, wp));
+ EXPECT_EQ(22, rp_count);
+
+}
/*##############################################################################################################################*/
/*##############################################################################################################################*/
diff --git a/tests/gtest_dlt_daemon_gateway.cpp b/tests/gtest_dlt_daemon_gateway.cpp
index 418ed86..02c80a1 100644
--- a/tests/gtest_dlt_daemon_gateway.cpp
+++ b/tests/gtest_dlt_daemon_gateway.cpp
@@ -146,8 +146,6 @@ TEST(t_dlt_gateway_send_control_message, Normal)
TEST(t_dlt_gateway_send_control_message, nullpointer)
{
DltDaemonLocal daemon_local;
- DltFilterConfiguration current;
- daemon_local.pFilter.current = &current;
DltGatewayConnection connections;
DltConnection connections1;
DltReceiver receiver1;
diff --git a/tests/gtest_dlt_daemon_multiple_files_logging.cpp b/tests/gtest_dlt_daemon_multiple_files_logging.cpp
new file mode 100644
index 0000000..05b58f2
--- /dev/null
+++ b/tests/gtest_dlt_daemon_multiple_files_logging.cpp
@@ -0,0 +1,277 @@
+/*
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2011-2015, BMW AG
+ *
+ * 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/.
+ */
+
+/*!
+ * \author
+ * Oleg Tropmann <oleg.tropmann@daimler.com>
+ * Daniel Weber <daniel.w.weber@daimler.com>
+ *
+ * \copyright Copyright © 2022 Daimler TSS GmbH. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file gtest_dlt_daemon_multiple_files_logging.ccpp
+ */
+
+#include <gtest/gtest.h>
+
+int connectServer(void);
+
+extern "C"
+{
+#include "dlt_common.h"
+#include <syslog.h>
+#include <dirent.h>
+#include <string.h>
+}
+
+// publish prototypes
+void configure(const char* path, const char* file_name, bool enable_limit, int file_size, int max_files_size);
+void write_log_message();
+void verify_multiple_files(const char* path, const char* file_name, int file_size, int max_files_size);
+void verify_single_file(const char* path, const char* file_name);
+void verify_in_one_file(const char* path, const char* file_name, const char* log1, const char* log2);
+bool file_contains_strings(const char* abs_file_path, const char* str1, const char* str2);
+int get_file_index(char* file_name);
+int compare_int(const void* a, const void* b);
+
+/**
+ * Configure dlt logging using file size limits.
+ */
+TEST(t_dlt_logging_multiple_files, normal)
+{
+ const char* path = "/tmp";
+ const char* file_name = "dlt.log";
+ const int file_size = 128;
+ const int max_file_size = 512;
+ configure(path, file_name, true, file_size, max_file_size);
+ write_log_message();
+ EXPECT_NO_THROW(dlt_log_free());
+ verify_multiple_files(path, file_name, file_size, max_file_size);
+}
+
+/**
+ * Configure dlt logging using file size limits.
+ * Though, due to an error during initialization dlt logging defaults to one file logging.
+ */
+TEST(t_dlt_logging_one_file_as_fallback, normal)
+{
+ const char* path = "/tmp";
+ const char* file_name = "dltlog";
+ configure(path, file_name, true, 128, 512);
+ write_log_message();
+ EXPECT_NO_THROW(dlt_log_free());
+ verify_single_file(path, file_name);
+}
+
+/**
+ * Configure dlt logging without file size limits resulting in one file logging.
+ */
+TEST(t_dlt_logging_one_file, normal)
+{
+ const char* path = "/tmp";
+ const char* file_name = "dlt.log";
+ configure(path, file_name, false, 128, 512);
+ write_log_message();
+ EXPECT_NO_THROW(dlt_log_free());
+ verify_single_file(path, file_name);
+}
+
+/**
+ * The dlt_daemon calls dlt_log_init multiple times. In the past, so we create
+ * unnecessary two files. The reinit have to append to the first file.
+ */
+TEST(t_dlt_logging_multiple_files_append_reinit, normal)
+{
+ const char* path = "/tmp";
+ const char* file_name = "dlt.log";
+ const int file_size = 256;
+ const int max_file_size = 512;
+
+ const char* log1 = "ONE\n";
+ const char* log2 = "TWO\n";
+
+ configure(path, file_name, true, file_size, max_file_size);
+ dlt_vlog(LOG_INFO, "%s", log1);
+ EXPECT_NO_THROW(dlt_log_free());
+
+ configure(path, file_name, true, file_size, max_file_size);
+ dlt_vlog(LOG_INFO, "%s", log2);
+ EXPECT_NO_THROW(dlt_log_free());
+ verify_in_one_file(path, file_name, log1, log2);
+}
+
+void configure(const char *path, const char* file_name, const bool enable_limit, const int file_size, const int max_files_size)
+{
+ char abs_file_path[PATH_MAX];
+ snprintf(abs_file_path, sizeof(abs_file_path), "%s/%s", path, file_name);
+ printf("debug test: %s\n", abs_file_path);
+
+ EXPECT_NO_THROW(dlt_log_set_filename(abs_file_path));
+ EXPECT_NO_THROW(dlt_log_set_level(6));
+ EXPECT_NO_THROW(dlt_log_init_multiple_logfiles_support(DLT_LOG_TO_FILE, enable_limit, file_size, max_files_size));
+}
+
+void write_log_message()
+{
+ for (unsigned int i = 0; i < 10; i++) {
+ dlt_vlog(LOG_INFO, "%d. Unit test logging into multiple files if configured.\n", i);
+ }
+}
+
+void verify_multiple_files(const char* path, const char* file_name, const int file_size, const int max_files_size)
+{
+ int sum_size = 0;
+ int num_files = 0;
+ int file_indices[100];
+
+ char filename[PATH_MAX + 1];
+ struct dirent *dp;
+ struct stat status;
+
+ char file_name_copy[NAME_MAX];
+ strncpy(file_name_copy, file_name, NAME_MAX);
+ char filename_base[NAME_MAX];
+ EXPECT_TRUE(dlt_extract_base_name_without_ext(file_name_copy, filename_base, sizeof(filename_base)));
+ const char *filename_ext = get_filename_ext(file_name);
+ EXPECT_TRUE(filename_ext);
+
+ DIR *dir = opendir(path);
+ while ((dp = readdir(dir)) != NULL) {
+ if (strstr(dp->d_name, filename_base) &&
+ strstr(dp->d_name, filename_ext)) {
+
+ snprintf(filename, sizeof(filename), "%s/%s", path, dp->d_name);
+
+ if (0 == stat(filename, &status)) {
+ EXPECT_LE(status.st_size, file_size);
+ EXPECT_GE(status.st_size, file_size/2);
+ sum_size += status.st_size;
+ file_indices[num_files++] = get_file_index(filename);
+ } else {
+ EXPECT_TRUE(false);
+ }
+ }
+ }
+
+ EXPECT_LE(sum_size, max_files_size);
+ EXPECT_GT(sum_size, 0);
+ EXPECT_GT(num_files, 0);
+
+ //check that file indices are successive in ascending order
+ qsort(file_indices, num_files, sizeof(int), compare_int);
+ int index = file_indices[0];
+ for (int i=1; i<num_files; i++) {
+ EXPECT_EQ(file_indices[i], ++index);
+ }
+}
+
+void verify_single_file(const char* path, const char* file_name)
+{
+ char abs_file_path[PATH_MAX];
+ snprintf(abs_file_path, sizeof(abs_file_path), "%s/%s", path, file_name);
+
+ struct stat status;
+ if (0 == stat(abs_file_path, &status)) {
+ EXPECT_GT(status.st_size, 0);
+ } else {
+ EXPECT_TRUE(false);
+ }
+}
+
+void verify_in_one_file(const char* path, const char* file_name, const char* log1, const char* log2)
+{
+ char abs_file_path[PATH_MAX + 1];
+ struct dirent *dp;
+
+ char file_name_copy[NAME_MAX];
+ strncpy(file_name_copy, file_name, NAME_MAX);
+ char filename_base[NAME_MAX];
+ EXPECT_TRUE(dlt_extract_base_name_without_ext(file_name_copy, filename_base, sizeof(filename_base)));
+ const char *filename_ext = get_filename_ext(file_name);
+ EXPECT_TRUE(filename_ext);
+
+ bool found = false;
+
+ DIR *dir = opendir(path);
+ while ((dp = readdir(dir)) != NULL) {
+ if (strstr(dp->d_name, filename_base) &&
+ strstr(dp->d_name, filename_ext)) {
+
+ snprintf(abs_file_path, sizeof(abs_file_path), "%s/%s", path, dp->d_name);
+
+ if (file_contains_strings(abs_file_path, log1, log2)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ EXPECT_TRUE(found);
+}
+
+bool file_contains_strings(const char* abs_file_path, const char* str1, const char* str2)
+{
+ bool found = false;
+ FILE *file = fopen(abs_file_path, "r");
+ if (file != nullptr) {
+ fseek (file , 0 , SEEK_END);
+ long size = ftell (file);
+ rewind (file);
+
+ char* buffer = (char*) malloc(size);
+ long read_bytes = fread(buffer, 1, size, file);
+
+ EXPECT_EQ(size, read_bytes);
+
+ if ((strstr(buffer, str1) != nullptr) &&
+ (strstr(buffer, str2) != nullptr)) {
+
+ found = true;
+ }
+
+ fclose(file);
+ free(buffer);
+ }
+ return found;
+}
+
+int get_file_index(char* file_name)
+{
+ char *dot = strrchr(file_name, '.');
+ *dot = '\0';
+
+ //start with the first zero
+ char *iterator = strchr(file_name, '0');
+ do {} while (*(++iterator) == '0');
+ //now iterator points to the first character after 0
+
+ return atoi(iterator);
+}
+
+int compare_int(const void* a, const void* b)
+{
+ if (*((int*)a) == *((int*)b)) return 0;
+ else if (*((int*)a) < *((int*)b)) return -1;
+ else return 1;
+}
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::FLAGS_gtest_break_on_failure = true;
+ /*::testing::FLAGS_gtest_filter = "*.normal"; */
+ /*::testing::FLAGS_gtest_repeat = 10000; */
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/gtest_dlt_daemon_offline_log.cpp b/tests/gtest_dlt_daemon_offline_log.cpp
index 0eb7715..e2ed88c 100644
--- a/tests/gtest_dlt_daemon_offline_log.cpp
+++ b/tests/gtest_dlt_daemon_offline_log.cpp
@@ -175,10 +175,62 @@ TEST(t_dlt_logstorage_read_number, null)
EXPECT_EQ(DLT_RETURN_ERROR, dlt_logstorage_read_number(&number, NULL));
}
+TEST(t_dlt_logstorage_read_boolean, normal)
+{
+ unsigned int val;
+ {
+ char str[] = "0";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(0, val);
+ }
+ {
+ char str[] = "1";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(1, val);
+ }
+ {
+ char str[] = "off";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(0, val);
+ }
+ {
+ char str[] = "on";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(1, val);
+ }
+ {
+ char str[] = "false";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(0, val);
+ }
+ {
+ char str[] = "true";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(1, val);
+ }
+ {
+ char str[] = "invalidvalue";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(0, val);
+ }
+ {
+ char str[] = "not";
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_read_bool(&val, str));
+ EXPECT_EQ(0, val);
+ }
+}
+
+TEST(t_dlt_logstorage_read_boolean, null)
+{
+ unsigned int val;
+ EXPECT_EQ(DLT_RETURN_ERROR, dlt_logstorage_read_bool(&val, NULL));
+}
+
/* Begin Method: dlt_logstorage::t_dlt_logstorage_create_keys*/
TEST(t_dlt_logstorage_create_keys, normal)
{
DltLogStorageFilterConfig data;
+ memset(&data, 0, sizeof(DltLogStorageFilterConfig));
char *keys = NULL;
int num_keys = 0;
char apids[] = "1234";
@@ -235,6 +287,7 @@ TEST(t_dlt_logstorage_validate_filter_name, null)
TEST(t_dlt_logstorage_filter_set_strategy, normal)
{
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
dlt_logstorage_filter_set_strategy(&config, DLT_LOGSTORAGE_SYNC_ON_MSG);
EXPECT_EQ(&dlt_logstorage_prepare_on_msg, config.dlt_logstorage_prepare);
@@ -269,6 +322,7 @@ TEST(t_dlt_logstorage_check_apids, normal)
{
char value[] = "a,b,c,d";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.apids = (char *)calloc (1, sizeof(char));
if (config.apids != NULL) {
@@ -288,6 +342,7 @@ TEST(t_dlt_logstorage_check_ctids, normal)
{
char value[] = "a,b,c,d";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.ctids = (char *)calloc (1, sizeof(char));
if (config.ctids != NULL) {
@@ -307,6 +362,7 @@ TEST(t_dlt_logstorage_check_loglevel, normal)
{
char value[] = "DLT_LOG_FATAL";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_check_loglevel(&config, value));
EXPECT_EQ(1, config.log_level);
@@ -322,6 +378,7 @@ TEST(t_dlt_logstorage_check_filename, normal)
{
char value[] = "file_name";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.file_name = (char *)calloc (1, sizeof(char));
if (config.file_name != NULL) {
@@ -335,6 +392,7 @@ TEST(t_dlt_logstorage_check_filename, abnormal)
{
char value[] = "../file_name";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.file_name = (char *)calloc (1, sizeof(char));
if (config.file_name != NULL) {
@@ -354,6 +412,7 @@ TEST(t_dlt_logstorage_check_filesize, normal)
{
char value[] = "100";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_check_filesize(&config, value));
EXPECT_EQ(100, config.file_size);
@@ -369,6 +428,7 @@ TEST(t_dlt_logstorage_check_nofiles, normal)
{
char value[] = "100";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_check_nofiles(&config, value));
EXPECT_EQ(100, config.num_files);
@@ -384,6 +444,7 @@ TEST(t_dlt_logstorage_check_sync_strategy, normal)
{
char value[] = "ON_MSG";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.sync = 0;
EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_check_sync_strategy(&config, value));
@@ -394,6 +455,7 @@ TEST(t_dlt_logstorage_check_sync_strategy, abnormal)
{
char value[] = "UNKNOWN";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.sync = 0;
EXPECT_EQ(DLT_RETURN_TRUE, dlt_logstorage_check_sync_strategy(&config, value));
@@ -410,6 +472,7 @@ TEST(t_dlt_logstorage_check_ecuid, normal)
{
char value[] = "213";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
config.ecuid = (char *)calloc (1, sizeof(char));
if (config.ecuid != NULL) {
@@ -432,6 +495,7 @@ TEST(t_dlt_logstorage_check_param, normal)
{
char value[] = "100";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_check_param(&config, DLT_LOGSTORAGE_FILTER_CONF_FILESIZE, value));
EXPECT_EQ(100, config.file_size);
@@ -560,6 +624,7 @@ TEST(t_dlt_logstorage_get_config, normal)
char file_name[] = "file_name";
int num_config = 0;
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.log_level = 0;
value.apids = apid;
value.ctids = ctid;
@@ -601,6 +666,7 @@ TEST(t_dlt_logstorage_filter, normal)
char filename[] = "file_name";
int num = 1;
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.apids = apid;
value.ctids = ctid;
value.ecuid = ecuid;
@@ -653,6 +719,7 @@ TEST(t_dlt_logstorage_write, normal)
handle.config_list = NULL;
handle.newest_file_list = NULL;
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.apids = apid;
value.ctids = ctid;
value.ecuid = ecuid;
@@ -685,6 +752,7 @@ TEST(t_dlt_logstorage_sync_caches, normal)
handle.num_configs = 1;
handle.config_list = NULL;
DltLogStorageFilterConfig configs;
+ memset(&configs, 0, sizeof(DltLogStorageFilterConfig));
configs.apids = apid;
configs.ctids = ctid;
configs.ecuid = ecuid;
@@ -708,7 +776,12 @@ TEST(t_dlt_logstorage_log_file_name, normal)
file_config.logfile_counteridxlen = 10;
int cmpRes = 0;
char name[] = "log";
- dlt_logstorage_log_file_name(log_file_name, &file_config, name, 0);
+
+ DltLogStorageFilterConfig filter_config;
+ memset(&filter_config, 0, sizeof(filter_config));
+ filter_config.file_name = &name[0];
+
+ dlt_logstorage_log_file_name(log_file_name, &file_config, &filter_config, 0);
cmpRes = strncmp(log_file_name, "log/0000000000", 14);
EXPECT_EQ(0, cmpRes);
@@ -716,8 +789,7 @@ TEST(t_dlt_logstorage_log_file_name, normal)
TEST(t_dlt_logstorage_log_file_name, null)
{
- char name[] = "log";
- dlt_logstorage_log_file_name(NULL, NULL, name, 0);
+ dlt_logstorage_log_file_name(NULL, NULL, NULL, 0);
}
/* Begin Method: dlt_logstorage::t_dlt_logstorage_sort_file_name*/
@@ -878,13 +950,23 @@ TEST(t_dlt_logstorage_get_idx_of_log_file, normal)
file_config.logfile_delimiter = { '_' };
file_config.logfile_maxcounter = 2;
file_config.logfile_counteridxlen = 2;
+ char name[] = "Test";
char *file = (char *)"Test_002_20160509_191132.dlt";
- EXPECT_EQ(2, dlt_logstorage_get_idx_of_log_file(&file_config, file));
+ DltLogStorageFilterConfig filter_config;
+ memset(&filter_config, 0, sizeof(filter_config));
+ filter_config.file_name = &name[0];
+
+ EXPECT_EQ(2, dlt_logstorage_get_idx_of_log_file(&file_config, &filter_config, file));
+
+ char *gz_file = (char *)"Test_142_20160509_191132.dlt.gz";
+ filter_config.gzip_compression = 1;
+
+ EXPECT_EQ(142, dlt_logstorage_get_idx_of_log_file(&file_config, &filter_config, gz_file));
}
TEST(t_dlt_logstorage_get_idx_of_log_file, null)
{
- EXPECT_EQ(DLT_RETURN_ERROR, dlt_logstorage_get_idx_of_log_file(NULL, NULL));
+ EXPECT_EQ(DLT_RETURN_ERROR, dlt_logstorage_get_idx_of_log_file(NULL, NULL, NULL));
}
/* Begin Method: dlt_logstorage::t_dlt_logstorage_storage_dir_info*/
@@ -897,6 +979,7 @@ TEST(t_dlt_logstorage_storage_dir_info, normal)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -921,6 +1004,7 @@ TEST(t_dlt_logstorage_open_log_file, normal)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -947,6 +1031,7 @@ TEST(t_dlt_logstorage_prepare_on_msg, normal1)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -975,6 +1060,7 @@ TEST(t_dlt_logstorage_prepare_on_msg, normal2)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -1016,6 +1102,7 @@ TEST(t_dlt_logstorage_prepare_on_msg, normal3)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
char *working_file_name = (char *)"Test_002_20160509_191132.dlt";
@@ -1064,6 +1151,7 @@ TEST(t_dlt_logstorage_write_on_msg, normal)
file_config.logfile_counteridxlen = 2;
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -1073,6 +1161,7 @@ TEST(t_dlt_logstorage_write_on_msg, normal)
config.log = NULL;
config.working_file_name = NULL;
config.wrap_id = 0;
+ config.gzip_compression = 0;
unsigned int size = 8;
unsigned char data1[] = "dlt_data";
unsigned char data2[] = "dlt_data";
@@ -1089,6 +1178,42 @@ TEST(t_dlt_logstorage_write_on_msg, normal)
data1, size, data2, size, data3, size));
}
+TEST(t_dlt_logstorage_write_on_msg, gzip)
+{
+ DltLogStorageUserConfig file_config;
+ file_config.logfile_timestamp = 191132;
+ file_config.logfile_delimiter = { '_' };
+ file_config.logfile_maxcounter = 2;
+ file_config.logfile_counteridxlen = 2;
+ char *path = (char *)"/tmp";
+ DltLogStorageFilterConfig config;
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
+ char apids;
+ char ctids;
+ config.apids = &apids;
+ config.ctids = &ctids;
+ config.file_name = (char *)"Test";
+ config.records = NULL;
+ config.log = NULL;
+ config.working_file_name = NULL;
+ config.wrap_id = 0;
+ config.gzip_compression = 1;
+ unsigned int size = 8;
+ unsigned char data1[] = "dlt_data";
+ unsigned char data2[] = "dlt_data";
+ unsigned char data3[] = "dlt_data";
+
+ DltNewestFileName newest_file_name;
+ newest_file_name.file_name = (char *)"Test";
+ newest_file_name.newest_file = (char *)"Test_003_20200728_191132.dlt.gz";
+ newest_file_name.wrap_id = 0;
+ newest_file_name.next = NULL;
+
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_prepare_on_msg(&config, &file_config, path, 1, &newest_file_name));
+ EXPECT_EQ(DLT_RETURN_OK, dlt_logstorage_write_on_msg(&config, &file_config, path,
+ data1, size, data2, size, data3, size));
+}
+
TEST(t_dlt_logstorage_write_on_msg, null)
{
EXPECT_EQ(DLT_RETURN_ERROR, dlt_logstorage_write_on_msg(NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, 0));
@@ -1130,6 +1255,8 @@ TEST(t_dlt_logstorage_prepare_msg_cache, normal)
char *path = (char *)"/tmp";
DltLogStorageFilterConfig config;
DltNewestFileName newest_info;
+ memset(&newest_info, 0, sizeof(DltNewestFileName));
+ memset(&config, 0, sizeof(DltLogStorageFilterConfig));
char apids;
char ctids;
config.apids = &apids;
@@ -1374,6 +1501,7 @@ TEST(t_dlt_daemon_logstorage_get_loglevel, normal)
memset(&daemon_local, 0, sizeof(DltDaemonLocal));
memset(&daemon_local.pGateway, 0, sizeof(DltGateway));
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.log_level = 4;
value.apids = apid;
value.ctids = ctid;
@@ -1427,6 +1555,7 @@ TEST(t_dlt_daemon_logstorage_update_application_loglevel, normal)
memset(&daemon_local, 0, sizeof(DltDaemonLocal));
memset(&daemon_local.pGateway, 0, sizeof(DltGateway));
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.log_level = 5;
value.apids = apid;
value.ctids = ctid;
@@ -1499,6 +1628,7 @@ TEST(t_dlt_daemon_logstorage_write, normal)
daemon.storage_handle->config_status = DLT_OFFLINE_LOGSTORAGE_CONFIG_DONE;
daemon.storage_handle->config_list = NULL;
DltLogStorageFilterConfig value;
+ memset(&value, 0, sizeof(DltLogStorageFilterConfig));
value.apids = apid;
value.ctids = ctid;
value.ecuid = ecuid;
@@ -1598,6 +1728,7 @@ TEST(t_dlt_daemon_logstorage_sync_cache, normal)
daemon.storage_handle->config_list = NULL;
strncpy(daemon.storage_handle->device_mount_point, "/tmp", 5);
DltLogStorageFilterConfig configs;
+ memset(&configs, 0, sizeof(DltLogStorageFilterConfig));
configs.apids = apid;
configs.ctids = ctid;
configs.ecuid = ecuid;
diff --git a/tests/gtest_dlt_user.cpp b/tests/gtest_dlt_user.cpp
index cc7851a..aa8b28e 100644
--- a/tests/gtest_dlt_user.cpp
+++ b/tests/gtest_dlt_user.cpp
@@ -30,6 +30,7 @@
#include <string.h>
#include <stdint.h>
#include <float.h>
+#include <chrono>
extern "C" {
#include "dlt_user.h"
@@ -5249,6 +5250,92 @@ TEST(t_dlt_user_is_logLevel_enabled, nullpointer)
}
/*/////////////////////////////////////// */
+/* t_dlt_user_shutdown_while_init_is_running */
+
+struct ShutdownWhileInitParams {
+ ShutdownWhileInitParams() = default;
+ // delete copy constructor
+ ShutdownWhileInitParams(const ShutdownWhileInitParams&) = delete;
+
+ std::chrono::time_point<std::chrono::steady_clock> stop_time;
+
+ pthread_cond_t dlt_free_done = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t dlt_free_mtx = PTHREAD_MUTEX_INITIALIZER;
+ bool has_error = false;
+
+};
+
+void* dlt_free_call_and_deadlock_detection(void *arg) {
+ auto *params = static_cast<ShutdownWhileInitParams *>(arg);
+
+ // allow thread to be canceled
+ int old_thread_type;
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_thread_type);
+
+ dlt_free();
+
+ // signal that we are done
+ pthread_mutex_lock(&params->dlt_free_mtx);
+ pthread_cond_signal(&params->dlt_free_done);
+ pthread_mutex_unlock(&params->dlt_free_mtx);
+ return nullptr;
+}
+
+void *dlt_free_thread(void *arg) {
+ auto *params = static_cast<ShutdownWhileInitParams *>(arg);
+ while (std::chrono::steady_clock::now() < params->stop_time && !params->has_error) {
+
+ // pthread cond_timedwait expects an absolute time to wait
+ struct timespec abs_time{};
+ clock_gettime(CLOCK_REALTIME, &abs_time);
+ abs_time.tv_sec += 3; // wait at most 3 seconds
+
+ pthread_t dlt_free_deadlock_detection_thread_id;
+
+ pthread_mutex_lock(&params->dlt_free_mtx);
+ pthread_create(&dlt_free_deadlock_detection_thread_id, nullptr, dlt_free_call_and_deadlock_detection, params);
+ const auto err = pthread_cond_timedwait(&params->dlt_free_done, &params->dlt_free_mtx, &abs_time);
+ pthread_mutex_unlock(&params->dlt_free_mtx);
+
+ if (err == ETIMEDOUT) {
+ fprintf(stderr, "\n%s: detected DLT-deadlock!\n", __func__);
+ params->has_error = true;
+
+ // cancel thread after timeout, so join won't block forever.
+ pthread_cancel(dlt_free_deadlock_detection_thread_id);
+ }
+
+ pthread_join(dlt_free_deadlock_detection_thread_id, nullptr);
+ }
+
+ return nullptr;
+}
+
+TEST(t_dlt_user_shutdown_while_init_is_running, normal) {
+ const auto max_runtime = std::chrono::seconds(15);
+ const auto stop_time = std::chrono::steady_clock::now() + max_runtime;
+
+ struct ShutdownWhileInitParams args{};
+ args.stop_time = stop_time;
+
+ pthread_t dlt_free_thread_id;
+ pthread_create(&dlt_free_thread_id, nullptr, dlt_free_thread, &args);
+
+ while (std::chrono::steady_clock::now() < stop_time && !args.has_error) {
+ dlt_init();
+ }
+
+ pthread_join(dlt_free_thread_id, nullptr);
+ EXPECT_FALSE(args.has_error);
+
+ const auto last_init = dlt_init();
+ const auto last_free = dlt_free();
+
+ EXPECT_EQ(last_init, DLT_RETURN_OK);
+ EXPECT_EQ(last_free, DLT_RETURN_OK);
+}
+
+/*/////////////////////////////////////// */
/* main */
int main(int argc, char **argv)
{
diff --git a/uncrustify.cfg b/uncrustify.cfg
deleted file mode 100644
index faec3ae..0000000
--- a/uncrustify.cfg
+++ /dev/null
@@ -1,2736 +0,0 @@
-# Uncrustify-0.68_f
-
-#
-# General options
-#
-
-# The type of line endings.
-#
-# Default: auto
-newlines = auto # lf/crlf/cr/auto
-
-# The original size of tabs in the input.
-#
-# Default: 8
-input_tab_size = 4 # unsigned number
-
-# The size of tabs in the output (only used if align_with_tabs=true).
-#
-# Default: 8
-output_tab_size = 4 # unsigned number
-
-# The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^).
-#
-# Default: 92
-string_escape_char = 92 # unsigned number
-
-# Alternate string escape char (usually only used for Pawn).
-# Only works right before the quote char.
-string_escape_char2 = 0 # unsigned number
-
-# Replace tab characters found in string literals with the escape sequence \t
-# instead.
-string_replace_tab_chars = false # true/false
-
-# Allow interpreting '>=' and '>>=' as part of a template in code like
-# 'void f(list<list<B>>=val);'. If true, 'assert(x<0 && y>=3)' will be broken.
-# Improvements to template detection may make this option obsolete.
-tok_split_gte = false # true/false
-
-# Specify the marker used in comments to disable processing of part of the
-# file.
-#
-# Default: *INDENT-OFF*
-disable_processing_cmt = "" # string
-
-# Specify the marker used in comments to (re)enable processing in a file.
-#
-# Default: *INDENT-ON*
-enable_processing_cmt = "" # string
-
-# Enable parsing of digraphs.
-enable_digraphs = false # true/false
-
-# Add or remove the UTF-8 BOM (recommend 'remove').
-utf8_bom = ignore # ignore/add/remove/force
-
-# If the file contains bytes with values between 128 and 255, but is not
-# UTF-8, then output as UTF-8.
-utf8_byte = false # true/false
-
-# Force the output encoding to UTF-8.
-utf8_force = false # true/false
-
-#
-# Spacing options
-#
-
-# Add or remove space around non-assignment symbolic operators ('+', '/', '%',
-# '<<', and so forth).
-sp_arith = force # ignore/add/remove/force
-
-# Add or remove space around arithmetic operators '+' and '-'.
-#
-# Overrides sp_arith.
-sp_arith_additive = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment operator '=', '+=', etc.
-sp_assign = force # ignore/add/remove/force
-
-# Add or remove space around '=' in C++11 lambda capture specifications.
-#
-# Overrides sp_assign.
-sp_cpp_lambda_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after the capture specification in C++11 lambda.
-sp_cpp_lambda_paren = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment operator '=' in a prototype.
-sp_assign_default = ignore # ignore/add/remove/force
-
-# Add or remove space before assignment operator '=', '+=', etc.
-#
-# Overrides sp_assign.
-sp_before_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after assignment operator '=', '+=', etc.
-#
-# Overrides sp_assign.
-sp_after_assign = ignore # ignore/add/remove/force
-
-# Add or remove space in 'NS_ENUM ('.
-sp_enum_paren = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment '=' in enum.
-sp_enum_assign = force # ignore/add/remove/force
-
-# Add or remove space before assignment '=' in enum.
-#
-# Overrides sp_enum_assign.
-sp_enum_before_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after assignment '=' in enum.
-#
-# Overrides sp_enum_assign.
-sp_enum_after_assign = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment ':' in enum.
-sp_enum_colon = ignore # ignore/add/remove/force
-
-# Add or remove space around preprocessor '##' concatenation operator.
-#
-# Default: add
-sp_pp_concat = ignore # ignore/add/remove/force
-
-# Add or remove space after preprocessor '#' stringify operator.
-# Also affects the '#@' charizing operator.
-sp_pp_stringify = ignore # ignore/add/remove/force
-
-# Add or remove space before preprocessor '#' stringify operator
-# as in '#define x(y) L#y'.
-sp_before_pp_stringify = ignore # ignore/add/remove/force
-
-# Add or remove space around boolean operators '&&' and '||'.
-sp_bool = force # ignore/add/remove/force
-
-# Add or remove space around compare operator '<', '>', '==', etc.
-sp_compare = force # ignore/add/remove/force
-
-# Add or remove space inside '(' and ')'.
-sp_inside_paren = remove # ignore/add/remove/force
-
-# Add or remove space between nested parentheses, i.e. '((' vs. ') )'.
-sp_paren_paren = remove # ignore/add/remove/force
-
-# Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('.
-sp_cparen_oparen = ignore # ignore/add/remove/force
-
-# Whether to balance spaces inside nested parentheses.
-sp_balance_nested_parens = false # true/false
-
-# Add or remove space between ')' and '{'.
-sp_paren_brace = force # ignore/add/remove/force
-
-# Add or remove space between nested braces, i.e. '{{' vs '{ {'.
-sp_brace_brace = ignore # ignore/add/remove/force
-
-# Add or remove space before pointer star '*'.
-sp_before_ptr_star = force # ignore/add/remove/force
-
-# Add or remove space before pointer star '*' that isn't followed by a
-# variable name. If set to 'ignore', sp_before_ptr_star is used instead.
-sp_before_unnamed_ptr_star = force # ignore/add/remove/force
-
-# Add or remove space between pointer stars '*'.
-sp_between_ptr_star = remove # ignore/add/remove/force
-
-# Add or remove space after pointer star '*', if followed by a word.
-sp_after_ptr_star = remove # ignore/add/remove/force
-
-# Add or remove space after pointer caret '^', if followed by a word.
-sp_after_ptr_block_caret = ignore # ignore/add/remove/force
-
-# Add or remove space after pointer star '*', if followed by a qualifier.
-sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force
-
-# Add or remove space after a pointer star '*', if followed by a function
-# prototype or function definition.
-sp_after_ptr_star_func = remove # ignore/add/remove/force
-
-# Add or remove space after a pointer star '*', if followed by an open
-# parenthesis, as in 'void* (*)().
-sp_ptr_star_paren = ignore # ignore/add/remove/force
-
-# Add or remove space before a pointer star '*', if followed by a function
-# prototype or function definition.
-sp_before_ptr_star_func = add # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&'.
-sp_before_byref = add # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&' that isn't followed by a
-# variable name. If set to 'ignore', sp_before_byref is used instead.
-sp_before_unnamed_byref = add # ignore/add/remove/force
-
-# Add or remove space after reference sign '&', if followed by a word.
-sp_after_byref = remove # ignore/add/remove/force
-
-# Add or remove space after a reference sign '&', if followed by a function
-# prototype or function definition.
-sp_after_byref_func = remove # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&', if followed by a function
-# prototype or function definition.
-sp_before_byref_func = add # ignore/add/remove/force
-
-# Add or remove space between type and word.
-#
-# Default: force
-sp_after_type = force # ignore/add/remove/force
-
-# Add or remove space between 'decltype(...)' and word.
-sp_after_decltype = ignore # ignore/add/remove/force
-
-# (D) Add or remove space before the parenthesis in the D constructs
-# 'template Foo(' and 'class Foo('.
-sp_before_template_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'template' and '<'.
-# If set to ignore, sp_before_angle is used.
-sp_template_angle = ignore # ignore/add/remove/force
-
-# Add or remove space before '<'.
-sp_before_angle = ignore # ignore/add/remove/force
-
-# Add or remove space inside '<' and '>'.
-sp_inside_angle = ignore # ignore/add/remove/force
-
-# Add or remove space between '>' and ':'.
-sp_angle_colon = ignore # ignore/add/remove/force
-
-# Add or remove space after '<>'.
-sp_after_angle = ignore # ignore/add/remove/force
-
-# Add or remove space between '>' and '(' as found in 'new List<byte>(foo);'.
-sp_angle_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between '>' and '()' as found in 'new List<byte>();'.
-sp_angle_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space between '>' and a word as in 'List<byte> m;' or
-# 'template <typename T> static ...'.
-sp_angle_word = ignore # ignore/add/remove/force
-
-# Add or remove space between '>' and '>' in '>>' (template stuff).
-#
-# Default: add
-sp_angle_shift = add # ignore/add/remove/force
-
-# (C++11) Permit removal of the space between '>>' in 'foo<bar<int> >'. Note
-# that sp_angle_shift cannot remove the space without this option.
-sp_permit_cpp11_shift = false # true/false
-
-# Add or remove space before '(' of control statements ('if', 'for', 'switch',
-# 'while', etc.).
-sp_before_sparen = force # ignore/add/remove/force
-
-# Add or remove space inside '(' and ')' of control statements.
-sp_inside_sparen = remove # ignore/add/remove/force
-
-# Add or remove space after '(' of control statements.
-#
-# Overrides sp_inside_sparen.
-sp_inside_sparen_open = ignore # ignore/add/remove/force
-
-# Add or remove space before ')' of control statements.
-#
-# Overrides sp_inside_sparen.
-sp_inside_sparen_close = ignore # ignore/add/remove/force
-
-# Add or remove space after ')' of control statements.
-sp_after_sparen = force # ignore/add/remove/force
-
-# Add or remove space between ')' and '{' of of control statements.
-sp_sparen_brace = force # ignore/add/remove/force
-
-# (D) Add or remove space between 'invariant' and '('.
-sp_invariant_paren = ignore # ignore/add/remove/force
-
-# (D) Add or remove space after the ')' in 'invariant (C) c'.
-sp_after_invariant_paren = ignore # ignore/add/remove/force
-
-# Add or remove space before empty statement ';' on 'if', 'for' and 'while'.
-sp_special_semi = remove # ignore/add/remove/force
-
-# Add or remove space before ';'.
-#
-# Default: remove
-sp_before_semi = remove # ignore/add/remove/force
-
-# Add or remove space before ';' in non-empty 'for' statements.
-sp_before_semi_for = remove # ignore/add/remove/force
-
-# Add or remove space before a semicolon of an empty part of a for statement.
-sp_before_semi_for_empty = ignore # ignore/add/remove/force
-
-# Add or remove space after ';', except when followed by a comment.
-#
-# Default: add
-sp_after_semi = add # ignore/add/remove/force
-
-# Add or remove space after ';' in non-empty 'for' statements.
-#
-# Default: force
-sp_after_semi_for = force # ignore/add/remove/force
-
-# Add or remove space after the final semicolon of an empty part of a for
-# statement, as in 'for ( ; ; <here> )'.
-sp_after_semi_for_empty = ignore # ignore/add/remove/force
-
-# Add or remove space before '[' (except '[]').
-sp_before_square = ignore # ignore/add/remove/force
-
-# Add or remove space before '[]'.
-sp_before_squares = remove # ignore/add/remove/force
-
-# Add or remove space before C++17 structured bindings.
-sp_cpp_before_struct_binding = ignore # ignore/add/remove/force
-
-# Add or remove space inside a non-empty '[' and ']'.
-sp_inside_square = remove # ignore/add/remove/force
-
-# (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and
-# ']'. If set to ignore, sp_inside_square is used.
-sp_inside_square_oc_array = ignore # ignore/add/remove/force
-
-# Add or remove space after ',', i.e. 'a,b' vs. 'a, b'.
-sp_after_comma = force # ignore/add/remove/force
-
-# Add or remove space before ','.
-#
-# Default: remove
-sp_before_comma = remove # ignore/add/remove/force
-
-# (C#) Add or remove space between ',' and ']' in multidimensional array type
-# like 'int[,,]'.
-sp_after_mdatype_commas = ignore # ignore/add/remove/force
-
-# (C#) Add or remove space between '[' and ',' in multidimensional array type
-# like 'int[,,]'.
-sp_before_mdatype_commas = ignore # ignore/add/remove/force
-
-# (C#) Add or remove space between ',' in multidimensional array type
-# like 'int[,,]'.
-sp_between_mdatype_commas = ignore # ignore/add/remove/force
-
-# Add or remove space between an open parenthesis and comma,
-# i.e. '(,' vs. '( ,'.
-#
-# Default: force
-sp_paren_comma = force # ignore/add/remove/force
-
-# Add or remove space before the variadic '...' when preceded by a
-# non-punctuator.
-sp_before_ellipsis = ignore # ignore/add/remove/force
-
-# Add or remove space between a type and '...'.
-sp_type_ellipsis = ignore # ignore/add/remove/force
-
-# Add or remove space between ')' and '...'.
-sp_paren_ellipsis = ignore # ignore/add/remove/force
-
-# Add or remove space after class ':'.
-sp_after_class_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before class ':'.
-sp_before_class_colon = ignore # ignore/add/remove/force
-
-# Add or remove space after class constructor ':'.
-sp_after_constr_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before class constructor ':'.
-sp_before_constr_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before case ':'.
-#
-# Default: remove
-sp_before_case_colon = remove # ignore/add/remove/force
-
-# Add or remove space between 'operator' and operator sign.
-sp_after_operator = ignore # ignore/add/remove/force
-
-# Add or remove space between the operator symbol and the open parenthesis, as
-# in 'operator ++('.
-sp_after_operator_sym = ignore # ignore/add/remove/force
-
-# Overrides sp_after_operator_sym when the operator has no arguments, as in
-# 'operator *()'.
-sp_after_operator_sym_empty = ignore # ignore/add/remove/force
-
-# Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or
-# '(int)a' vs. '(int) a'.
-sp_after_cast = remove # ignore/add/remove/force
-
-# Add or remove spaces inside cast parentheses.
-sp_inside_paren_cast = remove # ignore/add/remove/force
-
-# Add or remove space between the type and open parenthesis in a C++ cast,
-# i.e. 'int(exp)' vs. 'int (exp)'.
-sp_cpp_cast_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'sizeof' and '('.
-sp_sizeof_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'sizeof' and '...'.
-sp_sizeof_ellipsis = ignore # ignore/add/remove/force
-
-# Add or remove space between 'sizeof...' and '('.
-sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'decltype' and '('.
-sp_decltype_paren = ignore # ignore/add/remove/force
-
-# (Pawn) Add or remove space after the tag keyword.
-sp_after_tag = ignore # ignore/add/remove/force
-
-# Add or remove space inside enum '{' and '}'.
-sp_inside_braces_enum = ignore # ignore/add/remove/force
-
-# Add or remove space inside struct/union '{' and '}'.
-sp_inside_braces_struct = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}'
-sp_inside_braces_oc_dict = ignore # ignore/add/remove/force
-
-# Add or remove space after open brace in an unnamed temporary
-# direct-list-initialization.
-sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force
-
-# Add or remove space before close brace in an unnamed temporary
-# direct-list-initialization.
-sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force
-
-# Add or remove space inside an unnamed temporary direct-list-initialization.
-sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force
-
-# Add or remove space inside '{' and '}'.
-sp_inside_braces = remove # ignore/add/remove/force
-
-# Add or remove space inside '{}'.
-sp_inside_braces_empty = remove # ignore/add/remove/force
-
-# Add or remove space between return type and function name. A minimum of 1
-# is forced except for pointer return types.
-sp_type_func = ignore # ignore/add/remove/force
-
-# Add or remove space between type and open brace of an unnamed temporary
-# direct-list-initialization.
-sp_type_brace_init_lst = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function declaration.
-sp_func_proto_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '()' on function declaration
-# without parameters.
-sp_func_proto_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function definition.
-sp_func_def_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '()' on function definition
-# without parameters.
-sp_func_def_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space inside empty function '()'.
-sp_inside_fparens = remove # ignore/add/remove/force
-
-# Add or remove space inside function '(' and ')'.
-sp_inside_fparen = remove # ignore/add/remove/force
-
-# Add or remove space inside the first parentheses in a function type, as in
-# 'void (*x)(...)'.
-sp_inside_tparen = ignore # ignore/add/remove/force
-
-# Add or remove space between the ')' and '(' in a function type, as in
-# 'void (*x)(...)'.
-sp_after_tparen_close = ignore # ignore/add/remove/force
-
-# Add or remove space between ']' and '(' when part of a function call.
-sp_square_fparen = ignore # ignore/add/remove/force
-
-# Add or remove space between ')' and '{' of function.
-sp_fparen_brace = force # ignore/add/remove/force
-
-# Add or remove space between ')' and '{' of s function call in object
-# initialization.
-#
-# Overrides sp_fparen_brace.
-sp_fparen_brace_initializer = ignore # ignore/add/remove/force
-
-# (Java) Add or remove space between ')' and '{{' of double brace initializer.
-sp_fparen_dbrace = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function calls.
-sp_func_call_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between function name and '()' on function calls without
-# parameters. If set to 'ignore' (the default), sp_func_call_paren is used.
-sp_func_call_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space between the user function name and '(' on function
-# calls. You need to set a keyword to be a user function in the config file,
-# like:
-# set func_call_user tr _ i18n
-sp_func_call_user_paren = ignore # ignore/add/remove/force
-
-# Add or remove space inside user function '(' and ')'.
-sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force
-
-# Add or remove space between nested parentheses with user functions,
-# i.e. '((' vs. '( ('.
-sp_func_call_user_paren_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between a constructor/destructor and the open
-# parenthesis.
-sp_func_class_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between a constructor without parameters or destructor
-# and '()'.
-sp_func_class_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space between 'return' and '('.
-sp_return_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'return' and '{'.
-sp_return_brace = ignore # ignore/add/remove/force
-
-# Add or remove space between '__attribute__' and '('.
-sp_attribute_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'defined' and '(' in '#if defined (FOO)'.
-sp_defined_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'throw' and '(' in 'throw (something)'.
-sp_throw_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'throw' and anything other than '(' as in
-# '@throw [...];'.
-sp_after_throw = ignore # ignore/add/remove/force
-
-# Add or remove space between 'catch' and '(' in 'catch (something) { }'.
-# If set to ignore, sp_before_sparen is used.
-sp_catch_paren = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space between '@catch' and '('
-# in '@catch (something) { }'. If set to ignore, sp_catch_paren is used.
-sp_oc_catch_paren = ignore # ignore/add/remove/force
-
-# (D) Add or remove space between 'version' and '('
-# in 'version (something) { }'. If set to ignore, sp_before_sparen is used.
-sp_version_paren = ignore # ignore/add/remove/force
-
-# (D) Add or remove space between 'scope' and '('
-# in 'scope (something) { }'. If set to ignore, sp_before_sparen is used.
-sp_scope_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'super' and '(' in 'super (something)'.
-#
-# Default: remove
-sp_super_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'this' and '(' in 'this (something)'.
-#
-# Default: remove
-sp_this_paren = remove # ignore/add/remove/force
-
-# Add or remove space between a macro name and its definition.
-sp_macro = ignore # ignore/add/remove/force
-
-# Add or remove space between a macro function ')' and its definition.
-sp_macro_func = ignore # ignore/add/remove/force
-
-# Add or remove space between 'else' and '{' if on the same line.
-sp_else_brace = force # ignore/add/remove/force
-
-# Add or remove space between '}' and 'else' if on the same line.
-sp_brace_else = force # ignore/add/remove/force
-
-# Add or remove space between '}' and the name of a typedef on the same line.
-sp_brace_typedef = force # ignore/add/remove/force
-
-# Add or remove space before the '{' of a 'catch' statement, if the '{' and
-# 'catch' are on the same line, as in 'catch (decl) <here> {'.
-sp_catch_brace = force # ignore/add/remove/force
-
-# (OC) Add or remove space before the '{' of a '@catch' statement, if the '{'
-# and '@catch' are on the same line, as in '@catch (decl) <here> {'.
-# If set to ignore, sp_catch_brace is used.
-sp_oc_catch_brace = ignore # ignore/add/remove/force
-
-# Add or remove space between '}' and 'catch' if on the same line.
-sp_brace_catch = force # ignore/add/remove/force
-
-# (OC) Add or remove space between '}' and '@catch' if on the same line.
-# If set to ignore, sp_brace_catch is used.
-sp_oc_brace_catch = ignore # ignore/add/remove/force
-
-# Add or remove space between 'finally' and '{' if on the same line.
-sp_finally_brace = ignore # ignore/add/remove/force
-
-# Add or remove space between '}' and 'finally' if on the same line.
-sp_brace_finally = ignore # ignore/add/remove/force
-
-# Add or remove space between 'try' and '{' if on the same line.
-sp_try_brace = ignore # ignore/add/remove/force
-
-# Add or remove space between get/set and '{' if on the same line.
-sp_getset_brace = ignore # ignore/add/remove/force
-
-# Add or remove space between a variable and '{' for C++ uniform
-# initialization.
-#
-# Default: add
-sp_word_brace = add # ignore/add/remove/force
-
-# Add or remove space between a variable and '{' for a namespace.
-#
-# Default: add
-sp_word_brace_ns = add # ignore/add/remove/force
-
-# Add or remove space before the '::' operator.
-sp_before_dc = ignore # ignore/add/remove/force
-
-# Add or remove space after the '::' operator.
-sp_after_dc = ignore # ignore/add/remove/force
-
-# (D) Add or remove around the D named array initializer ':' operator.
-sp_d_array_colon = ignore # ignore/add/remove/force
-
-# Add or remove space after the '!' (not) unary operator.
-#
-# Default: remove
-sp_not = remove # ignore/add/remove/force
-
-# Add or remove space after the '~' (invert) unary operator.
-#
-# Default: remove
-sp_inv = remove # ignore/add/remove/force
-
-# Add or remove space after the '&' (address-of) unary operator. This does not
-# affect the spacing after a '&' that is part of a type.
-#
-# Default: remove
-sp_addr = remove # ignore/add/remove/force
-
-# Add or remove space around the '.' or '->' operators.
-#
-# Default: remove
-sp_member = remove # ignore/add/remove/force
-
-# Add or remove space after the '*' (dereference) unary operator. This does
-# not affect the spacing after a '*' that is part of a type.
-#
-# Default: remove
-sp_deref = remove # ignore/add/remove/force
-
-# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'.
-#
-# Default: remove
-sp_sign = remove # ignore/add/remove/force
-
-# Add or remove space between '++' and '--' the word to which it is being
-# applied, as in '(--x)' or 'y++;'.
-#
-# Default: remove
-sp_incdec = remove # ignore/add/remove/force
-
-# Add or remove space before a backslash-newline at the end of a line.
-#
-# Default: add
-sp_before_nl_cont = add # ignore/add/remove/force
-
-# (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;'
-# or '+(int) bar;'.
-sp_after_oc_scope = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after the colon in message specs,
-# i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'.
-sp_after_oc_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space before the colon in message specs,
-# i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'.
-sp_before_oc_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after the colon in immutable dictionary expression
-# 'NSDictionary *test = @{@"foo" :@"bar"};'.
-sp_after_oc_dict_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space before the colon in immutable dictionary expression
-# 'NSDictionary *test = @{@"foo" :@"bar"};'.
-sp_before_oc_dict_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after the colon in message specs,
-# i.e. '[object setValue:1];' vs. '[object setValue: 1];'.
-sp_after_send_oc_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space before the colon in message specs,
-# i.e. '[object setValue:1];' vs. '[object setValue :1];'.
-sp_before_send_oc_colon = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after the (type) in message specs,
-# i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'.
-sp_after_oc_type = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after the first (type) in message specs,
-# i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'.
-sp_after_oc_return_type = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space between '@selector' and '(',
-# i.e. '@selector(msgName)' vs. '@selector (msgName)'.
-# Also applies to '@protocol()' constructs.
-sp_after_oc_at_sel = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space between '@selector(x)' and the following word,
-# i.e. '@selector(foo) a:' vs. '@selector(foo)a:'.
-sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space inside '@selector' parentheses,
-# i.e. '@selector(foo)' vs. '@selector( foo )'.
-# Also applies to '@protocol()' constructs.
-sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space before a block pointer caret,
-# i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'.
-sp_before_oc_block_caret = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after a block pointer caret,
-# i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'.
-sp_after_oc_block_caret = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space between the receiver and selector in a message,
-# as in '[receiver selector ...]'.
-sp_after_oc_msg_receiver = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space after '@property'.
-sp_after_oc_property = ignore # ignore/add/remove/force
-
-# (OC) Add or remove space between '@synchronized' and the open parenthesis,
-# i.e. '@synchronized(foo)' vs. '@synchronized (foo)'.
-sp_after_oc_synchronized = ignore # ignore/add/remove/force
-
-# Add or remove space around the ':' in 'b ? t : f'.
-sp_cond_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before the ':' in 'b ? t : f'.
-#
-# Overrides sp_cond_colon.
-sp_cond_colon_before = ignore # ignore/add/remove/force
-
-# Add or remove space after the ':' in 'b ? t : f'.
-#
-# Overrides sp_cond_colon.
-sp_cond_colon_after = ignore # ignore/add/remove/force
-
-# Add or remove space around the '?' in 'b ? t : f'.
-sp_cond_question = ignore # ignore/add/remove/force
-
-# Add or remove space before the '?' in 'b ? t : f'.
-#
-# Overrides sp_cond_question.
-sp_cond_question_before = ignore # ignore/add/remove/force
-
-# Add or remove space after the '?' in 'b ? t : f'.
-#
-# Overrides sp_cond_question.
-sp_cond_question_after = ignore # ignore/add/remove/force
-
-# In the abbreviated ternary form '(a ?: b)', add or remove space between '?'
-# and ':'.
-#
-# Overrides all other sp_cond_* options.
-sp_cond_ternary_short = ignore # ignore/add/remove/force
-
-# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make
-# sense here.
-sp_case_label = ignore # ignore/add/remove/force
-
-# (D) Add or remove space around the D '..' operator.
-sp_range = ignore # ignore/add/remove/force
-
-# Add or remove space after ':' in a Java/C++11 range-based 'for',
-# as in 'for (Type var : expr)'.
-sp_after_for_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before ':' in a Java/C++11 range-based 'for',
-# as in 'for (Type var : expr)'.
-sp_before_for_colon = ignore # ignore/add/remove/force
-
-# (D) Add or remove space between 'extern' and '(' as in 'extern (C)'.
-sp_extern_paren = ignore # ignore/add/remove/force
-
-# Add or remove space after the opening of a C++ comment,
-# i.e. '// A' vs. '//A'.
-sp_cmt_cpp_start = ignore # ignore/add/remove/force
-
-# If true, space is added with sp_cmt_cpp_start will be added after doxygen
-# sequences like '///', '///<', '//!' and '//!<'.
-sp_cmt_cpp_doxygen = false # true/false
-
-# If true, space is added with sp_cmt_cpp_start will be added after Qt
-# translator or meta-data comments like '//:', '//=', and '//~'.
-sp_cmt_cpp_qttr = false # true/false
-
-# Add or remove space between #else or #endif and a trailing comment.
-sp_endif_cmt = ignore # ignore/add/remove/force
-
-# Add or remove space after 'new', 'delete' and 'delete[]'.
-sp_after_new = ignore # ignore/add/remove/force
-
-# Add or remove space between 'new' and '(' in 'new()'.
-sp_between_new_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between ')' and type in 'new(foo) BAR'.
-sp_after_newop_paren = ignore # ignore/add/remove/force
-
-# Add or remove space inside parenthesis of the new operator
-# as in 'new(foo) BAR'.
-sp_inside_newop_paren = ignore # ignore/add/remove/force
-
-# Add or remove space after the open parenthesis of the new operator,
-# as in 'new(foo) BAR'.
-#
-# Overrides sp_inside_newop_paren.
-sp_inside_newop_paren_open = ignore # ignore/add/remove/force
-
-# Add or remove space before the close parenthesis of the new operator,
-# as in 'new(foo) BAR'.
-#
-# Overrides sp_inside_newop_paren.
-sp_inside_newop_paren_close = ignore # ignore/add/remove/force
-
-# Add or remove space before a trailing or embedded comment.
-sp_before_tr_emb_cmt = ignore # ignore/add/remove/force
-
-# Number of spaces before a trailing or embedded comment.
-sp_num_before_tr_emb_cmt = 0 # unsigned number
-
-# (Java) Add or remove space between an annotation and the open parenthesis.
-sp_annotation_paren = ignore # ignore/add/remove/force
-
-# If true, vbrace tokens are dropped to the previous token and skipped.
-sp_skip_vbrace_tokens = false # true/false
-
-# Add or remove space after 'noexcept'.
-sp_after_noexcept = ignore # ignore/add/remove/force
-
-# If true, a <TAB> is inserted after #define.
-force_tab_after_define = false # true/false
-
-#
-# Indenting options
-#
-
-# The number of columns to indent per level. Usually 2, 3, 4, or 8.
-#
-# Default: 8
-indent_columns = 4 # unsigned number
-
-# The continuation indent. If non-zero, this overrides the indent of '(' and
-# '=' continuation indents. Negative values are OK; negative value is absolute
-# and not increased for each '(' level.
-#
-# For FreeBSD, this is set to 4.
-indent_continue = 0 # number
-
-# The continuation indent, only for class header line(s). If non-zero, this
-# overrides the indent of 'class' continuation indents.
-indent_continue_class_head = 0 # unsigned number
-
-# Whether to indent empty lines (i.e. lines which contain only spaces before
-# the newline character).
-indent_single_newlines = false # true/false
-
-# The continuation indent for func_*_param if they are true. If non-zero, this
-# overrides the indent.
-indent_param = 0 # unsigned number
-
-# How to use tabs when indenting code.
-#
-# 0: Spaces only
-# 1: Indent with tabs to brace level, align with spaces (default)
-# 2: Indent and align with tabs, using spaces when not on a tabstop
-#
-# Default: 1
-indent_with_tabs = 0 # unsigned number
-
-# Whether to indent comments that are not at a brace level with tabs on a
-# tabstop. Requires indent_with_tabs=2. If false, will use spaces.
-indent_cmt_with_tabs = false # true/false
-
-# Whether to indent strings broken by '\' so that they line up.
-indent_align_string = false # true/false
-
-# The number of spaces to indent multi-line XML strings.
-# Requires indent_align_string=true.
-indent_xml_string = 0 # unsigned number
-
-# Spaces to indent '{' from level.
-indent_brace = 0 # unsigned number
-
-# Whether braces are indented to the body level.
-indent_braces = false # true/false
-
-# Whether to disable indenting function braces if indent_braces=true.
-indent_braces_no_func = false # true/false
-
-# Whether to disable indenting class braces if indent_braces=true.
-indent_braces_no_class = false # true/false
-
-# Whether to disable indenting struct braces if indent_braces=true.
-indent_braces_no_struct = false # true/false
-
-# Whether to indent based on the size of the brace parent,
-# i.e. 'if' → 3 spaces, 'for' → 4 spaces, etc.
-indent_brace_parent = false # true/false
-
-# Whether to indent based on the open parenthesis instead of the open brace
-# in '({\n'.
-indent_paren_open_brace = false # true/false
-
-# (C#) Whether to indent the brace of a C# delegate by another level.
-indent_cs_delegate_brace = false # true/false
-
-# (C#) Whether to indent a C# delegate (to handle delegates with no brace) by
-# another level.
-indent_cs_delegate_body = false # true/false
-
-# Whether to indent the body of a 'namespace'.
-indent_namespace = false # true/false
-
-# Whether to indent only the first namespace, and not any nested namespaces.
-# Requires indent_namespace=true.
-indent_namespace_single_indent = false # true/false
-
-# The number of spaces to indent a namespace block.
-indent_namespace_level = 0 # unsigned number
-
-# If the body of the namespace is longer than this number, it won't be
-# indented. Requires indent_namespace=true. 0 means no limit.
-indent_namespace_limit = 0 # unsigned number
-
-# Whether the 'extern "C"' body is indented.
-indent_extern = false # true/false
-
-# Whether the 'class' body is indented.
-indent_class = false # true/false
-
-# Whether to indent the stuff after a leading base class colon.
-indent_class_colon = false # true/false
-
-# Whether to indent based on a class colon instead of the stuff after the
-# colon. Requires indent_class_colon=true.
-indent_class_on_colon = false # true/false
-
-# Whether to indent the stuff after a leading class initializer colon.
-indent_constr_colon = false # true/false
-
-# Virtual indent from the ':' for member initializers.
-#
-# Default: 2
-indent_ctor_init_leading = 2 # unsigned number
-
-# Additional indent for constructor initializer list.
-# Negative values decrease indent down to the first column.
-indent_ctor_init = 0 # number
-
-# Whether to indent 'if' following 'else' as a new block under the 'else'.
-# If false, 'else\nif' is treated as 'else if' for indenting purposes.
-indent_else_if = false # true/false
-
-# Amount to indent variable declarations after a open brace.
-#
-# <0: Relative
-# ≥0: Absolute
-indent_var_def_blk = 0 # number
-
-# Whether to indent continued variable declarations instead of aligning.
-indent_var_def_cont = false # true/false
-
-# Whether to indent continued shift expressions ('<<' and '>>') instead of
-# aligning. Set align_left_shift=false when enabling this.
-indent_shift = false # true/false
-
-# Whether to force indentation of function definitions to start in column 1.
-indent_func_def_force_col1 = false # true/false
-
-# Whether to indent continued function call parameters one indent level,
-# rather than aligning parameters under the open parenthesis.
-indent_func_call_param = false # true/false
-
-# Same as indent_func_call_param, but for function definitions.
-indent_func_def_param = false # true/false
-
-# Same as indent_func_call_param, but for function prototypes.
-indent_func_proto_param = false # true/false
-
-# Same as indent_func_call_param, but for class declarations.
-indent_func_class_param = false # true/false
-
-# Same as indent_func_call_param, but for class variable constructors.
-indent_func_ctor_var_param = false # true/false
-
-# Same as indent_func_call_param, but for template parameter lists.
-indent_template_param = false # true/false
-
-# Double the indent for indent_func_xxx_param options.
-# Use both values of the options indent_columns and indent_param.
-indent_func_param_double = false # true/false
-
-# Indentation column for standalone 'const' qualifier on a function
-# prototype.
-indent_func_const = 0 # unsigned number
-
-# Indentation column for standalone 'throw' qualifier on a function
-# prototype.
-indent_func_throw = 0 # unsigned number
-
-# The number of spaces to indent a continued '->' or '.'.
-# Usually set to 0, 1, or indent_columns.
-indent_member = 0 # unsigned number
-
-# Whether lines broken at '.' or '->' should be indented by a single indent.
-# The indent_member option will not be effective if this is set to true.
-indent_member_single = false # true/false
-
-# Spaces to indent single line ('//') comments on lines before code.
-indent_sing_line_comments = 0 # unsigned number
-
-# Whether to indent trailing single line ('//') comments relative to the code
-# instead of trying to keep the same absolute column.
-indent_relative_single_line_comments = false # true/false
-
-# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns.
-indent_switch_case = 4 # unsigned number
-
-# Whether to indent preprocessor statements inside of switch statements.
-#
-# Default: true
-indent_switch_pp = true # true/false
-
-# Spaces to shift the 'case' line, without affecting any other lines.
-# Usually 0.
-indent_case_shift = 0 # unsigned number
-
-# Spaces to indent '{' from 'case'. By default, the brace will appear under
-# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK.
-indent_case_brace = 0 # number
-
-# Whether to indent comments found in first column.
-indent_col1_comment = false # true/false
-
-# How to indent goto labels.
-#
-# >0: Absolute column where 1 is the leftmost column
-# ≤0: Subtract from brace indent
-#
-# Default: 1
-indent_label = 1 # number
-
-# Same as indent_label, but for access specifiers that are followed by a
-# colon.
-#
-# Default: 1
-indent_access_spec = 1 # number
-
-# Whether to indent the code after an access specifier by one level.
-# If true, this option forces 'indent_access_spec=0'.
-indent_access_spec_body = false # true/false
-
-# If an open parenthesis is followed by a newline, whether to indent the next
-# line so that it lines up after the open parenthesis (not recommended).
-indent_paren_nl = false # true/false
-
-# How to indent a close parenthesis after a newline.
-#
-# 0: Indent to body level (default)
-# 1: Align under the open parenthesis
-# 2: Indent to the brace level
-indent_paren_close = 0 # unsigned number
-
-# Whether to indent the open parenthesis of a function definition,
-# if the parenthesis is on its own line.
-indent_paren_after_func_def = false # true/false
-
-# Whether to indent the open parenthesis of a function declaration,
-# if the parenthesis is on its own line.
-indent_paren_after_func_decl = false # true/false
-
-# Whether to indent the open parenthesis of a function call,
-# if the parenthesis is on its own line.
-indent_paren_after_func_call = false # true/false
-
-# Whether to indent a comma when inside a parenthesis.
-# If true, aligns under the open parenthesis.
-indent_comma_paren = false # true/false
-
-# Whether to indent a Boolean operator when inside a parenthesis.
-# If true, aligns under the open parenthesis.
-indent_bool_paren = false # true/false
-
-# Whether to indent a semicolon when inside a for parenthesis.
-# If true, aligns under the open for parenthesis.
-indent_semicolon_for_paren = false # true/false
-
-# Whether to align the first expression to following ones
-# if indent_bool_paren=true.
-indent_first_bool_expr = false # true/false
-
-# Whether to align the first expression to following ones
-# if indent_semicolon_for_paren=true.
-indent_first_for_expr = false # true/false
-
-# If an open square is followed by a newline, whether to indent the next line
-# so that it lines up after the open square (not recommended).
-indent_square_nl = false # true/false
-
-# (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies.
-indent_preserve_sql = false # true/false
-
-# Whether to align continued statements at the '='. If false or if the '=' is
-# followed by a newline, the next line is indent one tab.
-#
-# Default: true
-indent_align_assign = false # true/false
-
-# Whether to align continued statements at the '('. If false or the '(' is not
-# followed by a newline, the next line indent is one tab.
-#
-# Default: true
-indent_align_paren = true # true/false
-
-# (OC) Whether to indent Objective-C blocks at brace level instead of usual
-# rules.
-indent_oc_block = false # true/false
-
-# (OC) Indent for Objective-C blocks in a message relative to the parameter
-# name.
-#
-# =0: Use indent_oc_block rules
-# >0: Use specified number of spaces to indent
-indent_oc_block_msg = 0 # unsigned number
-
-# (OC) Minimum indent for subsequent parameters
-indent_oc_msg_colon = 0 # unsigned number
-
-# (OC) Whether to prioritize aligning with initial colon (and stripping spaces
-# from lines, if necessary).
-#
-# Default: true
-indent_oc_msg_prioritize_first_colon = true # true/false
-
-# (OC) Whether to indent blocks the way that Xcode does by default
-# (from the keyword if the parameter is on its own line; otherwise, from the
-# previous indentation level). Requires indent_oc_block_msg=true.
-indent_oc_block_msg_xcode_style = false # true/false
-
-# (OC) Whether to indent blocks from where the brace is, relative to a
-# message keyword. Requires indent_oc_block_msg=true.
-indent_oc_block_msg_from_keyword = false # true/false
-
-# (OC) Whether to indent blocks from where the brace is, relative to a message
-# colon. Requires indent_oc_block_msg=true.
-indent_oc_block_msg_from_colon = false # true/false
-
-# (OC) Whether to indent blocks from where the block caret is.
-# Requires indent_oc_block_msg=true.
-indent_oc_block_msg_from_caret = false # true/false
-
-# (OC) Whether to indent blocks from where the brace caret is.
-# Requires indent_oc_block_msg=true.
-indent_oc_block_msg_from_brace = false # true/false
-
-# When indenting after virtual brace open and newline add further spaces to
-# reach this minimum indent.
-indent_min_vbrace_open = 0 # unsigned number
-
-# Whether to add further spaces after regular indent to reach next tabstop
-# when identing after virtual brace open and newline.
-indent_vbrace_open_on_tabstop = false # true/false
-
-# How to indent after a brace followed by another token (not a newline).
-# true: indent all contained lines to match the token
-# false: indent all contained lines to match the brace
-#
-# Default: true
-indent_token_after_brace = true # true/false
-
-# Whether to indent the body of a C++11 lambda.
-indent_cpp_lambda_body = false # true/false
-
-# (C#) Whether to indent a 'using' block if no braces are used.
-#
-# Default: true
-indent_using_block = true # true/false
-
-# How to indent the continuation of ternary operator.
-#
-# 0: Off (default)
-# 1: When the `if_false` is a continuation, indent it under `if_false`
-# 2: When the `:` is a continuation, indent it under `?`
-indent_ternary_operator = 0 # unsigned number
-
-# If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column.
-indent_off_after_return_new = false # true/false
-
-# If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token.
-indent_single_after_return = false # true/false
-
-# Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they
-# have their own indentation).
-indent_ignore_asm_block = false # true/false
-
-#
-# Newline adding and removing options
-#
-
-# Whether to collapse empty blocks between '{' and '}'.
-nl_collapse_empty_body = false # true/false
-
-# Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'.
-nl_assign_leave_one_liners = false # true/false
-
-# Don't split one-line braced statements inside a 'class xx { }' body.
-nl_class_leave_one_liners = false # true/false
-
-# Don't split one-line enums, as in 'enum foo { BAR = 15 };'
-nl_enum_leave_one_liners = false # true/false
-
-# Don't split one-line get or set functions.
-nl_getset_leave_one_liners = false # true/false
-
-# (C#) Don't split one-line property get or set functions.
-nl_cs_property_leave_one_liners = false # true/false
-
-# Don't split one-line function definitions, as in 'int foo() { return 0; }'.
-nl_func_leave_one_liners = false # true/false
-
-# Don't split one-line C++11 lambdas, as in '[]() { return 0; }'.
-nl_cpp_lambda_leave_one_liners = false # true/false
-
-# Don't split one-line if/else statements, as in 'if(...) b++;'.
-nl_if_leave_one_liners = false # true/false
-
-# Don't split one-line while statements, as in 'while(...) b++;'.
-nl_while_leave_one_liners = false # true/false
-
-# Don't split one-line for statements, as in 'for(...) b++;'.
-nl_for_leave_one_liners = false # true/false
-
-# (OC) Don't split one-line Objective-C messages.
-nl_oc_msg_leave_one_liner = false # true/false
-
-# (OC) Add or remove newline between method declaration and '{'.
-nl_oc_mdef_brace = ignore # ignore/add/remove/force
-
-# (OC) Add or remove newline between Objective-C block signature and '{'.
-nl_oc_block_brace = ignore # ignore/add/remove/force
-
-# (OC) Add or remove newline between '@interface' and '{'.
-nl_oc_interface_brace = ignore # ignore/add/remove/force
-
-# (OC) Add or remove newline between '@implementation' and '{'.
-nl_oc_implementation_brace = ignore # ignore/add/remove/force
-
-# Add or remove newlines at the start of the file.
-nl_start_of_file = ignore # ignore/add/remove/force
-
-# The minimum number of newlines at the start of the file (only used if
-# nl_start_of_file is 'add' or 'force').
-nl_start_of_file_min = 0 # unsigned number
-
-# Add or remove newline at the end of the file.
-nl_end_of_file = ignore # ignore/add/remove/force
-
-# The minimum number of newlines at the end of the file (only used if
-# nl_end_of_file is 'add' or 'force').
-nl_end_of_file_min = 0 # unsigned number
-
-# Add or remove newline between '=' and '{'.
-nl_assign_brace = remove # ignore/add/remove/force
-
-# (D) Add or remove newline between '=' and '['.
-nl_assign_square = ignore # ignore/add/remove/force
-
-# Add or remove newline between '[]' and '{'.
-nl_tsquare_brace = ignore # ignore/add/remove/force
-
-# (D) Add or remove newline after '= ['. Will also affect the newline before
-# the ']'.
-nl_after_square_assign = ignore # ignore/add/remove/force
-
-# The number of blank lines after a block of variable definitions at the top
-# of a function body.
-#
-# 0 = No change (default).
-nl_func_var_def_blk = 0 # unsigned number
-
-# The number of newlines before a block of typedefs. If nl_after_access_spec
-# is non-zero, that option takes precedence.
-#
-# 0 = No change (default).
-nl_typedef_blk_start = 0 # unsigned number
-
-# The number of newlines after a block of typedefs.
-#
-# 0 = No change (default).
-nl_typedef_blk_end = 0 # unsigned number
-
-# The maximum number of consecutive newlines within a block of typedefs.
-#
-# 0 = No change (default).
-nl_typedef_blk_in = 0 # unsigned number
-
-# The number of newlines before a block of variable definitions not at the top
-# of a function body. If nl_after_access_spec is non-zero, that option takes
-# precedence.
-#
-# 0 = No change (default).
-nl_var_def_blk_start = 0 # unsigned number
-
-# The number of newlines after a block of variable definitions not at the top
-# of a function body.
-#
-# 0 = No change (default).
-nl_var_def_blk_end = 0 # unsigned number
-
-# The maximum number of consecutive newlines within a block of variable
-# definitions.
-#
-# 0 = No change (default).
-nl_var_def_blk_in = 0 # unsigned number
-
-# Add or remove newline between a function call's ')' and '{', as in
-# 'list_for_each(item, &list) { }'.
-nl_fcall_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum' and '{'.
-nl_enum_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum' and 'class'.
-nl_enum_class = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum class' and the identifier.
-nl_enum_class_identifier = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum class' type and ':'.
-nl_enum_identifier_colon = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum class identifier :' and type.
-nl_enum_colon_type = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'struct and '{'.
-nl_struct_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'union' and '{'.
-nl_union_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'if' and '{'.
-nl_if_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'else'.
-nl_brace_else = remove # ignore/add/remove/force
-
-# Add or remove newline between 'else if' and '{'. If set to ignore,
-# nl_if_brace is used instead.
-nl_elseif_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between 'else' and '{'.
-nl_else_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between 'else' and 'if'.
-nl_else_if = ignore # ignore/add/remove/force
-
-# Add or remove newline before 'if'/'else if' closing parenthesis.
-nl_before_if_closing_paren = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'finally'.
-nl_brace_finally = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'finally' and '{'.
-nl_finally_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'try' and '{'.
-nl_try_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between get/set and '{'.
-nl_getset_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'for' and '{'.
-nl_for_brace = remove # ignore/add/remove/force
-
-# Add or remove newline before the '{' of a 'catch' statement, as in
-# 'catch (decl) <here> {'.
-nl_catch_brace = ignore # ignore/add/remove/force
-
-# (OC) Add or remove newline before the '{' of a '@catch' statement, as in
-# '@catch (decl) <here> {'. If set to ignore, nl_catch_brace is used.
-nl_oc_catch_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'catch'.
-nl_brace_catch = ignore # ignore/add/remove/force
-
-# (OC) Add or remove newline between '}' and '@catch'. If set to ignore,
-# nl_brace_catch is used.
-nl_oc_brace_catch = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and ']'.
-nl_brace_square = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and ')' in a function invocation.
-nl_brace_fparen = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'while' and '{'.
-nl_while_brace = remove # ignore/add/remove/force
-
-# (D) Add or remove newline between 'scope (x)' and '{'.
-nl_scope_brace = ignore # ignore/add/remove/force
-
-# (D) Add or remove newline between 'unittest' and '{'.
-nl_unittest_brace = ignore # ignore/add/remove/force
-
-# (D) Add or remove newline between 'version (x)' and '{'.
-nl_version_brace = ignore # ignore/add/remove/force
-
-# (C#) Add or remove newline between 'using' and '{'.
-nl_using_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between two open or close braces. Due to general
-# newline/brace handling, REMOVE may not work.
-nl_brace_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'do' and '{'.
-nl_do_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'while' of 'do' statement.
-nl_brace_while = remove # ignore/add/remove/force
-
-# Add or remove newline between 'switch' and '{'.
-nl_switch_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between 'synchronized' and '{'.
-nl_synchronized_brace = ignore # ignore/add/remove/force
-
-# Add a newline between ')' and '{' if the ')' is on a different line than the
-# if/for/etc.
-#
-# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and
-# nl_catch_brace.
-nl_multi_line_cond = false # true/false
-
-# Force a newline in a define after the macro name for multi-line defines.
-nl_multi_line_define = false # true/false
-
-# Whether to add a newline before 'case', and a blank line before a 'case'
-# statement that follows a ';' or '}'.
-nl_before_case = false # true/false
-
-# Whether to add a newline after a 'case' statement.
-nl_after_case = false # true/false
-
-# Add or remove newline between a case ':' and '{'.
-#
-# Overrides nl_after_case.
-nl_case_colon_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between ')' and 'throw'.
-nl_before_throw = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'namespace' and '{'.
-nl_namespace_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'template<>' and whatever follows.
-nl_template_class = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'class' and '{'.
-nl_class_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline before or after (depending on pos_class_comma) each
-# ',' in the base class list.
-nl_class_init_args = ignore # ignore/add/remove/force
-
-# Add or remove newline after each ',' in the constructor member
-# initialization. Related to nl_constr_colon, pos_constr_colon and
-# pos_constr_comma.
-nl_constr_init_args = ignore # ignore/add/remove/force
-
-# Add or remove newline before first element, after comma, and after last
-# element, in 'enum'.
-nl_enum_own_lines = ignore # ignore/add/remove/force
-
-# Add or remove newline between return type and function name in a function
-# definition.
-nl_func_type_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between return type and function name inside a class
-# definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name
-# is used instead.
-nl_func_type_name_class = ignore # ignore/add/remove/force
-
-# Add or remove newline between class specification and '::'
-# in 'void A::f() { }'. Only appears in separate member implementation (does
-# not appear with in-line implementation).
-nl_func_class_scope = ignore # ignore/add/remove/force
-
-# Add or remove newline between function scope and name, as in
-# 'void A :: <here> f() { }'.
-nl_func_scope_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between return type and function name in a prototype.
-nl_func_proto_type_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between a function name and the opening '(' in the
-# declaration.
-nl_func_paren = ignore # ignore/add/remove/force
-
-# Overrides nl_func_paren for functions with no parameters.
-nl_func_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline between a function name and the opening '(' in the
-# definition.
-nl_func_def_paren = ignore # ignore/add/remove/force
-
-# Overrides nl_func_def_paren for functions with no parameters.
-nl_func_def_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline between a function name and the opening '(' in the
-# call.
-nl_func_call_paren = ignore # ignore/add/remove/force
-
-# Overrides nl_func_call_paren for functions with no parameters.
-nl_func_call_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline after '(' in a function declaration.
-nl_func_decl_start = ignore # ignore/add/remove/force
-
-# Add or remove newline after '(' in a function definition.
-nl_func_def_start = ignore # ignore/add/remove/force
-
-# Overrides nl_func_decl_start when there is only one parameter.
-nl_func_decl_start_single = ignore # ignore/add/remove/force
-
-# Overrides nl_func_def_start when there is only one parameter.
-nl_func_def_start_single = ignore # ignore/add/remove/force
-
-# Whether to add a newline after '(' in a function declaration if '(' and ')'
-# are in different lines. If false, nl_func_decl_start is used instead.
-nl_func_decl_start_multi_line = false # true/false
-
-# Whether to add a newline after '(' in a function definition if '(' and ')'
-# are in different lines. If false, nl_func_def_start is used instead.
-nl_func_def_start_multi_line = false # true/false
-
-# Add or remove newline after each ',' in a function declaration.
-nl_func_decl_args = ignore # ignore/add/remove/force
-
-# Add or remove newline after each ',' in a function definition.
-nl_func_def_args = ignore # ignore/add/remove/force
-
-# Whether to add a newline after each ',' in a function declaration if '('
-# and ')' are in different lines. If false, nl_func_decl_args is used instead.
-nl_func_decl_args_multi_line = false # true/false
-
-# Whether to add a newline after each ',' in a function definition if '('
-# and ')' are in different lines. If false, nl_func_def_args is used instead.
-nl_func_def_args_multi_line = false # true/false
-
-# Add or remove newline before the ')' in a function declaration.
-nl_func_decl_end = ignore # ignore/add/remove/force
-
-# Add or remove newline before the ')' in a function definition.
-nl_func_def_end = ignore # ignore/add/remove/force
-
-# Overrides nl_func_decl_end when there is only one parameter.
-nl_func_decl_end_single = ignore # ignore/add/remove/force
-
-# Overrides nl_func_def_end when there is only one parameter.
-nl_func_def_end_single = ignore # ignore/add/remove/force
-
-# Whether to add a newline before ')' in a function declaration if '(' and ')'
-# are in different lines. If false, nl_func_decl_end is used instead.
-nl_func_decl_end_multi_line = false # true/false
-
-# Whether to add a newline before ')' in a function definition if '(' and ')'
-# are in different lines. If false, nl_func_def_end is used instead.
-nl_func_def_end_multi_line = false # true/false
-
-# Add or remove newline between '()' in a function declaration.
-nl_func_decl_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline between '()' in a function definition.
-nl_func_def_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline between '()' in a function call.
-nl_func_call_empty = ignore # ignore/add/remove/force
-
-# Whether to add a newline after '(' in a function call if '(' and ')' are in
-# different lines.
-nl_func_call_start_multi_line = false # true/false
-
-# Whether to add a newline after each ',' in a function call if '(' and ')'
-# are in different lines.
-nl_func_call_args_multi_line = false # true/false
-
-# Whether to add a newline before ')' in a function call if '(' and ')' are in
-# different lines.
-nl_func_call_end_multi_line = false # true/false
-
-# (OC) Whether to put each Objective-C message parameter on a separate line.
-# See nl_oc_msg_leave_one_liner.
-nl_oc_msg_args = false # true/false
-
-# Add or remove newline between function signature and '{'.
-nl_fdef_brace = force # ignore/add/remove/force
-
-# Add or remove newline between C++11 lambda signature and '{'.
-nl_cpp_ldef_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'return' and the return expression.
-nl_return_expr = ignore # ignore/add/remove/force
-
-# Whether to add a newline after semicolons, except in 'for' statements.
-nl_after_semicolon = false # true/false
-
-# (Java) Add or remove newline between the ')' and '{{' of the double brace
-# initializer.
-nl_paren_dbrace_open = ignore # ignore/add/remove/force
-
-# Whether to add a newline after the type in an unnamed temporary
-# direct-list-initialization.
-nl_type_brace_init_lst = ignore # ignore/add/remove/force
-
-# Whether to add a newline after the open brace in an unnamed temporary
-# direct-list-initialization.
-nl_type_brace_init_lst_open = ignore # ignore/add/remove/force
-
-# Whether to add a newline before the close brace in an unnamed temporary
-# direct-list-initialization.
-nl_type_brace_init_lst_close = ignore # ignore/add/remove/force
-
-# Whether to add a newline after '{'. This also adds a newline before the
-# matching '}'.
-nl_after_brace_open = false # true/false
-
-# Whether to add a newline between the open brace and a trailing single-line
-# comment. Requires nl_after_brace_open=true.
-nl_after_brace_open_cmt = false # true/false
-
-# Whether to add a newline after a virtual brace open with a non-empty body.
-# These occur in un-braced if/while/do/for statement bodies.
-nl_after_vbrace_open = false # true/false
-
-# Whether to add a newline after a virtual brace open with an empty body.
-# These occur in un-braced if/while/do/for statement bodies.
-nl_after_vbrace_open_empty = false # true/false
-
-# Whether to add a newline after '}'. Does not apply if followed by a
-# necessary ';'.
-nl_after_brace_close = false # true/false
-
-# Whether to add a newline after a virtual brace close,
-# as in 'if (foo) a++; <here> return;'.
-nl_after_vbrace_close = false # true/false
-
-# Add or remove newline between the close brace and identifier,
-# as in 'struct { int a; } <here> b;'. Affects enumerations, unions and
-# structures. If set to ignore, uses nl_after_brace_close.
-nl_brace_struct_var = ignore # ignore/add/remove/force
-
-# Whether to alter newlines in '#define' macros.
-nl_define_macro = false # true/false
-
-# Whether to alter newlines between consecutive parenthesis closes. The number
-# of closing parentheses in a line will depend on respective open parenthesis
-# lines.
-nl_squeeze_paren_close = false # true/false
-
-# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and
-# '#endif'. Does not affect top-level #ifdefs.
-nl_squeeze_ifdef = false # true/false
-
-# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well.
-nl_squeeze_ifdef_top_level = false # true/false
-
-# Add or remove blank line before 'if'.
-nl_before_if = force # ignore/add/remove/force
-
-# Add or remove blank line after 'if' statement. Add/Force work only if the
-# next token is not a closing brace.
-nl_after_if = force # ignore/add/remove/force
-
-# Add or remove blank line before 'for'.
-nl_before_for = force # ignore/add/remove/force
-
-# Add or remove blank line after 'for' statement.
-nl_after_for = force # ignore/add/remove/force
-
-# Add or remove blank line before 'while'.
-nl_before_while = force # ignore/add/remove/force
-
-# Add or remove blank line after 'while' statement.
-nl_after_while = force # ignore/add/remove/force
-
-# Add or remove blank line before 'switch'.
-nl_before_switch = force # ignore/add/remove/force
-
-# Add or remove blank line after 'switch' statement.
-nl_after_switch = force # ignore/add/remove/force
-
-# Add or remove blank line before 'synchronized'.
-nl_before_synchronized = ignore # ignore/add/remove/force
-
-# Add or remove blank line after 'synchronized' statement.
-nl_after_synchronized = ignore # ignore/add/remove/force
-
-# Add or remove blank line before 'do'.
-nl_before_do = force # ignore/add/remove/force
-
-# Add or remove blank line after 'do/while' statement.
-nl_after_do = force # ignore/add/remove/force
-
-# Whether to double-space commented-entries in 'struct'/'union'/'enum'.
-nl_ds_struct_enum_cmt = false # true/false
-
-# Whether to force a newline before '}' of a 'struct'/'union'/'enum'.
-# (Lower priority than eat_blanks_before_close_brace.)
-nl_ds_struct_enum_close_brace = false # true/false
-
-# Add or remove newline before or after (depending on pos_class_colon) a class
-# colon, as in 'class Foo <here> : <or here> public Bar'.
-nl_class_colon = ignore # ignore/add/remove/force
-
-# Add or remove newline around a class constructor colon. The exact position
-# depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma.
-nl_constr_colon = ignore # ignore/add/remove/force
-
-# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }'
-# into a single line. If true, prevents other brace newline rules from turning
-# such code into four lines.
-nl_namespace_two_to_one_liner = false # true/false
-
-# Whether to remove a newline in simple unbraced if statements, turning them
-# into one-liners, as in 'if(b)\n i++;' → 'if(b) i++;'.
-nl_create_if_one_liner = false # true/false
-
-# Whether to remove a newline in simple unbraced for statements, turning them
-# into one-liners, as in 'for (...)\n stmt;' → 'for (...) stmt;'.
-nl_create_for_one_liner = false # true/false
-
-# Whether to remove a newline in simple unbraced while statements, turning
-# them into one-liners, as in 'while (expr)\n stmt;' → 'while (expr) stmt;'.
-nl_create_while_one_liner = false # true/false
-
-# Whether to collapse a function definition whose body (not counting braces)
-# is only one line so that the entire definition (prototype, braces, body) is
-# a single line.
-nl_create_func_def_one_liner = false # true/false
-
-# Whether to split one-line simple unbraced if statements into two lines by
-# adding a newline, as in 'if(b) <here> i++;'.
-nl_split_if_one_liner = false # true/false
-
-# Whether to split one-line simple unbraced for statements into two lines by
-# adding a newline, as in 'for (...) <here> stmt;'.
-nl_split_for_one_liner = false # true/false
-
-# Whether to split one-line simple unbraced while statements into two lines by
-# adding a newline, as in 'while (expr) <here> stmt;'.
-nl_split_while_one_liner = false # true/false
-
-#
-# Blank line options
-#
-
-# The maximum number of consecutive newlines (3 = 2 blank lines).
-nl_max = 0 # unsigned number
-
-# The maximum number of consecutive newlines in a function.
-nl_max_blank_in_func = 0 # unsigned number
-
-# The number of newlines before a function prototype.
-nl_before_func_body_proto = 0 # unsigned number
-
-# The number of newlines before a multi-line function definition.
-nl_before_func_body_def = 0 # unsigned number
-
-# The number of newlines before a class constructor/destructor prototype.
-nl_before_func_class_proto = 0 # unsigned number
-
-# The number of newlines before a class constructor/destructor definition.
-nl_before_func_class_def = 0 # unsigned number
-
-# The number of newlines after a function prototype.
-nl_after_func_proto = 0 # unsigned number
-
-# The number of newlines after a function prototype, if not followed by
-# another function prototype.
-nl_after_func_proto_group = 0 # unsigned number
-
-# The number of newlines after a class constructor/destructor prototype.
-nl_after_func_class_proto = 0 # unsigned number
-
-# The number of newlines after a class constructor/destructor prototype,
-# if not followed by another constructor/destructor prototype.
-nl_after_func_class_proto_group = 0 # unsigned number
-
-# Whether one-line method definitions inside a class body should be treated
-# as if they were prototypes for the purposes of adding newlines.
-#
-# Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def
-# and nl_before_func_class_def for one-liners.
-nl_class_leave_one_liner_groups = false # true/false
-
-# The number of newlines after '}' of a multi-line function body.
-nl_after_func_body = 0 # unsigned number
-
-# The number of newlines after '}' of a multi-line function body in a class
-# declaration. Also affects class constructors/destructors.
-#
-# Overrides nl_after_func_body.
-nl_after_func_body_class = 0 # unsigned number
-
-# The number of newlines after '}' of a single line function body. Also
-# affects class constructors/destructors.
-#
-# Overrides nl_after_func_body and nl_after_func_body_class.
-nl_after_func_body_one_liner = 0 # unsigned number
-
-# The minimum number of newlines before a multi-line comment.
-# Doesn't apply if after a brace open or another multi-line comment.
-nl_before_block_comment = 0 # unsigned number
-
-# The minimum number of newlines before a single-line C comment.
-# Doesn't apply if after a brace open or other single-line C comments.
-nl_before_c_comment = 0 # unsigned number
-
-# The minimum number of newlines before a CPP comment.
-# Doesn't apply if after a brace open or other CPP comments.
-nl_before_cpp_comment = 0 # unsigned number
-
-# Whether to force a newline after a multi-line comment.
-nl_after_multiline_comment = false # true/false
-
-# Whether to force a newline after a label's colon.
-nl_after_label_colon = false # true/false
-
-# The number of newlines after '}' or ';' of a struct/enum/union definition.
-nl_after_struct = 0 # unsigned number
-
-# The number of newlines before a class definition.
-nl_before_class = 0 # unsigned number
-
-# The number of newlines after '}' or ';' of a class definition.
-nl_after_class = 0 # unsigned number
-
-# The number of newlines before an access specifier label. This also includes
-# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count
-# if after a brace open.
-#
-# 0 = No change (default).
-nl_before_access_spec = 0 # unsigned number
-
-# The number of newlines after an access specifier label. This also includes
-# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count
-# if after a brace open.
-#
-# 0 = No change (default).
-#
-# Overrides nl_typedef_blk_start and nl_var_def_blk_start.
-nl_after_access_spec = 0 # unsigned number
-
-# The number of newlines between a function definition and the function
-# comment, as in '// comment\n <here> void foo() {...}'.
-#
-# 0 = No change (default).
-nl_comment_func_def = 0 # unsigned number
-
-# The number of newlines after a try-catch-finally block that isn't followed
-# by a brace close.
-#
-# 0 = No change (default).
-nl_after_try_catch_finally = 0 # unsigned number
-
-# (C#) The number of newlines before and after a property, indexer or event
-# declaration.
-#
-# 0 = No change (default).
-nl_around_cs_property = 0 # unsigned number
-
-# (C#) The number of newlines between the get/set/add/remove handlers.
-#
-# 0 = No change (default).
-nl_between_get_set = 0 # unsigned number
-
-# (C#) Add or remove newline between property and the '{'.
-nl_property_brace = ignore # ignore/add/remove/force
-
-# The number of newlines after '{' of a namespace. This also adds newlines
-# before the matching '}'.
-#
-# 0 = Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if
-# applicable, otherwise no change.
-#
-# Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace.
-nl_inside_namespace = 0 # unsigned number
-
-# Whether to remove blank lines after '{'.
-eat_blanks_after_open_brace = false # true/false
-
-# Whether to remove blank lines before '}'.
-eat_blanks_before_close_brace = true # true/false
-
-# How aggressively to remove extra newlines not in preprocessor.
-#
-# 0: No change (default)
-# 1: Remove most newlines not handled by other config
-# 2: Remove all newlines and reformat completely by config
-nl_remove_extra_newlines = 0 # unsigned number
-
-# Whether to put a blank line before 'return' statements, unless after an open
-# brace.
-nl_before_return = false # true/false
-
-# Whether to put a blank line after 'return' statements, unless followed by a
-# close brace.
-nl_after_return = false # true/false
-
-# (Java) Add or remove newline after an annotation statement. Only affects
-# annotations that are after a newline.
-nl_after_annotation = ignore # ignore/add/remove/force
-
-# (Java) Add or remove newline between two annotations.
-nl_between_annotation = ignore # ignore/add/remove/force
-
-#
-# Positioning options
-#
-
-# The position of arithmetic operators in wrapped expressions.
-pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of assignment in wrapped expressions. Do not affect '='
-# followed by '{'.
-pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of Boolean operators in wrapped expressions.
-pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of comparison operators in wrapped expressions.
-pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of conditional operators, as in the '?' and ':' of
-# 'expr ? stmt : stmt', in wrapped expressions.
-pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of the comma in wrapped expressions.
-pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of the comma in enum entries.
-pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of the comma in the base class list if there is more than one
-# line. Affects nl_class_init_args.
-pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of the comma in the constructor initialization list.
-# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon.
-pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of trailing/leading class colon, between class and base class
-# list. Affects nl_class_colon.
-pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-# The position of colons between constructor and member initialization.
-# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma.
-pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
-
-#
-# Line splitting options
-#
-
-# Try to limit code width to N columns.
-code_width = 100 # unsigned number
-
-# Whether to fully split long 'for' statements at semi-colons.
-ls_for_split_full = true # true/false
-
-# Whether to fully split long function prototypes/calls at commas.
-ls_func_split_full = true # true/false
-
-# Whether to split lines as close to code_width as possible and ignore some
-# groupings.
-ls_code_width = false # true/false
-
-#
-# Code alignment options (not left column spaces/tabs)
-#
-
-# Whether to keep non-indenting tabs.
-align_keep_tabs = false # true/false
-
-# Whether to use tabs for aligning.
-align_with_tabs = false # true/false
-
-# Whether to bump out to the next tab when aligning.
-align_on_tabstop = false # true/false
-
-# Whether to right-align numbers.
-align_number_right = false # true/false
-
-# Whether to keep whitespace not required for alignment.
-align_keep_extra_space = false # true/false
-
-# Whether to align variable definitions in prototypes and functions.
-align_func_params = false # true/false
-
-# The span for aligning parameter definitions in function on parameter name.
-#
-# 0 = Don't align (default).
-align_func_params_span = 0 # unsigned number
-
-# The threshold for aligning function parameter definitions.
-#
-# 0 = No limit (default).
-align_func_params_thresh = 0 # unsigned number
-
-# The gap for aligning function parameter definitions.
-align_func_params_gap = 0 # unsigned number
-
-# Whether to align parameters in single-line functions that have the same
-# name. The function names must already be aligned with each other.
-align_same_func_call_params = false # true/false
-
-# The span for aligning function-call parameters for single line functions.
-#
-# 0 = Don't align (default).
-align_same_func_call_params_span = 0 # unsigned number
-
-# The threshold for aligning function-call parameters for single line
-# functions.
-#
-# 0 = No limit (default).
-align_same_func_call_params_thresh = 0 # unsigned number
-
-# The span for aligning variable definitions.
-#
-# 0 = Don't align (default).
-align_var_def_span = 0 # unsigned number
-
-# How to align the '*' in variable definitions.
-#
-# 0: Part of the type 'void * foo;' (default)
-# 1: Part of the variable 'void *foo;'
-# 2: Dangling 'void *foo;'
-align_var_def_star_style = 0 # unsigned number
-
-# How to align the '&' in variable definitions.
-#
-# 0: Part of the type 'long & foo;' (default)
-# 1: Part of the variable 'long &foo;'
-# 2: Dangling 'long &foo;'
-align_var_def_amp_style = 0 # unsigned number
-
-# The threshold for aligning variable definitions.
-#
-# 0 = No limit (default).
-align_var_def_thresh = 0 # unsigned number
-
-# The gap for aligning variable definitions.
-align_var_def_gap = 0 # unsigned number
-
-# Whether to align the colon in struct bit fields.
-align_var_def_colon = false # true/false
-
-# The gap for aligning the colon in struct bit fields.
-align_var_def_colon_gap = 0 # unsigned number
-
-# Whether to align any attribute after the variable name.
-align_var_def_attribute = false # true/false
-
-# Whether to align inline struct/enum/union variable definitions.
-align_var_def_inline = false # true/false
-
-# The span for aligning on '=' in assignments.
-#
-# 0 = Don't align (default).
-align_assign_span = 0 # unsigned number
-
-# The threshold for aligning on '=' in assignments.
-#
-# 0 = No limit (default).
-align_assign_thresh = 0 # unsigned number
-
-# How to apply align_assign_span to function declaration "assignments", i.e.
-# 'virtual void foo() = 0' or '~foo() = {default|delete}'.
-#
-# 0: Align with other assignments (default)
-# 1: Align with each other, ignoring regular assignments
-# 2: Don't align
-align_assign_decl_func = 0 # unsigned number
-
-# The span for aligning on '=' in enums.
-#
-# 0 = Don't align (default).
-align_enum_equ_span = 0 # unsigned number
-
-# The threshold for aligning on '=' in enums.
-#
-# 0 = no limit (default).
-align_enum_equ_thresh = 0 # unsigned number
-
-# The span for aligning class member definitions.
-#
-# 0 = Don't align (default).
-align_var_class_span = 0 # unsigned number
-
-# The threshold for aligning class member definitions.
-#
-# 0 = No limit (default).
-align_var_class_thresh = 0 # unsigned number
-
-# The gap for aligning class member definitions.
-align_var_class_gap = 0 # unsigned number
-
-# The span for aligning struct/union member definitions.
-#
-# 0 = Don't align (default).
-align_var_struct_span = 0 # unsigned number
-
-# The threshold for aligning struct/union member definitions.
-#
-# 0 = No limit (default).
-align_var_struct_thresh = 0 # unsigned number
-
-# The gap for aligning struct/union member definitions.
-align_var_struct_gap = 0 # unsigned number
-
-# The span for aligning struct initializer values.
-#
-# 0 = Don't align (default).
-align_struct_init_span = 0 # unsigned number
-
-# The minimum space between the type and the synonym of a typedef.
-align_typedef_gap = 0 # unsigned number
-
-# The span for aligning single-line typedefs.
-#
-# 0 = Don't align (default).
-align_typedef_span = 0 # unsigned number
-
-# How to align typedef'd functions with other typedefs.
-#
-# 0: Don't mix them at all (default)
-# 1: Align the open parenthesis with the types
-# 2: Align the function type name with the other type names
-align_typedef_func = 0 # unsigned number
-
-# How to align the '*' in typedefs.
-#
-# 0: Align on typedef type, ignore '*' (default)
-# 1: The '*' is part of type name: 'typedef int *pint;'
-# 2: The '*' is part of the type, but dangling: 'typedef int *pint;'
-align_typedef_star_style = 0 # unsigned number
-
-# How to align the '&' in typedefs.
-#
-# 0: Align on typedef type, ignore '&' (default)
-# 1: The '&' is part of type name: 'typedef int &pint;'
-# 2: The '&' is part of the type, but dangling: 'typedef int &pint;'
-align_typedef_amp_style = 0 # unsigned number
-
-# The span for aligning comments that end lines.
-#
-# 0 = Don't align (default).
-align_right_cmt_span = 2 # unsigned number
-
-# If aligning comments, whether to mix with comments after '}' and #endif with
-# less than three spaces before the comment.
-align_right_cmt_mix = false # true/false
-
-# Whether to only align trailing comments that are at the same brace level.
-align_right_cmt_same_level = false # true/false
-
-# Minimum number of columns between preceding text and a trailing comment in
-# order for the comment to qualify for being aligned. Must be non-zero to have
-# an effect.
-align_right_cmt_gap = 0 # unsigned number
-
-# Minimum column at which to align trailing comments. Comments which are
-# aligned beyond this column, but which can be aligned in a lesser column,
-# may be "pulled in".
-#
-# 0 = Ignore (default).
-align_right_cmt_at_col = 0 # unsigned number
-
-# The span for aligning function prototypes.
-#
-# 0 = Don't align (default).
-align_func_proto_span = 0 # unsigned number
-
-# Minimum gap between the return type and the function name.
-align_func_proto_gap = 0 # unsigned number
-
-# Whether to align function prototypes on the 'operator' keyword instead of
-# what follows.
-align_on_operator = false # true/false
-
-# Whether to mix aligning prototype and variable declarations. If true,
-# align_var_def_XXX options are used instead of align_func_proto_XXX options.
-align_mix_var_proto = false # true/false
-
-# Whether to align single-line functions with function prototypes.
-# Uses align_func_proto_span.
-align_single_line_func = false # true/false
-
-# Whether to align the open brace of single-line functions.
-# Requires align_single_line_func=true. Uses align_func_proto_span.
-align_single_line_brace = false # true/false
-
-# Gap for align_single_line_brace.
-align_single_line_brace_gap = 0 # unsigned number
-
-# (OC) The span for aligning Objective-C message specifications.
-#
-# 0 = Don't align (default).
-align_oc_msg_spec_span = 0 # unsigned number
-
-# Whether to align macros wrapped with a backslash and a newline. This will
-# not work right if the macro contains a multi-line comment.
-align_nl_cont = false # true/false
-
-# Whether to align macro functions and variables together.
-align_pp_define_together = false # true/false
-
-# The minimum space between label and value of a preprocessor define.
-align_pp_define_gap = 0 # unsigned number
-
-# The span for aligning on '#define' bodies.
-#
-# =0: Don't align (default)
-# >0: Number of lines (including comments) between blocks
-align_pp_define_span = 0 # unsigned number
-
-# Whether to align lines that start with '<<' with previous '<<'.
-#
-# Default: true
-align_left_shift = true # true/false
-
-# Whether to align text after 'asm volatile ()' colons.
-align_asm_colon = false # true/false
-
-# (OC) Span for aligning parameters in an Objective-C message call
-# on the ':'.
-#
-# 0 = Don't align.
-align_oc_msg_colon_span = 0 # unsigned number
-
-# (OC) Whether to always align with the first parameter, even if it is too
-# short.
-align_oc_msg_colon_first = false # true/false
-
-# (OC) Whether to align parameters in an Objective-C '+' or '-' declaration
-# on the ':'.
-align_oc_decl_colon = false # true/false
-
-#
-# Comment modification options
-#
-
-# Try to wrap comments at N columns.
-cmt_width = 0 # unsigned number
-
-# How to reflow comments.
-#
-# 0: No reflowing (apart from the line wrapping due to cmt_width) (default)
-# 1: No touching at all
-# 2: Full reflow
-cmt_reflow_mode = 0 # unsigned number
-
-# Whether to convert all tabs to spaces in comments. If false, tabs in
-# comments are left alone, unless used for indenting.
-cmt_convert_tab_to_spaces = true # true/false
-
-# Whether to apply changes to multi-line comments, including cmt_width,
-# keyword substitution and leading chars.
-#
-# Default: true
-cmt_indent_multi = true # true/false
-
-# Whether to group c-comments that look like they are in a block.
-cmt_c_group = false # true/false
-
-# Whether to put an empty '/*' on the first line of the combined c-comment.
-cmt_c_nl_start = false # true/false
-
-# Whether to add a newline before the closing '*/' of the combined c-comment.
-cmt_c_nl_end = false # true/false
-
-# Whether to change cpp-comments into c-comments.
-cmt_cpp_to_c = true # true/false
-
-# Whether to group cpp-comments that look like they are in a block. Only
-# meaningful if cmt_cpp_to_c=true.
-cmt_cpp_group = false # true/false
-
-# Whether to put an empty '/*' on the first line of the combined cpp-comment
-# when converting to a c-comment.
-#
-# Requires cmt_cpp_to_c=true and cmt_cpp_group=true.
-cmt_cpp_nl_start = false # true/false
-
-# Whether to add a newline before the closing '*/' of the combined cpp-comment
-# when converting to a c-comment.
-#
-# Requires cmt_cpp_to_c=true and cmt_cpp_group=true.
-cmt_cpp_nl_end = false # true/false
-
-# Whether to put a star on subsequent comment lines.
-cmt_star_cont = true # true/false
-
-# The number of spaces to insert at the start of subsequent comment lines.
-cmt_sp_before_star_cont = 0 # unsigned number
-
-# The number of spaces to insert after the star on subsequent comment lines.
-cmt_sp_after_star_cont = 0 # unsigned number
-
-# For multi-line comments with a '*' lead, remove leading spaces if the first
-# and last lines of the comment are the same length.
-#
-# Default: true
-cmt_multi_check_last = true # true/false
-
-# For multi-line comments with a '*' lead, remove leading spaces if the first
-# and last lines of the comment are the same length AND if the length is
-# bigger as the first_len minimum.
-#
-# Default: 4
-cmt_multi_first_len_minimum = 4 # unsigned number
-
-# Path to a file that contains text to insert at the beginning of a file if
-# the file doesn't start with a C/C++ comment. If the inserted text contains
-# '$(filename)', that will be replaced with the current file's name.
-cmt_insert_file_header = "" # string
-
-# Path to a file that contains text to insert at the end of a file if the
-# file doesn't end with a C/C++ comment. If the inserted text contains
-# '$(filename)', that will be replaced with the current file's name.
-cmt_insert_file_footer = "" # string
-
-# Path to a file that contains text to insert before a function definition if
-# the function isn't preceded by a C/C++ comment. If the inserted text
-# contains '$(function)', '$(javaparam)' or '$(fclass)', these will be
-# replaced with, respectively, the name of the function, the javadoc '@param'
-# and '@return' stuff, or the name of the class to which the member function
-# belongs.
-cmt_insert_func_header = "" # string
-
-# Path to a file that contains text to insert before a class if the class
-# isn't preceded by a C/C++ comment. If the inserted text contains '$(class)',
-# that will be replaced with the class name.
-cmt_insert_class_header = "" # string
-
-# Path to a file that contains text to insert before an Objective-C message
-# specification, if the method isn't preceded by a C/C++ comment. If the
-# inserted text contains '$(message)' or '$(javaparam)', these will be
-# replaced with, respectively, the name of the function, or the javadoc
-# '@param' and '@return' stuff.
-cmt_insert_oc_msg_header = "" # string
-
-# Whether a comment should be inserted if a preprocessor is encountered when
-# stepping backwards from a function name.
-#
-# Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and
-# cmt_insert_class_header.
-cmt_insert_before_preproc = false # true/false
-
-# Whether a comment should be inserted if a function is declared inline to a
-# class definition.
-#
-# Applies to cmt_insert_func_header.
-#
-# Default: true
-cmt_insert_before_inlines = true # true/false
-
-# Whether a comment should be inserted if the function is a class constructor
-# or destructor.
-#
-# Applies to cmt_insert_func_header.
-cmt_insert_before_ctor_dtor = false # true/false
-
-#
-# Code modifying options (non-whitespace)
-#
-
-# Add or remove braces on a single-line 'do' statement.
-mod_full_brace_do = add # ignore/add/remove/force
-
-# Add or remove braces on a single-line 'for' statement.
-mod_full_brace_for = add # ignore/add/remove/force
-
-# (Pawn) Add or remove braces on a single-line function definition.
-mod_full_brace_function = force # ignore/add/remove/force
-
-# Add or remove braces on a single-line 'if' statement. Braces will not be
-# removed if the braced statement contains an 'else'.
-mod_full_brace_if = add # ignore/add/remove/force
-
-# Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either
-# have, or do not have, braces. If true, braces will be added if any block
-# needs braces, and will only be removed if they can be removed from all
-# blocks.
-#
-# Overrides mod_full_brace_if.
-mod_full_brace_if_chain = false # true/false
-
-# Whether to add braces to all blocks of an 'if'/'else if'/'else' chain.
-# If true, mod_full_brace_if_chain will only remove braces from an 'if' that
-# does not have an 'else if' or 'else'.
-mod_full_brace_if_chain_only = true # true/false
-
-# Add or remove braces on single-line 'while' statement.
-mod_full_brace_while = ignore # ignore/add/remove/force
-
-# Add or remove braces on single-line 'using ()' statement.
-mod_full_brace_using = ignore # ignore/add/remove/force
-
-# Don't remove braces around statements that span N newlines
-mod_full_brace_nl = 0 # unsigned number
-
-# Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks
-# which span multiple lines.
-#
-# Affects:
-# mod_full_brace_for
-# mod_full_brace_if
-# mod_full_brace_if_chain
-# mod_full_brace_if_chain_only
-# mod_full_brace_while
-# mod_full_brace_using
-#
-# Does not affect:
-# mod_full_brace_do
-# mod_full_brace_function
-mod_full_brace_nl_block_rem_mlcond = false # true/false
-
-# Add or remove unnecessary parenthesis on 'return' statement.
-mod_paren_on_return = remove # ignore/add/remove/force
-
-# (Pawn) Whether to change optional semicolons to real semicolons.
-mod_pawn_semicolon = false # true/false
-
-# Whether to fully parenthesize Boolean expressions in 'while' and 'if'
-# statement, as in 'if (a && b > c)' → 'if (a && (b > c))'.
-mod_full_paren_if_bool = true # true/false
-
-# Whether to remove superfluous semicolons.
-mod_remove_extra_semicolon = true # true/false
-
-# If a function body exceeds the specified number of newlines and doesn't have
-# a comment after the close brace, a comment will be added.
-mod_add_long_function_closebrace_comment = 0 # unsigned number
-
-# If a namespace body exceeds the specified number of newlines and doesn't
-# have a comment after the close brace, a comment will be added.
-mod_add_long_namespace_closebrace_comment = 0 # unsigned number
-
-# If a class body exceeds the specified number of newlines and doesn't have a
-# comment after the close brace, a comment will be added.
-mod_add_long_class_closebrace_comment = 0 # unsigned number
-
-# If a switch body exceeds the specified number of newlines and doesn't have a
-# comment after the close brace, a comment will be added.
-mod_add_long_switch_closebrace_comment = 0 # unsigned number
-
-# If an #ifdef body exceeds the specified number of newlines and doesn't have
-# a comment after the #endif, a comment will be added.
-mod_add_long_ifdef_endif_comment = 0 # unsigned number
-
-# If an #ifdef or #else body exceeds the specified number of newlines and
-# doesn't have a comment after the #else, a comment will be added.
-mod_add_long_ifdef_else_comment = 0 # unsigned number
-
-# Whether to sort consecutive single-line 'import' statements.
-mod_sort_import = false # true/false
-
-# (C#) Whether to sort consecutive single-line 'using' statements.
-mod_sort_using = false # true/false
-
-# Whether to sort consecutive single-line '#include' statements (C/C++) and
-# '#import' statements (Objective-C). Be aware that this has the potential to
-# break your code if your includes/imports have ordering dependencies.
-mod_sort_include = false # true/false
-
-# Whether to move a 'break' that appears after a fully braced 'case' before
-# the close brace, as in 'case X: { ... } break;' → 'case X: { ... break; }'.
-mod_move_case_break = false # true/false
-
-# Add or remove braces around a fully braced case statement. Will only remove
-# braces if there are no variable declarations in the block.
-mod_case_brace = ignore # ignore/add/remove/force
-
-# Whether to remove a void 'return;' that appears as the last statement in a
-# function.
-mod_remove_empty_return = false # true/false
-
-# Add or remove the comma after the last value of an enumeration.
-mod_enum_last_comma = ignore # ignore/add/remove/force
-
-# (OC) Whether to organize the properties. If true, properties will be
-# rearranged according to the mod_sort_oc_property_*_weight factors.
-mod_sort_oc_properties = false # true/false
-
-# (OC) Weight of a class property modifier.
-mod_sort_oc_property_class_weight = 0 # number
-
-# (OC) Weight of 'atomic' and 'nonatomic'.
-mod_sort_oc_property_thread_safe_weight = 0 # number
-
-# (OC) Weight of 'readwrite' when organizing properties.
-mod_sort_oc_property_readwrite_weight = 0 # number
-
-# (OC) Weight of a reference type specifier ('retain', 'copy', 'assign',
-# 'weak', 'strong') when organizing properties.
-mod_sort_oc_property_reference_weight = 0 # number
-
-# (OC) Weight of getter type ('getter=') when organizing properties.
-mod_sort_oc_property_getter_weight = 0 # number
-
-# (OC) Weight of setter type ('setter=') when organizing properties.
-mod_sort_oc_property_setter_weight = 0 # number
-
-# (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified',
-# 'null_resettable') when organizing properties.
-mod_sort_oc_property_nullability_weight = 0 # number
-
-#
-# Preprocessor options
-#
-
-# Add or remove indentation of preprocessor directives inside #if blocks
-# at brace level 0 (file-level).
-pp_indent = remove # ignore/add/remove/force
-
-# Whether to indent #if/#else/#endif at the brace level. If false, these are
-# indented from column 1.
-pp_indent_at_level = false # true/false
-
-# Specifies the number of columns to indent preprocessors per level
-# at brace level 0 (file-level). If pp_indent_at_level=false, also specifies
-# the number of columns to indent preprocessors per level
-# at brace level > 0 (function-level).
-#
-# Default: 1
-pp_indent_count = 1 # unsigned number
-
-# Add or remove space after # based on pp_level of #if blocks.
-pp_space = remove # ignore/add/remove/force
-
-# Sets the number of spaces per level added with pp_space.
-pp_space_count = 3 # unsigned number
-
-# The indent for '#region' and '#endregion' in C# and '#pragma region' in
-# C/C++. Negative values decrease indent down to the first column.
-pp_indent_region = 0 # number
-
-# Whether to indent the code between #region and #endregion.
-pp_region_indent_code = false # true/false
-
-# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when
-# not at file-level. Negative values decrease indent down to the first column.
-#
-# =0: Indent preprocessors using output_tab_size
-# >0: Column at which all preprocessors will be indented
-pp_indent_if = 4 # number
-
-# Whether to indent the code between #if, #else and #endif.
-pp_if_indent_code = false # true/false
-
-# Whether to indent '#define' at the brace level. If false, these are
-# indented from column 1.
-pp_define_at_level = false # true/false
-
-# Whether to ignore the '#define' body while formatting.
-pp_ignore_define_body = false # true/false
-
-# Whether to indent case statements between #if, #else, and #endif.
-# Only applies to the indent of the preprocesser that the case statements
-# directly inside of.
-#
-# Default: true
-pp_indent_case = true # true/false
-
-# Whether to indent whole function definitions between #if, #else, and #endif.
-# Only applies to the indent of the preprocesser that the function definition
-# is directly inside of.
-#
-# Default: true
-pp_indent_func_def = true # true/false
-
-# Whether to indent extern C blocks between #if, #else, and #endif.
-# Only applies to the indent of the preprocesser that the extern block is
-# directly inside of.
-#
-# Default: true
-pp_indent_extern = true # true/false
-
-# Whether to indent braces directly inside #if, #else, and #endif.
-# Only applies to the indent of the preprocesser that the braces are directly
-# inside of.
-#
-# Default: true
-pp_indent_brace = true # true/false
-
-#
-# Sort includes options
-#
-
-# The regex for include category with priority 0.
-include_category_0 = "" # string
-
-# The regex for include category with priority 1.
-include_category_1 = "" # string
-
-# The regex for include category with priority 2.
-include_category_2 = "" # string
-
-#
-# Use or Do not Use options
-#
-
-# true: indent_func_call_param will be used (default)
-# false: indent_func_call_param will NOT be used
-#
-# Default: true
-use_indent_func_call_param = true # true/false
-
-# The value of the indentation for a continuation line is calculated
-# differently if the statement is:
-# - a declaration: your case with QString fileName ...
-# - an assignment: your case with pSettings = new QSettings( ...
-#
-# At the second case the indentation value might be used twice:
-# - at the assignment
-# - at the function call (if present)
-#
-# To prevent the double use of the indentation value, use this option with the
-# value 'true'.
-#
-# true: indent_continue will be used only once
-# false: indent_continue will be used every time (default)
-use_indent_continue_only_once = false # true/false
-
-# The value might be used twice:
-# - at the assignment
-# - at the opening brace
-#
-# To prevent the double use of the indentation value, use this option with the
-# value 'true'.
-#
-# true: indentation will be used only once
-# false: indentation will be used every time (default)
-indent_cpp_lambda_only_once = false # true/false
-
-# Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially,
-# this tries to format these so that they match Qt's normalized form (i.e. the
-# result of QMetaObject::normalizedSignature), which can slightly improve the
-# performance of the QObject::connect call, rather than how they would
-# otherwise be formatted.
-#
-# See options_for_QT.cpp for details.
-#
-# Default: true
-use_options_overriding_for_qt_macros = true # true/false
-
-#
-# Warn levels - 1: error, 2: warning (default), 3: note
-#
-
-# (C#) Warning is given if doing tab-to-\t replacement and we have found one
-# in a C# verbatim string literal.
-#
-# Default: 2
-warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number
-
-# Meaning of the settings:
-# Ignore - do not do any changes
-# Add - makes sure there is 1 or more space/brace/newline/etc
-# Force - makes sure there is exactly 1 space/brace/newline/etc,
-# behaves like Add in some contexts
-# Remove - removes space/brace/newline/etc
-#
-#
-# - Token(s) can be treated as specific type(s) with the 'set' option:
-# `set tokenType tokenString [tokenString...]`
-#
-# Example:
-# `set BOOL __AND__ __OR__`
-#
-# tokenTypes are defined in src/token_enum.h, use them without the
-# 'CT_' prefix: 'CT_BOOL' → 'BOOL'
-#
-#
-# - Token(s) can be treated as type(s) with the 'type' option.
-# `type tokenString [tokenString...]`
-#
-# Example:
-# `type int c_uint_8 Rectangle`
-#
-# This can also be achieved with `set TYPE int c_uint_8 Rectangle`
-#
-#
-# To embed whitespace in tokenStrings use the '\' escape character, or quote
-# the tokenStrings. These quotes are supported: "'`
-#
-#
-# - Support for the auto detection of languages through the file ending can be
-# added using the 'file_ext' command.
-# `file_ext langType langString [langString..]`
-#
-# Example:
-# `file_ext CPP .ch .cxx .cpp.in`
-#
-# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use
-# them without the 'LANG_' prefix: 'LANG_CPP' → 'CPP'
-#
-#
-# - Custom macro-based indentation can be set up using 'macro-open',
-# 'macro-else' and 'macro-close'.
-# `(macro-open | macro-else | macro-close) tokenString`
-#
-# Example:
-# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP`
-# `macro-open BEGIN_MESSAGE_MAP`
-# `macro-close END_MESSAGE_MAP`
-#
-#
-# option(s) with 'not default' value: 87
-#