diff --git a/CMakeLists.txt b/CMakeLists.txt index 842bb99ff..78b3d4895 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -236,6 +236,7 @@ set(STUMPLESS_SOURCES ${PROJECT_SOURCE_DIR}/src/target/stream.c ${PROJECT_SOURCE_DIR}/src/version.c ${PROJECT_SOURCE_DIR}/src/validate.c + ${PROJECT_SOURCE_DIR}/src/priority.c ) @@ -645,6 +646,7 @@ install(FILES ${PROJECT_SOURCE_DIR}/include/stumpless/severity.h ${PROJECT_SOURCE_DIR}/include/stumpless/target.h ${PROJECT_SOURCE_DIR}/include/stumpless/version.h + ${PROJECT_SOURCE_DIR}/include/stumpless/priority.h DESTINATION "include/stumpless" ) @@ -957,6 +959,10 @@ add_function_test(version SOURCES test/function/version.cpp ) +add_function_test(priority + SOURCES test/function/priority.cpp +) + add_custom_target(build-test DEPENDS ${STUMPLESS_FUNCTION_TESTS} ) diff --git a/include/stumpless.h b/include/stumpless.h index cbc8db58f..e08220e63 100644 --- a/include/stumpless.h +++ b/include/stumpless.h @@ -99,6 +99,7 @@ #include #include #include +#include #ifdef STUMPLESS_JOURNALD_TARGETS_SUPPORTED /** @example journald_example.c diff --git a/include/stumpless/priority.h b/include/stumpless/priority.h new file mode 100644 index 000000000..2f65ad906 --- /dev/null +++ b/include/stumpless/priority.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* + * Copyright 2022 Joel E. Anderson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file + * Priority value (PRIVAL) represents both the Facility and Severity values. + * + * @since release v2.2.0 + */ + +#ifndef __STUMPLESS_PRIORITY_H +# define __STUMPLESS_PRIORITY_H + +# include + +# ifdef __cplusplus +extern "C" { +# endif + +/** + * Extract PRIVAL number (Facility and Severity) from the given string with + * the direct number or with two names divided with a period in the order: + * facility first, then severity ("."). + * + * **Thread Safety: MT-Safe** + * This function is thread safe. A mutex is used to coordinate changes to the + * target while it is being read. + * + * **Async Signal Safety: AS-Unsafe lock** + * This function is not safe to call from signal handlers due to the use of a + * non-reentrant lock to coordinate the read of the target. + * + * **Async Cancel Safety: AC-Unsafe lock** + * This function is not safe to call from threads that may be asynchronously + * cancelled, due to the use of a lock that could be left locked.. + * + * @since release v2.2.0 + * + * @param string The string to extract the prival from. + * + * @return the PRIVAL number used for the severity and facility values of + * the logged entry, in the event of an error it returns -1. + */ +STUMPLESS_PUBLIC_FUNCTION +int +stumpless_prival_from_string( const char *string ); + +# ifdef __cplusplus +} /* extern "C" */ +# endif + +#endif /* __STUMPLESS_PRIORITY_H */ diff --git a/src/priority.c b/src/priority.c new file mode 100644 index 000000000..d6cb0e10e --- /dev/null +++ b/src/priority.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + * Copyright 2022 Joel E. Anderson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "private/memory.h" +#include "private/entry.h" +#include "private/validate.h" +#include "private/config.h" + +static void toUpperCase( char *str ) { + for( int i = 0; str[i]; i++) { + str[i] = toupper( str[i] ); + } +} + +int +stumpless_prival_from_string( const char *string ) { + int prival; + int severity; + int facility; + char *param; + char *period; + char *sec_period; + size_t len; + size_t slen; + size_t pre_len; + const char pre_facility[] = "STUMPLESS_FACILITY_"; + const char pre_severity[] = "STUMPLESS_SEVERITY_"; + + VALIDATE_ARG_NOT_NULL_INT_RETURN( string ); + + if( unlikely( !string[0] ) ) { + return -1; + } + + slen = strlen( string ); + + if( isdigit( string[0] ) ) { + prival = atoi( string ); + if( prival >= 0 && prival <= 191 && slen < 4 ) { + return prival; + } + } + + // find the first period character + period = strchr( string, '.' ); + if( !period ) + return -1; + + // check there is no another period character + sec_period = strchr( period + 1, '.' ); + if( sec_period != NULL ) { + return -1; + } + + // Calculate the facility length, up to the first period character + len = period - string; + pre_len = sizeof(pre_facility) - 1; + param = alloc_mem( len + 1 + pre_len ); + if( !param ) { + return -1; + } + // Copy the facility substring to the param buffer + memcpy( param, pre_facility, pre_len ); + memcpy( param + pre_len, string, len ); + param[pre_len + len] = '\0'; + + toUpperCase(param); + facility = stumpless_get_facility_enum( param ); + + free_mem( param ); + + if( facility < 0 ) + return -1; + + // Calculate the severity length + len = slen - ++len; + pre_len = sizeof(pre_severity) - 1; + + param = alloc_mem( len + 1 + pre_len ); + if( !param ) { + return -1; + } + // Copy the severity substring to the param buffer + memcpy( param, pre_severity, pre_len ); + memcpy( param + pre_len, ++period, len); + param[pre_len + len] = '\0'; + + toUpperCase(param); + severity = stumpless_get_severity_enum( param ); + + free_mem( param ); + + if( severity < 0 ) + return -1; + + return get_prival( facility, severity ); +} + diff --git a/src/windows/stumpless.def b/src/windows/stumpless.def index 082988721..310633732 100644 --- a/src/windows/stumpless.def +++ b/src/windows/stumpless.def @@ -223,3 +223,4 @@ EXPORTS stumpless_unload_entry_only @206 stumpless_unload_param @207 vstumpless_load_entry @208 + stumpless_prival_from_string @209 diff --git a/test/function/README.md b/test/function/README.md index 72e716296..0e2796998 100644 --- a/test/function/README.md +++ b/test/function/README.md @@ -57,3 +57,7 @@ Tests for general target functionality. ## `version.cpp` Tests for versioning of the library. + + +## `priority.cpp` +Tests for functions that deal with priority values (PRIVAL). diff --git a/test/function/priority.cpp b/test/function/priority.cpp new file mode 100644 index 000000000..7fb2feb8f --- /dev/null +++ b/test/function/priority.cpp @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + * Copyright 2019-2021 Joel E. Anderson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "test/helper/assert.hpp" +#include "test/helper/memory_allocation.hpp" + +namespace { + + class PriorityTest : public::testing::Test { + }; + + TEST( GetPriorityValue, NumValidPriority ) { + int result; + + result = stumpless_prival_from_string( "119" ); + EXPECT_EQ( result, 119 ); + } + + TEST( GetPriorityValue, UpperValidPriority ) { + int result; + + result = stumpless_prival_from_string( "USER.INFO" ); + EXPECT_EQ( result, 14 ); + } + + TEST( GetPriorityValue, LowerValidPriority ) { + int result; + + result = stumpless_prival_from_string( "user.info" ); + EXPECT_EQ( result, 14 ); + } + + TEST( GetPriorityValue, EmptyPriority ) { + int result; + + result = stumpless_prival_from_string( "" ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, NullPriority ) { + int result; + + result = stumpless_prival_from_string( NULL ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, InvalidFacilityPriority ) { + int result; + + result = stumpless_prival_from_string( "umer.info" ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, InvalidSeverityPriority ) { + int result; + + result = stumpless_prival_from_string( "user.imfo" ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, InvalidNoPeriodPriority ) { + int result; + + result = stumpless_prival_from_string( "userinfo" ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, InvalidMorePeriodPriority ) { + int result; + + result = stumpless_prival_from_string( "user.info." ); + EXPECT_EQ( result, -1 ); + } + + TEST( GetPriorityValue, InvalidMemFacilityPriority ) { + int result; + void * (*set_malloc_result)(size_t); + set_malloc_result = stumpless_set_malloc( MALLOC_FAIL ); + ASSERT_NOT_NULL( set_malloc_result ); + + result = stumpless_prival_from_string( "user.err" ); + EXPECT_EQ( result, -1 ); + + set_malloc_result = stumpless_set_malloc( malloc ); + EXPECT_TRUE( set_malloc_result == malloc ); + } + + TEST( GetPriorityValue, InvalidMemSeverityPriority ) { + int result; + void * (*set_malloc_result)(size_t); + const struct stumpless_error *error; + set_malloc_result = stumpless_set_malloc( MALLOC_FAIL_ON_SIZE( 23 ) ); + ASSERT_NOT_NULL( set_malloc_result ); + + result = stumpless_prival_from_string( "syslog.err" ); + EXPECT_EQ( result, -1 ); + + EXPECT_ERROR_ID_EQ( STUMPLESS_MEMORY_ALLOCATION_FAILURE ); + + set_malloc_result = stumpless_set_malloc( malloc ); + EXPECT_TRUE( set_malloc_result == malloc ); + } + +} diff --git a/tools/check_headers/standard_library.yml b/tools/check_headers/standard_library.yml index d7ee3f8a0..ff75ef9a0 100644 --- a/tools/check_headers/standard_library.yml +++ b/tools/check_headers/standard_library.yml @@ -230,3 +230,5 @@ "WSACleanup": - "winsock2.h" - "private/windows_wrapper.h" +"isdigit": "ctype.h" +"toupper": "ctype.h" diff --git a/tools/check_headers/stumpless.yml b/tools/check_headers/stumpless.yml index dcddd109e..3e774397b 100644 --- a/tools/check_headers/stumpless.yml +++ b/tools/check_headers/stumpless.yml @@ -628,3 +628,4 @@ "stumpless_get_target_type_string" : "stumpless/target.h" "STUMPLESS_FOREACH_TARGET_TYPE" : "stumpless/target.h" "STUMPLESS_FOREACH_SEVERITY" : "stumpless/severity.h" +"stumpless_prival_from_string" : "stumpless/priority.h" diff --git a/tools/wrapture/priority.yml b/tools/wrapture/priority.yml new file mode 100644 index 000000000..d18084bf2 --- /dev/null +++ b/tools/wrapture/priority.yml @@ -0,0 +1,33 @@ +version: "0.5.0" +classes: + - name: "Priority" + doc: > + PRIVAL as priority value (as defined in RFC 5424) represents both the + Facility and Severity. + The Priority value consists of one, two, or three decimal integers. + namespace: "stumpless" + functions: + - name: "GetOption" + doc: > + Gets the given option for this target. + + While the returned value is the option if it is set, callers can also + simply use the truth value of the return to see if the provided option + is set. + params: + - name: "option" + doc: "The option to check this target for." + type: "int" + return: + doc: > + The option if it is set on the target. If the option is not set, + then zero is returned. + type: "int" + wrapped-function: + name: "stumpless_get_option" + includes: "stumpless/target.h" + params: + - value: "equivalent-struct-pointer" + - value: "option" + return: + type: "int"