diff --git a/docs/capi.rst b/docs/capi.rst index 646a5994..f5da3dab 100644 --- a/docs/capi.rst +++ b/docs/capi.rst @@ -510,6 +510,19 @@ Functions success another error code in case of error. The list of possible return codes vary according to the modules compiled into YARA. +.. c:function:: void yr_get_version(int* major, int* minor, int* micro) + + Get the version of the library loaded at runtime. The + :c:macro:`YR_MAJOR_VERSION`, :c:macro:`YR_MINOR_VERSION` and + :c:macro:`YR_MICRO_VERSION` macros are fixed when your program is compiled, + so a program linked against a shared ``libyara`` cannot use them to tell + which version it actually got. This function reports that. + + Any argument may be ``NULL`` if you do not need that component. Unlike the + rest of the API, this may be called before :c:func:`yr_initialize`. + + .. versionadded:: 4.6.0 + .. c:function:: int yr_compiler_create(YR_COMPILER** compiler) Create a YARA compiler. You must pass the address of a pointer to a diff --git a/libyara/include/yara/libyara.h b/libyara/include/yara/libyara.h index 1dad7fb6..334e71bf 100644 --- a/libyara/include/yara/libyara.h +++ b/libyara/include/yara/libyara.h @@ -87,6 +87,12 @@ YR_API int yr_initialize(void); YR_API int yr_finalize(void); +// Returns the version of the library actually loaded at runtime, which is not +// necessarily the one the caller was compiled against. Any of the arguments +// may be NULL if that component is not needed. Unlike the rest of the API this +// can be called before yr_initialize. +YR_API void yr_get_version(int* major, int* minor, int* micro); + YR_API int yr_set_configuration(YR_CONFIG_NAME, void*); YR_API int yr_set_configuration_uint32(YR_CONFIG_NAME, uint32_t); YR_API int yr_set_configuration_uint64(YR_CONFIG_NAME, uint64_t); diff --git a/libyara/libyara.c b/libyara/libyara.c index f8331f20..7379e133 100644 --- a/libyara/libyara.c +++ b/libyara/libyara.c @@ -546,4 +546,28 @@ YR_API int yr_get_configuration_uint64(YR_CONFIG_NAME name, uint64_t *value) default: return ERROR_INVALID_ARGUMENT; } -} \ No newline at end of file +} + +//////////////////////////////////////////////////////////////////////////////// +// Get the version of the library loaded at runtime. +// +// The YR_MAJOR_VERSION, YR_MINOR_VERSION and YR_MICRO_VERSION macros are fixed +// at compile time, so a program linked against libyara.so cannot use them to +// tell which version it ended up with. This function reports the version of +// the library that is actually loaded. +// +// Any argument may be NULL if the caller does not need that component. This +// function does not depend on any global state, so unlike the rest of the API +// it can be called before yr_initialize. +// +YR_API void yr_get_version(int *major, int *minor, int *micro) +{ + if (major != NULL) + *major = YR_MAJOR_VERSION; + + if (minor != NULL) + *minor = YR_MINOR_VERSION; + + if (micro != NULL) + *micro = YR_MICRO_VERSION; +} diff --git a/tests/test-version.c b/tests/test-version.c index 70b56a51..df6dbcaa 100644 --- a/tests/test-version.c +++ b/tests/test-version.c @@ -42,6 +42,28 @@ int main(int argc, char **argv) int result = strcmp(PACKAGE_VERSION, YR_VERSION); + // yr_get_version must report the same version the macros carry, and must + // work before yr_initialize and with any argument omitted. + + int major = -1, minor = -1, micro = -1; + + yr_get_version(&major, &minor, µ); + + if (major != YR_MAJOR_VERSION || minor != YR_MINOR_VERSION || + micro != YR_MICRO_VERSION) + result = 1; + + major = minor = micro = -1; + + yr_get_version(&major, NULL, NULL); + yr_get_version(NULL, &minor, NULL); + yr_get_version(NULL, NULL, µ); + yr_get_version(NULL, NULL, NULL); + + if (major != YR_MAJOR_VERSION || minor != YR_MINOR_VERSION || + micro != YR_MICRO_VERSION) + result = 1; + YR_DEBUG_FPRINTF( 1, stderr, "} = %d // %s() in %s\n", result, __FUNCTION__, argv[0]);