From 799820bf4b9208f76b290213f501f2cf2a9735dc Mon Sep 17 00:00:00 2001 From: Michal Minar Date: Tue, 25 Mar 2014 12:19:58 +0100 Subject: moved openlmicommon library to common/ subfolder --- src/CMakeLists.txt | 26 +--- src/common/CMakeLists.txt | 20 +++ src/common/openlmi.c | 384 ++++++++++++++++++++++++++++++++++++++++++++++ src/common/openlmi.conf | 22 +++ src/common/openlmi.h | 162 +++++++++++++++++++ src/common/openlmi.pc.in | 10 ++ src/openlmi.c | 384 ---------------------------------------------- src/openlmi.conf | 22 --- src/openlmi.h | 162 ------------------- src/openlmi.pc.in | 10 -- 10 files changed, 604 insertions(+), 598 deletions(-) create mode 100644 src/common/CMakeLists.txt create mode 100644 src/common/openlmi.c create mode 100644 src/common/openlmi.conf create mode 100644 src/common/openlmi.h create mode 100644 src/common/openlmi.pc.in delete mode 100644 src/openlmi.c delete mode 100644 src/openlmi.conf delete mode 100644 src/openlmi.h delete mode 100644 src/openlmi.pc.in diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index abca02d..888b59a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,24 +1,10 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMPI_INCLUDE_DIR} ${GLIB_INCLUDE_DIRS}) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + common + ${CMPI_INCLUDE_DIR} + ${GLIB_INCLUDE_DIRS}) -add_library(openlmicommon SHARED - openlmi.c -) - -target_link_libraries(openlmicommon ${GLIB_LIBRARIES} dl) - -set(OPENLMICOMMON_VERSION_MAJOR 0) -set(OPENLMICOMMON_VERSION_MINOR 0) -set(OPENLMICOMMON_VERSION_PATCH 1) -set(OPENLMICOMMON_VERSION "${OPENLMICOMMON_VERSION_MAJOR}.${OPENLMICOMMON_VERSION_MINOR}.${OPENLMICOMMON_VERSION_PATCH}") - -set_target_properties(openlmicommon PROPERTIES VERSION ${OPENLMICOMMON_VERSION}) -set_target_properties(openlmicommon PROPERTIES SOVERSION ${OPENLMICOMMON_VERSION_MAJOR}) - -install(TARGETS openlmicommon DESTINATION lib${LIB_SUFFIX}) -install(FILES openlmi.h DESTINATION include/openlmi) -configure_file(openlmi.pc.in ${CMAKE_CURRENT_BINARY_DIR}/openlmi.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openlmi.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig) -install(FILES openlmi.conf DESTINATION ${SYSCONF_INSTALL_DIR}/openlmi) +add_subdirectory(common) if (WITH-FAN) add_subdirectory(fan) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt new file mode 100644 index 0000000..129719f --- /dev/null +++ b/src/common/CMakeLists.txt @@ -0,0 +1,20 @@ +set(OPENLMICOMMON_VERSION_MAJOR 0) +set(OPENLMICOMMON_VERSION_MINOR 0) +set(OPENLMICOMMON_VERSION_PATCH 1) +set(OPENLMICOMMON_VERSION "${OPENLMICOMMON_VERSION_MAJOR}.${OPENLMICOMMON_VERSION_MINOR}.${OPENLMICOMMON_VERSION_PATCH}") + +configure_file(openlmi.pc.in ${CMAKE_CURRENT_BINARY_DIR}/openlmi.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openlmi.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig) +install(FILES openlmi.conf DESTINATION ${SYSCONF_INSTALL_DIR}/openlmi) + +add_library(openlmicommon SHARED + openlmi.c +) + +target_link_libraries(openlmicommon ${GLIB_LIBRARIES} dl) + +set_target_properties(openlmicommon PROPERTIES VERSION ${OPENLMICOMMON_VERSION}) +set_target_properties(openlmicommon PROPERTIES SOVERSION ${OPENLMICOMMON_VERSION_MAJOR}) + +install(TARGETS openlmicommon DESTINATION lib${LIB_SUFFIX}) +install(FILES openlmi.h DESTINATION include/openlmi) diff --git a/src/common/openlmi.c b/src/common/openlmi.c new file mode 100644 index 0000000..2391062 --- /dev/null +++ b/src/common/openlmi.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2012-2014 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Radek Novacek + */ + +#include "openlmi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *_system_name = NULL; +static CMPIObjectPath *_computer_system = NULL; +static const CMPIBroker *_cb = NULL; +static char *_provider = NULL; + +// Storage for all keys from configuration files and default configuration option +// Access needs to be mutexed +static GKeyFile *_masterKeyFile = NULL; + +// Mutex for running lmi_init +static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER; + +// Cache for SystemCreationClassName +static char *_system_creation_class_name = NULL; + +// Cache for log level +static int _log_level = _LMI_DEBUG_NONE; + +// Cache for log stderr +static bool _log_stderr = false; + +static ConfigEntry _toplevel_config_defaults[] = { + { "CIM", "Namespace", "root/cimv2" }, + { "CIM", "SystemClassName", "PG_ComputerSystem" }, + { "LOG", "Level", "ERROR" }, + { "LOG", "Stderr" , "false" }, + { NULL, NULL, NULL } +}; + +#define TOPLEVEL_CONFIG_FILE "/etc/openlmi/openlmi.conf" +#define PROVIDER_CONFIG_FILE "/etc/openlmi/%s/%s.conf" + +/** + * Enumerate configured ComputerSystem class in order to obtain + * ComputerSystem ObjectPath and Hostname + * + * @param cb CMPIBroker + * @param ctx CMPIContext + * @retval true Success + * @retval false Failure + */ +static bool get_computer_system(const CMPIBroker *cb, const CMPIContext *ctx) +{ + free(_system_name); + _system_name = NULL; + if (_computer_system != NULL) { + CMRelease(_computer_system); + _computer_system = NULL; + } + + const char *class_name = lmi_get_system_creation_class_name(); + char *namespace = lmi_read_config("CIM", "Namespace"); + CMPIStatus rc = { 0, NULL }; + CMPIObjectPath *op = CMNewObjectPath(cb, namespace, class_name, &rc); + g_free (namespace); + if (rc.rc != CMPI_RC_OK) { + lmi_error("Unable to create object path: %s", rc.msg); + return false; + } + CMPIEnumeration *en = CBEnumInstanceNames(cb, ctx, op, &rc); + if (rc.rc != CMPI_RC_OK) { + lmi_error("Unable to enumerate instance names of class %s", class_name); + return false; + } + + if (!CMHasNext(en, &rc)) { + lmi_error("No instance of class %s exists", class_name); + CMRelease(en); + return false; + } + CMPIData data = CMGetNext(en, &rc); + if (rc.rc != CMPI_RC_OK) { + lmi_error("Unable to get instance name of class %s", class_name); + CMRelease(en); + return false; + } + if (data.type != CMPI_ref) { + lmi_error("EnumInstanceNames didn't return CMPI_ref type, but %d", data.type); + CMRelease(en); + return false; + } + _computer_system = CMClone(data.value.ref, &rc); + if (rc.rc != CMPI_RC_OK) { + lmi_error("Unable to clone ComputerSystem object path"); + CMRelease(en); + return false; + } + _system_name = strdup(CMGetCharPtr(CMGetKey(_computer_system, "Name", &rc).value.string)); + CMRelease(en); + return true; +} + +CMPIObjectPath *lmi_get_computer_system(void) +{ + return _computer_system; +} + +const char *lmi_get_system_name(void) +{ + return _system_name; +} + +const char *lmi_get_system_creation_class_name(void) +{ + if (_system_creation_class_name == NULL) { + if (_masterKeyFile == NULL) { + lmi_error("Configuration was not read, using default option"); + return "PG_ComputerSystem"; + } + _system_creation_class_name = lmi_read_config("CIM", "SystemClassName"); + if (_system_creation_class_name == NULL) { + // This shouldn't happen, SystemClassName should be at least + // in default config keys + return "PG_ComputerSystem"; + } + } + return _system_creation_class_name; +} + +char *lmi_read_config(const char *group, const char *key) +{ + if (_masterKeyFile == NULL) { + lmi_warn("Attempted to read config file before calling lmi_init"); + return NULL; + } + return g_key_file_get_string(_masterKeyFile, group, key, NULL); +} + +bool lmi_read_config_boolean(const char *group, const char *key) +{ + char *value = lmi_read_config(group, key); + if (value == NULL) { + return false; + } + char *true_values[] = { "1", "yes", "true", "on" }; + size_t len = sizeof(true_values) / sizeof(true_values[0]); + for (size_t i = 0; i < len; ++i) { + if (strcasecmp(true_values[i], value) == 0) { + free(value); + return true; + } + } + free(value); + return false; +} + +void read_config(GKeyFile *keyFile, const ConfigEntry *config_dict) +{ + while (config_dict != NULL && config_dict->group != NULL && config_dict->key != NULL) { + if (!g_key_file_has_key(keyFile, config_dict->group, + config_dict->key, NULL)) { + + g_key_file_set_value(keyFile, config_dict->group, config_dict->key, + config_dict->value); + } + config_dict++; + } +} + +GKeyFile *parse_config(const char *provider_name, const ConfigEntry *provider_config_defaults) +{ + GError *error = NULL; + char *providerconf; + + // Get all configuration options to masterKeyFile + GKeyFile *masterKeyFile = g_key_file_new(); + + // Read top-level openlmi configuration + if (!g_key_file_load_from_file(masterKeyFile, TOPLEVEL_CONFIG_FILE, G_KEY_FILE_NONE, &error)) { + lmi_debug("Can't read openlmi top-level config file %s: %s", TOPLEVEL_CONFIG_FILE, error->message); + g_clear_error(&error); + } + + // Read provider-specific configuration + if (asprintf(&providerconf, PROVIDER_CONFIG_FILE, provider_name, provider_name) <= 0) { + lmi_error("Memory allocation failed"); + g_key_file_free(masterKeyFile); + return NULL; + } + GKeyFile *providerKeyFile; + if ((providerKeyFile = g_key_file_new()) == NULL) { + lmi_error("Memory allocation failed"); + g_key_file_free(masterKeyFile); + free(providerconf); + return NULL; + } + if (!g_key_file_load_from_file(providerKeyFile, providerconf, G_KEY_FILE_NONE, &error)) { + lmi_debug("Can't read provider specific config file %s: %s", providerconf, error->message); + g_clear_error(&error); + } + + // Merge provider config to _masterKeyFile + gsize groups_len, keys_len, i, j; + gchar *v; + gchar **groups = g_key_file_get_groups(providerKeyFile, &groups_len), **keys; + if (groups != NULL) { + for (i = 0; i < groups_len; ++i) { + keys = g_key_file_get_keys(providerKeyFile, groups[i], &keys_len, NULL); + for (j = 0; j < keys_len; ++j) { + v = g_key_file_get_value(providerKeyFile, groups[i], keys[j], NULL); + g_key_file_set_value(masterKeyFile, groups[i], keys[j], v); + free(v); + } + g_strfreev(keys); + } + g_strfreev(groups); + } + g_key_file_free(providerKeyFile); + + // Fill in default values where nothing gets read from config file. + // Provider-specific configs first + read_config(masterKeyFile, provider_config_defaults); + // Top-level configs + read_config(masterKeyFile, _toplevel_config_defaults); + + free(providerconf); + return masterKeyFile; +} + +void lmi_init(const char *provider, const CMPIBroker *cb, + const CMPIContext *ctx, + const ConfigEntry *provider_config_defaults) +{ + static void *glib_loaded = 0; + + pthread_mutex_lock(&_init_mutex); + // Broker can change between threads + _cb = cb; + + // Provider should remain the same + if (_provider != NULL) { + if (strcmp(_provider, provider) != 0) { + lmi_error("lmi_init called twice with different provider (%s -> %s), " + "this shouldn't happen", _provider, provider); + free(_provider); + } else { + pthread_mutex_unlock(&_init_mutex); + return; + } + } + _provider = strdup(provider); + if (_masterKeyFile != NULL) { + g_key_file_free(_masterKeyFile); + } + // Read config only on first call of this function + _masterKeyFile = parse_config(provider, provider_config_defaults); + // We might read different log config, reread it in next _log_debug call + _log_level = _LMI_DEBUG_NONE; + + // Read ComputerSystem instance + if (_computer_system == NULL || _system_name == NULL) { + get_computer_system(cb, ctx); + } + + /* + * Ugly hack to prevent Pegasus from crashing on cleanup. + * Glib2 adds some thread shutdown callback (see man pthread_key_create), + * but when cimprovagt destroys threads, this provider is already dlclosed(). + * So keep the libglib in memory so the callback does not crash. + * https://bugzilla.redhat.com/show_bug.cgi?id=1010238 + */ + if (!glib_loaded) { + glib_loaded = dlopen("libglib-2.0.so.0", RTLD_LAZY); + lmi_info("Loaded glib: %p\n", glib_loaded); + } + + pthread_mutex_unlock(&_init_mutex); +} + +int lmi_log_level(void) +{ + return _log_level; +} + +void lmi_set_log_level(int level) +{ + _log_level = level; +} + +void _lmi_debug(int level, const char *file, int line, const char *format, ...) +{ + const char *lvl[] = { "NONE", "ERROR", "WARNING", "INFO", "DEBUG" }; + if (_log_level == _LMI_DEBUG_NONE) { + // Read log level from config or default + _log_level = _LMI_DEBUG_ERROR; // Default + char *level = lmi_read_config("Log", "Level"); + if (level != NULL) { + size_t len = sizeof(lvl) / sizeof(lvl[0]); + for (size_t i = 0; i < len; ++i) { + if (strcasecmp(level, lvl[i]) == 0) { + _log_level = i; + break; + } + } + free(level); + } + + // Read if log to stderr + _log_stderr = lmi_read_config_boolean("Log", "Stderr"); + } + if (level > 4) { + level = 4; + } + if (level < 1) { + level = 1; + } + + if (level > _log_level) { + // Do not log this message + return; + } + + char *message, *text; + va_list args; + va_start(args, format); + vasprintf(&message, format, args); + va_end(args); + asprintf(&text, "[%s] %s:%d\t%s", lvl[level], file, line, message); + free(message); + + CMPIStatus rc; + rc.rc = CMPI_RC_OK; + if (_cb != NULL) { + // try to use standard CMPI logging + + // CMPI has different severity levels (1=info, 4=fatal) + int severity = CMPI_SEV_INFO; + switch (level) { + case _LMI_DEBUG_DEBUG: + severity = CMPI_DEV_DEBUG; + break; + case _LMI_DEBUG_INFO: + severity = CMPI_SEV_INFO; + break; + case _LMI_DEBUG_WARN: + severity = CMPI_SEV_WARNING; + break; + case _LMI_DEBUG_ERROR: + severity = CMPI_SEV_ERROR; + break; + } + rc = CMLogMessage(_cb, severity, _provider, text, NULL); + } + + if (_log_stderr || _cb == NULL || rc.rc != CMPI_RC_OK) { + // Fallback to stderr + fprintf(stderr, "%s\n", text); + } + free(text); +} diff --git a/src/common/openlmi.conf b/src/common/openlmi.conf new file mode 100644 index 0000000..64684a8 --- /dev/null +++ b/src/common/openlmi.conf @@ -0,0 +1,22 @@ +# Sample configuration file for OpenLMI providers + +[CIM] +# To override default CIM Namespace, uncomment the line below. +#Namespace = root/cimv2 + +# To change the CIM class of ComputerSystem, which is associated to many +# software classes, uncomment the line below. +#SystemClassName = PG_ComputerSystem + +[Log] +# These options modify logging configuration of the main process spawned +# by CIMOM. + +# Level can be set to following values: +# TRACE_VERBOSE, TRACE_INFO, TRACE_WARNING, DEBUG, INFO, WARNING, ERROR, CRITICAL +# It does not have any effect, if file_config option is set. +#Level = ERROR + +# If logging to stderr is desired, set this option to True. This option won't +# apply if file_config option is set. +#Stderr = False diff --git a/src/common/openlmi.h b/src/common/openlmi.h new file mode 100644 index 0000000..a46544c --- /dev/null +++ b/src/common/openlmi.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2012-2014 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Radek Novacek + */ + +#ifndef OPENLMI_H +#define OPENLMI_H + +#include +#include + +typedef struct { + const char *group; + const char *key; + const char *value; +} ConfigEntry; + +/** + * This function returns object path of an instance of CIM_ComputerSystem + * subclass. + * + * The instance is obtained by enumerating the configured ComputerSystem + * classname. + * + * @warning Call lmi_init function before calling this function! + * + * @return CIM_ComputerSystem object path + */ +CMPIObjectPath *lmi_get_computer_system(void); + +/** + * This function returns system name for the computer system + * + * @note Use this in the SystemName property of all provider created instances. + * + * @warning Call lmi_init function before calling this function! + * + * @return The scoping System's Name. + */ +const char *lmi_get_system_name(void); + +/** + * This function returns system creation class name + * + * @note Use this in the SystemCreationClassName property of all provider + * created instances. + * + * @return The scoping System's Creation class name. + */ +const char *lmi_get_system_creation_class_name(void); + +/** + * Initialize usage base openlmi tools like configuration file access, + * logging etc. + * + * @note You must call this function prior to getting any configuration option + * or usage of logging. lmi_get_system_creation_class_name requires that this + * function will be called first (SystemCreationClassName is read from config). + * + * This function is reentrant and thread safe, but it should be called always + * with same parameters + * + * @param provider Identification of the CIM provider (must be same as name of the + * configuration file) + * @param cb CMPIBroker + * @param ctx CMPIContext + * @param provider_config_defaults Array of default config values for given provider + * terminated by empty struct or NULL if there is no + * provider-specific configuration + */ +void lmi_init(const char *provider, const CMPIBroker *cb, + const CMPIContext *ctx, + const ConfigEntry *provider_config_defaults); + +/** + * Reads string key out of configration files or default configration options. + * + * @param group Configration group + * @param key Configration key + * @return String value of the key or NULL if group/key is not found + */ +char *lmi_read_config(const char *group, const char *key); + +/** + * Reads a boolean value out of configuration files or default configuration + * options. + * + * Values "1", "yes", "true", and "on" are converted to TRUE, others to FALSE + * + * @param group Configration group + * @param key Configration key + * @return Boolean value of the key, false if the key is not in the + * configuration files neither in default options. + */ +bool lmi_read_config_boolean(const char *group, const char *key); + +/** + * To use standard CIMOM logging facility, broker must be assigned. Without + * calling this function, logging will go to stderr. + * + * @deprecated Use lmi_init instead + * + * @param log_id Identification of log messages + * @param cb CMPIBroker + */ +void lmi_init_logging(const char *log_id, const CMPIBroker *cb); + +/** + * Get currently set logging level + * + * @return logging level + */ +int lmi_log_level(void); + +/** + * Set logging level + * + * @note This method shouldn't be used directly, user setting + * from the configuration file should be honored + * + * @param level new logging level + */ +void lmi_set_log_level(int level); + +/** + * Add an instance \p w to the result \p cr. + * + * @param cr CMPIResult where should be the instance added + * @param w instance to add + * @retval true if succeeds + * @retval false if addition fails + */ +#define LMI_ReturnInstance(cr, w) KOkay(__KReturnInstance((cr), &(w).__base)) + +enum { + _LMI_DEBUG_NONE=0, _LMI_DEBUG_ERROR, _LMI_DEBUG_WARN, + _LMI_DEBUG_INFO, _LMI_DEBUG_DEBUG +}; + +void _lmi_debug(int level, const char *file, int line, const char *format, ...); + +#define lmi_debug(...) _lmi_debug(_LMI_DEBUG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define lmi_info(...) _lmi_debug(_LMI_DEBUG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define lmi_warn(...) _lmi_debug(_LMI_DEBUG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define lmi_error(...) _lmi_debug(_LMI_DEBUG_ERROR, __FILE__, __LINE__, __VA_ARGS__) + +#endif diff --git a/src/common/openlmi.pc.in b/src/common/openlmi.pc.in new file mode 100644 index 0000000..939d672 --- /dev/null +++ b/src/common/openlmi.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib@LIB_SUFFIX@ + +Name: openlmi +Description: OpenLMI provider support +Version: @OPENLMICOMMON_VERSION@ +Libs: -L${libdir} -lopenlmicommon +CFlags: -I${includedir}/openlmi diff --git a/src/openlmi.c b/src/openlmi.c deleted file mode 100644 index 2391062..0000000 --- a/src/openlmi.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (C) 2012-2014 Red Hat, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Radek Novacek - */ - -#include "openlmi.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static char *_system_name = NULL; -static CMPIObjectPath *_computer_system = NULL; -static const CMPIBroker *_cb = NULL; -static char *_provider = NULL; - -// Storage for all keys from configuration files and default configuration option -// Access needs to be mutexed -static GKeyFile *_masterKeyFile = NULL; - -// Mutex for running lmi_init -static pthread_mutex_t _init_mutex = PTHREAD_MUTEX_INITIALIZER; - -// Cache for SystemCreationClassName -static char *_system_creation_class_name = NULL; - -// Cache for log level -static int _log_level = _LMI_DEBUG_NONE; - -// Cache for log stderr -static bool _log_stderr = false; - -static ConfigEntry _toplevel_config_defaults[] = { - { "CIM", "Namespace", "root/cimv2" }, - { "CIM", "SystemClassName", "PG_ComputerSystem" }, - { "LOG", "Level", "ERROR" }, - { "LOG", "Stderr" , "false" }, - { NULL, NULL, NULL } -}; - -#define TOPLEVEL_CONFIG_FILE "/etc/openlmi/openlmi.conf" -#define PROVIDER_CONFIG_FILE "/etc/openlmi/%s/%s.conf" - -/** - * Enumerate configured ComputerSystem class in order to obtain - * ComputerSystem ObjectPath and Hostname - * - * @param cb CMPIBroker - * @param ctx CMPIContext - * @retval true Success - * @retval false Failure - */ -static bool get_computer_system(const CMPIBroker *cb, const CMPIContext *ctx) -{ - free(_system_name); - _system_name = NULL; - if (_computer_system != NULL) { - CMRelease(_computer_system); - _computer_system = NULL; - } - - const char *class_name = lmi_get_system_creation_class_name(); - char *namespace = lmi_read_config("CIM", "Namespace"); - CMPIStatus rc = { 0, NULL }; - CMPIObjectPath *op = CMNewObjectPath(cb, namespace, class_name, &rc); - g_free (namespace); - if (rc.rc != CMPI_RC_OK) { - lmi_error("Unable to create object path: %s", rc.msg); - return false; - } - CMPIEnumeration *en = CBEnumInstanceNames(cb, ctx, op, &rc); - if (rc.rc != CMPI_RC_OK) { - lmi_error("Unable to enumerate instance names of class %s", class_name); - return false; - } - - if (!CMHasNext(en, &rc)) { - lmi_error("No instance of class %s exists", class_name); - CMRelease(en); - return false; - } - CMPIData data = CMGetNext(en, &rc); - if (rc.rc != CMPI_RC_OK) { - lmi_error("Unable to get instance name of class %s", class_name); - CMRelease(en); - return false; - } - if (data.type != CMPI_ref) { - lmi_error("EnumInstanceNames didn't return CMPI_ref type, but %d", data.type); - CMRelease(en); - return false; - } - _computer_system = CMClone(data.value.ref, &rc); - if (rc.rc != CMPI_RC_OK) { - lmi_error("Unable to clone ComputerSystem object path"); - CMRelease(en); - return false; - } - _system_name = strdup(CMGetCharPtr(CMGetKey(_computer_system, "Name", &rc).value.string)); - CMRelease(en); - return true; -} - -CMPIObjectPath *lmi_get_computer_system(void) -{ - return _computer_system; -} - -const char *lmi_get_system_name(void) -{ - return _system_name; -} - -const char *lmi_get_system_creation_class_name(void) -{ - if (_system_creation_class_name == NULL) { - if (_masterKeyFile == NULL) { - lmi_error("Configuration was not read, using default option"); - return "PG_ComputerSystem"; - } - _system_creation_class_name = lmi_read_config("CIM", "SystemClassName"); - if (_system_creation_class_name == NULL) { - // This shouldn't happen, SystemClassName should be at least - // in default config keys - return "PG_ComputerSystem"; - } - } - return _system_creation_class_name; -} - -char *lmi_read_config(const char *group, const char *key) -{ - if (_masterKeyFile == NULL) { - lmi_warn("Attempted to read config file before calling lmi_init"); - return NULL; - } - return g_key_file_get_string(_masterKeyFile, group, key, NULL); -} - -bool lmi_read_config_boolean(const char *group, const char *key) -{ - char *value = lmi_read_config(group, key); - if (value == NULL) { - return false; - } - char *true_values[] = { "1", "yes", "true", "on" }; - size_t len = sizeof(true_values) / sizeof(true_values[0]); - for (size_t i = 0; i < len; ++i) { - if (strcasecmp(true_values[i], value) == 0) { - free(value); - return true; - } - } - free(value); - return false; -} - -void read_config(GKeyFile *keyFile, const ConfigEntry *config_dict) -{ - while (config_dict != NULL && config_dict->group != NULL && config_dict->key != NULL) { - if (!g_key_file_has_key(keyFile, config_dict->group, - config_dict->key, NULL)) { - - g_key_file_set_value(keyFile, config_dict->group, config_dict->key, - config_dict->value); - } - config_dict++; - } -} - -GKeyFile *parse_config(const char *provider_name, const ConfigEntry *provider_config_defaults) -{ - GError *error = NULL; - char *providerconf; - - // Get all configuration options to masterKeyFile - GKeyFile *masterKeyFile = g_key_file_new(); - - // Read top-level openlmi configuration - if (!g_key_file_load_from_file(masterKeyFile, TOPLEVEL_CONFIG_FILE, G_KEY_FILE_NONE, &error)) { - lmi_debug("Can't read openlmi top-level config file %s: %s", TOPLEVEL_CONFIG_FILE, error->message); - g_clear_error(&error); - } - - // Read provider-specific configuration - if (asprintf(&providerconf, PROVIDER_CONFIG_FILE, provider_name, provider_name) <= 0) { - lmi_error("Memory allocation failed"); - g_key_file_free(masterKeyFile); - return NULL; - } - GKeyFile *providerKeyFile; - if ((providerKeyFile = g_key_file_new()) == NULL) { - lmi_error("Memory allocation failed"); - g_key_file_free(masterKeyFile); - free(providerconf); - return NULL; - } - if (!g_key_file_load_from_file(providerKeyFile, providerconf, G_KEY_FILE_NONE, &error)) { - lmi_debug("Can't read provider specific config file %s: %s", providerconf, error->message); - g_clear_error(&error); - } - - // Merge provider config to _masterKeyFile - gsize groups_len, keys_len, i, j; - gchar *v; - gchar **groups = g_key_file_get_groups(providerKeyFile, &groups_len), **keys; - if (groups != NULL) { - for (i = 0; i < groups_len; ++i) { - keys = g_key_file_get_keys(providerKeyFile, groups[i], &keys_len, NULL); - for (j = 0; j < keys_len; ++j) { - v = g_key_file_get_value(providerKeyFile, groups[i], keys[j], NULL); - g_key_file_set_value(masterKeyFile, groups[i], keys[j], v); - free(v); - } - g_strfreev(keys); - } - g_strfreev(groups); - } - g_key_file_free(providerKeyFile); - - // Fill in default values where nothing gets read from config file. - // Provider-specific configs first - read_config(masterKeyFile, provider_config_defaults); - // Top-level configs - read_config(masterKeyFile, _toplevel_config_defaults); - - free(providerconf); - return masterKeyFile; -} - -void lmi_init(const char *provider, const CMPIBroker *cb, - const CMPIContext *ctx, - const ConfigEntry *provider_config_defaults) -{ - static void *glib_loaded = 0; - - pthread_mutex_lock(&_init_mutex); - // Broker can change between threads - _cb = cb; - - // Provider should remain the same - if (_provider != NULL) { - if (strcmp(_provider, provider) != 0) { - lmi_error("lmi_init called twice with different provider (%s -> %s), " - "this shouldn't happen", _provider, provider); - free(_provider); - } else { - pthread_mutex_unlock(&_init_mutex); - return; - } - } - _provider = strdup(provider); - if (_masterKeyFile != NULL) { - g_key_file_free(_masterKeyFile); - } - // Read config only on first call of this function - _masterKeyFile = parse_config(provider, provider_config_defaults); - // We might read different log config, reread it in next _log_debug call - _log_level = _LMI_DEBUG_NONE; - - // Read ComputerSystem instance - if (_computer_system == NULL || _system_name == NULL) { - get_computer_system(cb, ctx); - } - - /* - * Ugly hack to prevent Pegasus from crashing on cleanup. - * Glib2 adds some thread shutdown callback (see man pthread_key_create), - * but when cimprovagt destroys threads, this provider is already dlclosed(). - * So keep the libglib in memory so the callback does not crash. - * https://bugzilla.redhat.com/show_bug.cgi?id=1010238 - */ - if (!glib_loaded) { - glib_loaded = dlopen("libglib-2.0.so.0", RTLD_LAZY); - lmi_info("Loaded glib: %p\n", glib_loaded); - } - - pthread_mutex_unlock(&_init_mutex); -} - -int lmi_log_level(void) -{ - return _log_level; -} - -void lmi_set_log_level(int level) -{ - _log_level = level; -} - -void _lmi_debug(int level, const char *file, int line, const char *format, ...) -{ - const char *lvl[] = { "NONE", "ERROR", "WARNING", "INFO", "DEBUG" }; - if (_log_level == _LMI_DEBUG_NONE) { - // Read log level from config or default - _log_level = _LMI_DEBUG_ERROR; // Default - char *level = lmi_read_config("Log", "Level"); - if (level != NULL) { - size_t len = sizeof(lvl) / sizeof(lvl[0]); - for (size_t i = 0; i < len; ++i) { - if (strcasecmp(level, lvl[i]) == 0) { - _log_level = i; - break; - } - } - free(level); - } - - // Read if log to stderr - _log_stderr = lmi_read_config_boolean("Log", "Stderr"); - } - if (level > 4) { - level = 4; - } - if (level < 1) { - level = 1; - } - - if (level > _log_level) { - // Do not log this message - return; - } - - char *message, *text; - va_list args; - va_start(args, format); - vasprintf(&message, format, args); - va_end(args); - asprintf(&text, "[%s] %s:%d\t%s", lvl[level], file, line, message); - free(message); - - CMPIStatus rc; - rc.rc = CMPI_RC_OK; - if (_cb != NULL) { - // try to use standard CMPI logging - - // CMPI has different severity levels (1=info, 4=fatal) - int severity = CMPI_SEV_INFO; - switch (level) { - case _LMI_DEBUG_DEBUG: - severity = CMPI_DEV_DEBUG; - break; - case _LMI_DEBUG_INFO: - severity = CMPI_SEV_INFO; - break; - case _LMI_DEBUG_WARN: - severity = CMPI_SEV_WARNING; - break; - case _LMI_DEBUG_ERROR: - severity = CMPI_SEV_ERROR; - break; - } - rc = CMLogMessage(_cb, severity, _provider, text, NULL); - } - - if (_log_stderr || _cb == NULL || rc.rc != CMPI_RC_OK) { - // Fallback to stderr - fprintf(stderr, "%s\n", text); - } - free(text); -} diff --git a/src/openlmi.conf b/src/openlmi.conf deleted file mode 100644 index 64684a8..0000000 --- a/src/openlmi.conf +++ /dev/null @@ -1,22 +0,0 @@ -# Sample configuration file for OpenLMI providers - -[CIM] -# To override default CIM Namespace, uncomment the line below. -#Namespace = root/cimv2 - -# To change the CIM class of ComputerSystem, which is associated to many -# software classes, uncomment the line below. -#SystemClassName = PG_ComputerSystem - -[Log] -# These options modify logging configuration of the main process spawned -# by CIMOM. - -# Level can be set to following values: -# TRACE_VERBOSE, TRACE_INFO, TRACE_WARNING, DEBUG, INFO, WARNING, ERROR, CRITICAL -# It does not have any effect, if file_config option is set. -#Level = ERROR - -# If logging to stderr is desired, set this option to True. This option won't -# apply if file_config option is set. -#Stderr = False diff --git a/src/openlmi.h b/src/openlmi.h deleted file mode 100644 index a46544c..0000000 --- a/src/openlmi.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2012-2014 Red Hat, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Radek Novacek - */ - -#ifndef OPENLMI_H -#define OPENLMI_H - -#include -#include - -typedef struct { - const char *group; - const char *key; - const char *value; -} ConfigEntry; - -/** - * This function returns object path of an instance of CIM_ComputerSystem - * subclass. - * - * The instance is obtained by enumerating the configured ComputerSystem - * classname. - * - * @warning Call lmi_init function before calling this function! - * - * @return CIM_ComputerSystem object path - */ -CMPIObjectPath *lmi_get_computer_system(void); - -/** - * This function returns system name for the computer system - * - * @note Use this in the SystemName property of all provider created instances. - * - * @warning Call lmi_init function before calling this function! - * - * @return The scoping System's Name. - */ -const char *lmi_get_system_name(void); - -/** - * This function returns system creation class name - * - * @note Use this in the SystemCreationClassName property of all provider - * created instances. - * - * @return The scoping System's Creation class name. - */ -const char *lmi_get_system_creation_class_name(void); - -/** - * Initialize usage base openlmi tools like configuration file access, - * logging etc. - * - * @note You must call this function prior to getting any configuration option - * or usage of logging. lmi_get_system_creation_class_name requires that this - * function will be called first (SystemCreationClassName is read from config). - * - * This function is reentrant and thread safe, but it should be called always - * with same parameters - * - * @param provider Identification of the CIM provider (must be same as name of the - * configuration file) - * @param cb CMPIBroker - * @param ctx CMPIContext - * @param provider_config_defaults Array of default config values for given provider - * terminated by empty struct or NULL if there is no - * provider-specific configuration - */ -void lmi_init(const char *provider, const CMPIBroker *cb, - const CMPIContext *ctx, - const ConfigEntry *provider_config_defaults); - -/** - * Reads string key out of configration files or default configration options. - * - * @param group Configration group - * @param key Configration key - * @return String value of the key or NULL if group/key is not found - */ -char *lmi_read_config(const char *group, const char *key); - -/** - * Reads a boolean value out of configuration files or default configuration - * options. - * - * Values "1", "yes", "true", and "on" are converted to TRUE, others to FALSE - * - * @param group Configration group - * @param key Configration key - * @return Boolean value of the key, false if the key is not in the - * configuration files neither in default options. - */ -bool lmi_read_config_boolean(const char *group, const char *key); - -/** - * To use standard CIMOM logging facility, broker must be assigned. Without - * calling this function, logging will go to stderr. - * - * @deprecated Use lmi_init instead - * - * @param log_id Identification of log messages - * @param cb CMPIBroker - */ -void lmi_init_logging(const char *log_id, const CMPIBroker *cb); - -/** - * Get currently set logging level - * - * @return logging level - */ -int lmi_log_level(void); - -/** - * Set logging level - * - * @note This method shouldn't be used directly, user setting - * from the configuration file should be honored - * - * @param level new logging level - */ -void lmi_set_log_level(int level); - -/** - * Add an instance \p w to the result \p cr. - * - * @param cr CMPIResult where should be the instance added - * @param w instance to add - * @retval true if succeeds - * @retval false if addition fails - */ -#define LMI_ReturnInstance(cr, w) KOkay(__KReturnInstance((cr), &(w).__base)) - -enum { - _LMI_DEBUG_NONE=0, _LMI_DEBUG_ERROR, _LMI_DEBUG_WARN, - _LMI_DEBUG_INFO, _LMI_DEBUG_DEBUG -}; - -void _lmi_debug(int level, const char *file, int line, const char *format, ...); - -#define lmi_debug(...) _lmi_debug(_LMI_DEBUG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -#define lmi_info(...) _lmi_debug(_LMI_DEBUG_INFO, __FILE__, __LINE__, __VA_ARGS__) -#define lmi_warn(...) _lmi_debug(_LMI_DEBUG_WARN, __FILE__, __LINE__, __VA_ARGS__) -#define lmi_error(...) _lmi_debug(_LMI_DEBUG_ERROR, __FILE__, __LINE__, __VA_ARGS__) - -#endif diff --git a/src/openlmi.pc.in b/src/openlmi.pc.in deleted file mode 100644 index 939d672..0000000 --- a/src/openlmi.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -includedir=${prefix}/include -libdir=${exec_prefix}/lib@LIB_SUFFIX@ - -Name: openlmi -Description: OpenLMI provider support -Version: @OPENLMICOMMON_VERSION@ -Libs: -L${libdir} -lopenlmicommon -CFlags: -I${includedir}/openlmi -- cgit