%files test
# API test
%{_bindir}/system_info_test
+# Init DB test
+%{_bindir}/system_info_init_db_test
# Plugin test
%attr(0755,root,-) %{_bindir}/system_info_external_plugin_test.sh
%{_libdir}/libsystem_info_plugins/libsystem_info_test_plugin.so
SET(TESTS
api
+ init_db
plugin
)
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+SET(INIT_DB_TEST "system_info_init_db_test")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SRCS)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(init_db_test_pkgs REQUIRED
+ libxml-2.0
+)
+
+FOREACH(flag ${init_db_test_pkgs_CXXFLAGS})
+ SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} -g -fno-omit-frame-pointer -finstrument-functions -fpie")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS}")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+
+ADD_EXECUTABLE(${INIT_DB_TEST} ${SRCS})
+ADD_DEPENDENCIES(${INIT_DB_TEST} ${fw_name})
+TARGET_LINK_LIBRARIES(${INIT_DB_TEST} ${init_db_test_pkgs_LDFLAGS} "-L${CMAKE_SOURCE_DIR} -lcapi-system-info")
+
+INSTALL(TARGETS ${INIT_DB_TEST} DESTINATION bin)
--- /dev/null
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <climits>
+#include <cstdlib>
+#include <string>
+#include <sstream>
+
+#include <system_info.h>
+
+#include "system_info_init_db_test.h"
+#include "feature.h"
+#include "util.h"
+
+/********** Feature **********/
+
+Feature::ModType Feature::getModType(void)
+{
+ return (ModType)(rand() % static_cast<int>(ModType::NUM_TYPE));
+}
+
+/********** BoolFeature **********/
+
+BoolFeature::BoolFeature(std::string k, std::string v) : Feature(k)
+{
+ if (!v.compare(STRBOOL_TRUE))
+ value = true;
+ else if (!v.compare(STRBOOL_FALSE))
+ value = false;
+ else {
+ LOG("Invalid value : key(%s), value(%s)", k.c_str(), v.c_str());
+ value = false;
+ }
+}
+
+int BoolFeature::modifyValue(void)
+{
+ switch (getModType()) {
+ case ModType::NONE:
+ break;
+ case ModType::EXPAND:
+ value = false;
+ break;
+ case ModType::SHRINK:
+ value = true;
+ break;
+ default:
+ LOG("Invalid modType");
+ return EINVAL;
+ }
+
+ return util.updateDB(key, STRTYPE_BOOL, value ? STRBOOL_TRUE : STRBOOL_FALSE);
+}
+
+int BoolFeature::verifyValue(void)
+{
+ int ret;
+ bool output;
+
+ ret = system_info_get_platform_bool(key.c_str(), &output);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ LOG("system_info_get_platform_bool failed (%d)", ret);
+ return ret;
+ }
+
+ if (value != output) {
+ LOG("Failed to verify value : key(%s), value(%s), expected(%s)",
+ key.c_str(),
+ output ? STRBOOL_TRUE : STRBOOL_FALSE,
+ value ? STRBOOL_TRUE : STRBOOL_FALSE);
+ return -1;
+ }
+
+ return SUCCEED;
+}
+
+/********** IntFeature **********/
+
+IntFeature::IntFeature(std::string k, std::string v) : Feature(k)
+{
+ value = stoi(v);
+}
+
+int IntFeature::modifyValue(void)
+{
+ switch (getModType()) {
+ case ModType::NONE:
+ break;
+ case ModType::EXPAND:
+ if (value < (INT_MAX / 128))
+ value *= 128;
+ else
+ value = INT_MAX;
+ break;
+ case ModType::SHRINK:
+ value /= 128;
+ break;
+ default:
+ LOG("Invalid modType");
+ break;
+ }
+
+ return util.updateDB(key, STRTYPE_INT, std::to_string(value));
+}
+
+int IntFeature::verifyValue(void)
+{
+ int ret;
+ int output;
+
+ ret = system_info_get_platform_int(key.c_str(), &output);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ LOG("system_info_get_platform_int failed (%d)", ret);
+ return ret;
+ }
+
+ if (value != output) {
+ LOG("Failed to verify value : key(%s), value(%d), expected(%d)",
+ key.c_str(), output, value);
+ return -1;
+ }
+
+ return SUCCEED;
+}
+
+/********** DoubleFeature **********/
+
+DoubleFeature::DoubleFeature(std::string k, std::string v) : Feature(k)
+{
+ value = stod(v);
+}
+
+int DoubleFeature::modifyValue(void)
+{
+ std::ostringstream oss;
+
+ switch (getModType()) {
+ case ModType::NONE:
+ break;
+ case ModType::EXPAND:
+ value *= 128.0;
+ break;
+ case ModType::SHRINK:
+ value /= 128.0;
+ break;
+ default:
+ LOG("Invalid modType");
+ break;
+ }
+
+ // Set the decimal precision
+ oss << std::fixed << std::setprecision(15) << value;
+
+ return util.updateDB(key, STRTYPE_DOUBLE, oss.str());
+}
+
+int DoubleFeature::verifyValue(void)
+{
+ int ret;
+ double output;
+
+ ret = system_info_get_platform_double(key.c_str(), &output);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ LOG("system_info_get_platform_double failed (%d)", ret);
+ return ret;
+ }
+
+ if (value != output) {
+ LOG("Failed to verify value : key(%s), value(%.16lf), expected(%.16lf)",
+ key.c_str(), output, value);
+ return -1;
+ }
+
+ return SUCCEED;
+}
+
+/********** StringFeature **********/
+
+StringFeature::StringFeature(std::string k, std::string v) : Feature(k)
+{
+ value = v;
+}
+
+int StringFeature::modifyValue(void)
+{
+ switch (getModType()) {
+ case ModType::NONE:
+ break;
+ case ModType::EXPAND:
+ value += value;
+ break;
+ case ModType::SHRINK:
+ value.resize(std::max(value.length() / 2, (size_t)1));
+ break;
+ default:
+ LOG("Invalid modType");
+ break;
+ }
+
+ return util.updateDB(key, STRTYPE_STRING, value);
+}
+
+int StringFeature::verifyValue(void)
+{
+ int ret;
+ char *output = nullptr;
+
+ ret = system_info_get_platform_string(key.c_str(), &output);
+ if (ret != SYSTEM_INFO_ERROR_NONE) {
+ LOG("system_info_get_platform_string failed (%d)", ret);
+ return ret;
+ }
+
+ if (value.compare(output)) {
+ LOG("Failed to verify value : key(%s), value(%s), expected(%s)",
+ key.c_str(), output, value.c_str());
+ return -1;
+ }
+
+ return SUCCEED;
+}
--- /dev/null
+#ifndef __FEATURE_H__
+#define __FEATURE_H__
+
+#include <string>
+#include <vector>
+
+class Feature {
+public:
+ Feature(std::string k) : key(k) {}
+ virtual ~Feature() {};
+
+ /**
+ * @brief Modify value
+ * @retval SUCCEED on success, otherwise an error value
+ */
+ virtual int modifyValue(void) = 0;
+
+ /**
+ * @brief Compare system-info result with DB
+ * @retval SUCCEED on success, otherwise an error value
+ */
+ virtual int verifyValue(void) = 0;
+
+protected:
+ std::string key;
+
+ enum class ModType {
+ NONE = 0, // Don't modify
+ EXPAND, // Increase value length
+ SHRINK, // Decrease value length
+ NUM_TYPE
+ };
+
+ /**
+ * @brief Decide the value modification type
+ * @retval Refer to ModType
+ */
+ ModType getModType(void);
+};
+
+extern std::vector<Feature *>featureList;
+
+class BoolFeature : public Feature {
+public:
+ BoolFeature(std::string k, std::string v);
+
+ int modifyValue(void);
+ int verifyValue(void);
+
+private:
+ bool value;
+};
+
+class IntFeature : public Feature {
+public:
+ IntFeature(std::string k, std::string v);
+
+ int modifyValue(void);
+ int verifyValue(void);
+
+private:
+ int value;
+};
+
+class DoubleFeature : public Feature {
+public:
+ DoubleFeature(std::string k, std::string v);
+
+ int modifyValue(void);
+ int verifyValue(void);
+
+private:
+ double value;
+};
+
+class StringFeature : public Feature {
+public:
+ StringFeature(std::string k, std::string v);
+
+ int modifyValue(void);
+ int verifyValue(void);
+
+private:
+ std::string value;
+};
+
+#endif /* __FEATURE_H__ */
--- /dev/null
+#include <cstdlib>
+#include <ctime>
+#include <vector>
+
+#include <unistd.h>
+
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "tester.h"
+#include "util.h"
+
+Util util;
+std::vector<Feature *> featureList;
+
+static int initialize(void)
+{
+ int ret;
+
+ // Move original RO DB
+ if (access(SYSTEM_INFO_DB_RO_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("mv", SYSTEM_INFO_DB_RO_PATH, BACKUP_DB_RO_PATH, nullptr);
+ if (ret != SUCCEED) {
+ LOG("Failed to move original RO DB (%d)", ret);
+ return ret;
+ }
+ }
+
+ // Move original RW DB
+ if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("mv", SYSTEM_INFO_DB_RW_PATH, BACKUP_DB_RW_PATH, nullptr);
+ if (ret != SUCCEED) {
+ LOG("Failed to move original RW DB (%d)", ret);
+ return ret;
+ }
+ }
+
+ // Read model-config
+ ret = util.readModelConfig();
+ if (ret != SUCCEED) {
+ LOG("Failed to read model-config (%d)", ret);
+ return ret;
+ }
+
+ srand(time(nullptr));
+
+ return SUCCEED;
+}
+
+static void finalize(void)
+{
+ int ret;
+
+ // Free feature list
+ for (auto feature : featureList)
+ delete(feature);
+ featureList.clear();
+
+ // Remove test RW DB
+ if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("rm", "-rf", SYSTEM_INFO_DB_RW_PATH, nullptr);
+ if (ret != SUCCEED) {
+ LOG("Failed to remove RW DB (%d)", ret);
+ goto handle_ro_db;
+ }
+ }
+
+ // Put back original RW DB
+ if (access(BACKUP_DB_RW_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("mv", BACKUP_DB_RW_PATH, SYSTEM_INFO_DB_RW_PATH, nullptr);
+ if (ret != SUCCEED)
+ LOG("Failed to move original RW DB (%d)", ret);
+ }
+
+handle_ro_db:
+ // Remove test RO DB
+ if (access(SYSTEM_INFO_DB_RO_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("rm", "-rf", SYSTEM_INFO_DB_RO_PATH, nullptr);
+ if (ret != SUCCEED) {
+ LOG("Failed to remove RO DB (%d)", ret);
+ return;
+ }
+ }
+
+ // Put back original RO DB
+ if (access(BACKUP_DB_RO_PATH, F_OK) == 0) {
+ ret = util.forkAndExec("mv", BACKUP_DB_RO_PATH, SYSTEM_INFO_DB_RO_PATH, nullptr);
+ if (ret != SUCCEED)
+ LOG("Failed to move original RO DB (%d)", ret);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ LOG("========== Start system_info_init_db test ==========\n");
+
+ ret = initialize();
+ if (ret != SUCCEED) {
+ LOG("Failed to initialize (%d)", ret);
+ finalize();
+ return ret;
+ }
+
+ Tester *testerList[] = {
+ new CreateDB(),
+ new InsertKey(),
+ new ModifyValue(),
+ new VerifyValue(),
+ new CreateRWDB(),
+ };
+
+ for (auto tester : testerList) {
+ tester->test();
+ delete(tester);
+ }
+
+ finalize();
+
+ LOG("========== End system_info_init_db test ==========");
+ return 0;
+}
--- /dev/null
+#ifndef __SYSTEM_INFO_INIT_DB_TEST_H__
+#define __SYSTEM_INFO_INIT_DB_TEST_H__
+
+#define INIT_DB "system_info_init_db"
+
+#define SUCCEED 0
+
+#define LOG(fmt, arg...) printf(fmt "\n", ##arg)
+
+#define BACKUP_DB_RO_PATH SYSTEM_INFO_DB_RO_PATH "_backup"
+#define BACKUP_DB_RW_PATH SYSTEM_INFO_DB_RW_PATH "_backup"
+
+#define STRTYPE_BOOL "bool"
+#define STRTYPE_INT "int"
+#define STRTYPE_DOUBLE "double"
+#define STRTYPE_STRING "string"
+
+#define STRBOOL_FALSE "false"
+#define STRBOOL_TRUE "true"
+
+#endif /* __SYSTEM_INFO_INIT_DB_TEST_H__ */
--- /dev/null
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "tester.h"
+#include "util.h"
+
+/********** Tester **********/
+
+void Tester::test(void)
+{
+ int ret;
+
+ LOG("[%s] Start", name.c_str());
+
+ ret = run();
+
+ LOG("[%s] Result : %d(%s)\n", name.c_str(), ret,
+ ret == SUCCEED ? "\x1b[32mPASSED\x1b[0m" : "\x1b[31mFAILED\x1b[0m");
+}
+
+/********** CreateDB **********/
+
+int CreateDB::run(void)
+{
+ return util.forkAndExec(INIT_DB, nullptr);
+}
+
+/********** InsertKey **********/
+
+int InsertKey::run(void)
+{
+ int ret;
+ int dice;
+ std::string keyPrefix = "http://tizen.org/test/test.key.";
+ std::string key;
+ std::string type;
+ std::string value;
+ int valueLen;
+ Feature *feature = nullptr;
+
+ for (int keyIndex = 0; keyIndex < 100; keyIndex++) {
+ key = keyPrefix + std::to_string(keyIndex);
+
+ dice = (double)rand() / RAND_MAX * 2000000; // 0 ~ 2M
+
+ /**
+ * In current, most of model-config features have boolean type.
+ * So, we insert other type features more.
+ */
+ switch (dice % 10) {
+ case 0:
+ // Bool
+ type = STRTYPE_BOOL;
+ value = (dice % 2 == 1) ? STRBOOL_TRUE : STRBOOL_FALSE;
+ feature = new BoolFeature(key, value);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ // Int
+ type = STRTYPE_INT;
+ value = std::to_string(dice - 1000000); // -1M ~ 1M
+ feature = new IntFeature(key, value);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ // Double
+ type = STRTYPE_DOUBLE;
+ value = std::to_string(dice - 1000000.0); // -1.0M ~ 1.0M
+ feature = new DoubleFeature(key, value);
+ break;
+ case 7:
+ case 8:
+ case 9:
+ // String
+ type = STRTYPE_STRING;
+ valueLen = (dice % 100) + 1; // 1 ~ 100
+ value.clear();
+ value.reserve(valueLen);
+ do {
+ value += 't';
+ } while (--valueLen);
+ feature = new StringFeature(key, value);
+ break;
+ default:
+ LOG("Invalid dice value (%d)", dice);
+ return EIO;
+ }
+
+ featureList.push_back(feature);
+
+ ret = util.updateDB(key, type, value);
+ if (ret != SUCCEED) {
+ LOG("Failed to insert key(%d)", ret);
+ return ret;
+ }
+ }
+
+ return SUCCEED;
+}
+
+/********** ModifyValue **********/
+
+int ModifyValue::run(void)
+{
+ int ret;
+
+ for (auto feature : featureList) {
+ ret = feature->modifyValue();
+ if (ret != SUCCEED) {
+ LOG("Failed to modify value (%d)", ret);
+ return ret;
+ }
+ }
+
+ return SUCCEED;
+}
+
+/********** VerifyValue **********/
+
+int VerifyValue::run(void)
+{
+ int ret;
+
+ for (auto feature : featureList) {
+ ret = feature->verifyValue();
+ if (ret != SUCCEED) {
+ LOG("Failed to verify value (%d)", ret);
+ return ret;
+ }
+ }
+
+ return SUCCEED;
+}
+
+/********** CreateRWDB **********/
+
+int CreateRWDB::run(void)
+{
+ return util.forkAndExec(INIT_DB, "-i", MODEL_CONFIG_RO_PATH, "-o", SYSTEM_INFO_DB_RW_PATH, nullptr);
+}
--- /dev/null
+#ifndef __TESTER_H__
+#define __TESTER_H__
+
+#include <string>
+
+class Tester {
+public:
+ Tester(std::string n) : name(n) {}
+ virtual ~Tester() {}
+
+ /**
+ * @brief Test and print result
+ */
+ void test(void);
+
+protected:
+ /**
+ * @brief Run test
+ * @retval SUCCEED on succeed, otherwise an error number
+ */
+ virtual int run(void) = 0;
+
+private:
+ std::string name;
+};
+
+class CreateDB : public Tester {
+public:
+ CreateDB() : Tester("Create DB") {}
+
+protected:
+ int run(void);
+};
+
+class InsertKey : public Tester {
+public:
+ InsertKey() : Tester("Insert key") {}
+
+protected:
+ int run(void);
+};
+
+class ModifyValue : public Tester {
+public:
+ ModifyValue() : Tester("Modify value") {}
+
+protected:
+ int run(void);
+};
+
+class VerifyValue : public Tester {
+public:
+ VerifyValue() : Tester("Verify value") {}
+
+protected:
+ int run(void);
+};
+
+class CreateRWDB : public Tester {
+public:
+ CreateRWDB() : Tester("Create RW DB") {}
+
+protected:
+ int run(void);
+};
+
+#endif /* __TESTER_H__ */
--- /dev/null
+#include <cstdarg>
+#include <cstdlib>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "feature.h"
+#include "system_info_init_db_test.h"
+#include "util.h"
+
+int Util::forkAndExec(const char *argv, ...)
+{
+ int ret;
+ pid_t pid;
+ int status;
+ va_list ap;
+ const char *arr[256];
+ int numArg = 0;
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ LOG("fork failed");
+ return EIO;
+ case 0:
+ // Execute program
+ va_start(ap, argv);
+ while (argv && numArg < 255) {
+ arr[numArg++] = argv;
+ argv = va_arg(ap, const char *);
+ }
+ va_end(ap);
+ arr[numArg] = nullptr;
+
+ ret = execvp(arr[0], (char * const *)arr);
+ if (ret == -1) {
+ LOG("execv for %s failed (%d)", arr[0], errno);
+ ret = errno;
+ } else
+ ret = SUCCEED;
+ exit(ret);
+ break;
+ default:
+ // Wait until child is terminated
+ if (wait(&status) == -1) {
+ LOG("wait failed (%d)", errno);
+ return errno;
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == SUCCEED)
+ return SUCCEED;
+ else
+ return EIO;
+ break;
+ }
+
+ return EFAULT;
+}
+
+int Util::updateDB(std::string key, std::string type, std::string value)
+{
+ return forkAndExec(INIT_DB,
+ "-g", "platform",
+ "-k", key.c_str(),
+ "-t", type.c_str(),
+ "-v", value.c_str(),
+ nullptr);
+}
+
+int Util::readModelConfig(void)
+{
+ int ret;
+ xmlDocPtr doc = nullptr;
+ xmlNodePtr nodeRoot = nullptr;
+ xmlNodePtr nodeTag = nullptr;
+ xmlNodePtr nodeKey = nullptr;
+ xmlNode *nodeCur = nullptr;
+ xmlChar *propName = nullptr;
+ xmlChar *propType = nullptr;
+ xmlChar *propValue = nullptr;
+ std::string name;
+ std::string type;
+ std::string value;
+ Feature *feature = nullptr;
+ int numBoolKey = 0;
+ int numIntKey = 0;
+ int numDoubleKey = 0;
+ int numStringKey = 0;
+
+ // Read xml file
+ doc = xmlParseFile(MODEL_CONFIG_RO_PATH);
+ if (!doc) {
+ LOG("xmlParseFile failed");
+ return ENOENT;
+ }
+
+ nodeRoot = xmlDocGetRootElement(doc);
+ if (!nodeRoot) {
+ LOG("xmlDocGetRootElement failed");
+ ret = ENOENT;
+ goto clean;
+ }
+
+ if (xmlStrcmp(nodeRoot->name, (const xmlChar *)"model-config")) {
+ LOG("Failed to find model-config tag");
+ ret = ENOENT;
+ goto clean;
+ }
+
+ nodeTag = nodeRoot->xmlChildrenNode;
+
+ for (nodeCur = nodeTag; nodeCur; nodeCur = nodeCur->next) {
+ if (!xmlStrcmp(nodeCur->name, (const xmlChar *)"platform")) {
+ nodeKey = nodeCur;
+ break;
+ }
+ }
+
+ if (!nodeKey) {
+ LOG("Failed to find platform tag");
+ ret = ENOENT;
+ goto clean;
+ }
+
+ nodeKey = nodeKey->xmlChildrenNode;
+
+ // Store each model-config feature
+ for (nodeCur = nodeKey; nodeCur; nodeCur = nodeCur->next) {
+ propName = xmlGetProp(nodeCur, (const xmlChar *)"name");
+ propType = xmlGetProp(nodeCur, (const xmlChar *)"type");
+ propValue = xmlNodeListGetString(doc, nodeCur->xmlChildrenNode, 1);
+
+ if (!propName || !propType || !propValue) {
+ if (!propName && !propType && !propValue)
+ continue;
+
+ LOG("Invalid feature : name(%s), type(%s), value(%s)",
+ (char *)propName, (char *)propType, (char *)propValue);
+ ret = EIO;
+ goto clean;
+ }
+
+ name.assign((char *)propName);
+ type.assign((char *)propType);
+ value.assign((char *)propValue);
+
+ if (!type.compare(STRTYPE_BOOL)) {
+ feature = new BoolFeature(name, value);
+ numBoolKey++;
+ } else if (!type.compare(STRTYPE_INT)) {
+ feature = new IntFeature(name, value);
+ numIntKey++;
+ } else if (!type.compare(STRTYPE_DOUBLE)) {
+ feature = new DoubleFeature(name, value);
+ numDoubleKey++;
+ } else if (!type.compare(STRTYPE_STRING)) {
+ feature = new StringFeature(name, value);
+ numStringKey++;
+ } else {
+ LOG("Invalid type : key(%s), type(%s)", name.c_str(), type.c_str());
+ ret = EINVAL;
+ goto clean;
+ }
+
+ featureList.push_back(feature);
+
+ xmlFree(propValue);
+ xmlFree(propType);
+ xmlFree(propName);
+ }
+
+ LOG("Number of model-config platform key : Bool(%d), Int(%d), Double(%d), String(%d), Total(%d)\n",
+ numBoolKey, numIntKey, numDoubleKey, numStringKey,
+ numBoolKey + numIntKey + numDoubleKey + numStringKey);
+ ret = SUCCEED;
+
+clean:
+ if (propValue)
+ xmlFree(propValue);
+
+ if (propType)
+ xmlFree(propType);
+
+ if (propName)
+ xmlFree(propName);
+
+ if (doc)
+ xmlFreeDoc(doc);
+
+ return ret;
+}
--- /dev/null
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+class Util {
+public:
+ /**
+ * @brief Fork and execute program
+ * @retval SUCCEED on success, otherwise an error value
+ */
+ static int forkAndExec(const char *argv, ...);
+
+ /**
+ * @brief Update system-info DB
+ * @retval SUCCEED on success, otherwise an error value
+ */
+ static int updateDB(std::string key, std::string type, std::string value);
+
+ /**
+ * @brief Read model-config
+ * @detail Each feature is stored into the featureList
+ * @retval SUCCEED on success, otherwise an error value
+ */
+ static int readModelConfig(void);
+};
+
+extern Util util;
+
+#endif /* __UTIL_H__ */