diff options
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 @@ -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) @@ -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 = ¤t; 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(¶ms->dlt_free_mtx); + pthread_cond_signal(¶ms->dlt_free_done); + pthread_mutex_unlock(¶ms->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(¶ms->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(¶ms->dlt_free_done, ¶ms->dlt_free_mtx, &abs_time); + pthread_mutex_unlock(¶ms->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 -# |