The existing code assumes that optional data is a key/value where the key is
a string type. However, the python code is placing numeric values, string lists
and strings into the optional data which automatically gets serialized and
de-serialized back to the client retaining the types enclosed. I made a change
in a previous commit which changes it to make everything a string and we broke
the display code which was expecting the member id of the optional pool data to
be a list of strings.
This patch adds the following capabilities for optional data type values for
the C API:
-Get/Set long double
-Get/Set uint64_t
-Get/Set int64_t
-Get/Set lsm_string_list
I added a enum and function:
typedef enum {
LSM_OPTIONAL_DATA_INVALID = -2, /**< Invalid */
LSM_OPTIONAL_DATA_NOT_FOUND = -1, /**< Key not found */
LSM_OPTIONAL_DATA_STRING = 1, /**< Contains a string */
LSM_OPTIONAL_DATA_SIGN_INT = 2, /**< Contains a signed int */
LSM_OPTIONAL_DATA_UNSIGNED_INT = 3, /**< Contains an unsigned int */
LSM_OPTIONAL_DATA_REAL = 4, /**< Contains a real number */
LSM_OPTIONAL_DATA_STRING_LIST = 10 /**< Contains a list of strings*/
} lsm_optional_data_type;
lsm_optional_data_type LSM_DLL_EXPORT lsm_optional_data_type_get(
lsm_optional_data *op, const char *key);
Which needs to be utilized to see that type the value is. Once that is
determined then the user can call one of the newly added corresponding get
functions.
However, this is far from ideal for the following reason. The JSON RPC IPC
used between the client and plug-in only has a single number type which
encompasses all of the types listed above (int64_t, uint64_t, long double)
and then some (numbers of arbitrary size). Thus a plug-in could be returning
a value to a client and the 'type' of numeric may vary based on the numerical
value. So a client to be robust would need to handle checking for multiple
numeric types for a single optional value. The only way I see this being
consistent is if we extend the API so that we encode the 'type' and value in
the serialized JSON so that we can consistently give the same 'type' of numeric
to the client application. This patch looks at the numeric string and puts it
in the first available fitting number in this order: int64, uint64, long double.
Any other suggestions people have, please share them.
Thanks!
Regards,
Tony
Signed-off-by: Tony Asleson <***@redhat.com>
---
.../libstoragemgmt/libstoragemgmt_optionaldata.h | 125 +++++++++-
c_binding/lsm_convert.cpp | 77 +++++-
c_binding/lsm_datatypes.cpp | 266 +++++++++++++++++++--
c_binding/lsm_datatypes.hpp | 31 ++-
c_binding/lsm_ipc.cpp | 29 ++-
c_binding/lsm_ipc.hpp | 8 +-
plugin/simc/simc_lsmplugin.c | 2 +-
test/tester.c | 101 +++++++-
8 files changed, 601 insertions(+), 38 deletions(-)
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_optionaldata.h b/c_binding/include/libstoragemgmt/libstoragemgmt_optionaldata.h
index cfd6974..5128609 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_optionaldata.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_optionaldata.h
@@ -27,6 +27,26 @@
extern "C" {
#endif
+typedef enum {
+ LSM_OPTIONAL_DATA_INVALID = -2, /**< Invalid */
+ LSM_OPTIONAL_DATA_NOT_FOUND = -1, /**< Key not found */
+ LSM_OPTIONAL_DATA_STRING = 1, /**< Contains a string */
+ LSM_OPTIONAL_DATA_SIGN_INT = 2, /**< Contains a signed int */
+ LSM_OPTIONAL_DATA_UNSIGNED_INT = 3, /**< Contains an unsigned int */
+ LSM_OPTIONAL_DATA_REAL = 4, /**< Contains a real number */
+ LSM_OPTIONAL_DATA_STRING_LIST = 10 /**< Contains a list of strings*/
+} lsm_optional_data_type;
+
+
+/**
+ * Returns the type of data stored.
+ * @param op Record
+ * @param key Key to lookup
+ * @return One of the enumerated types above.
+ */
+lsm_optional_data_type LSM_DLL_EXPORT lsm_optional_data_type_get(
+ lsm_optional_data *op, const char *key);
+
/**
* Free a optional data record
* @param op Record to free.
@@ -38,11 +58,10 @@ int LSM_DLL_EXPORT lsm_optional_data_record_free(lsm_optional_data *op);
* Get the list of 'keys' available in the optional data
* @param [in] op Valid optional data pointer
* @param [out] l String list pointer
- * @param [out] count Number of items in string list
* @return LSM_ERR_OK on success, else error reason
*/
-int LSM_DLL_EXPORT lsm_optional_data_list_get(lsm_optional_data *op,
- lsm_string_list **l, uint32_t *count);
+int LSM_DLL_EXPORT lsm_optional_data_keys(lsm_optional_data *op,
+ lsm_string_list **l);
/**
* Get the value of a key (string)
@@ -71,7 +90,105 @@ int LSM_DLL_EXPORT lsm_optional_data_string_set(lsm_optional_data *op,
* @param src lsm_optional_data to copy
* @return NULL on error/memory allocation failure, else copy
*/
-lsm_optional_data LSM_DLL_EXPORT *lsm_optional_data_record_copy(lsm_optional_data *src);
+lsm_optional_data LSM_DLL_EXPORT *lsm_optional_data_record_copy(
+ lsm_optional_data *src);
+
+/**
+ * Set the value of a key with a signed integer
+ * @param[in] op Valid optional data pointer
+ * @param[in] key Key to set value for (key is copied)
+ * @param[in] value Value to set
+ * @return LSM_ERR_OK on success, else error reason
+ */
+int LSM_DLL_EXPORT lsm_optional_data_int64_set(lsm_optional_data *op,
+ const char *key,
+ int64_t value);
+
+/**
+ * Get the value of the key which is a int64.
+ * Note: lsm_optional_data_type_get needs to return LSM_OPTIONAL_DATA_SIGN_INT
+ * before it is valid to call this function.
+ * @param op
+ * @param key
+ * @return Value, MAX on errors. To determine if value is valid call
+ * lsm_optional_data_type_get first, then you are ensured return value is
+ * correct.
+ */
+int64_t LSM_DLL_EXPORT lsm_optional_data_int64_get(lsm_optional_data *op,
+ const char *key);
+
+/**
+ * Set the value of a key with an unsigned integer
+ * @param[in] op Valid optional data pointer
+ * @param[in] key Key to set value for (key is copied)
+ * @param[in] value Value to set
+ * @return LSM_ERR_OK on success, else error reason
+ */
+int LSM_DLL_EXPORT lsm_optional_data_uint64_set(lsm_optional_data *op,
+ const char *key,
+ uint64_t value);
+
+/**
+ * Get the value of the key which is a uint64.
+ * Note: lsm_optional_data_type_get needs to return
+ * LSM_OPTIONAL_DATA_UNSIGNED_INT before it is valid to call this function.
+ * @param [in] op Valid optional data pointer
+ * @param [in] key Key that exists
+ * @return Value, MAX on errors. To determine if value is valid call
+ * lsm_optional_data_type_get first, then you are ensured return value is
+ * correct.
+ */
+uint64_t LSM_DLL_EXPORT lsm_optional_data_uint64_get(lsm_optional_data *op,
+ const char *key);
+
+/**
+ * Set the value of a key with a real number
+ * @param[in] op Valid optional data pointer
+ * @param[in] key Key to set value for (key is copied)
+ * @param[in] value Value to set
+ * @return LSM_ERR_OK on success, else error reason
+ */
+int LSM_DLL_EXPORT lsm_optional_data_real_set(lsm_optional_data *op,
+ const char *key,
+ long double value);
+
+/**
+ * Get the value of the key which is a real.
+ * Note: lsm_optional_data_type_get needs to return
+ * LSM_OPTIONAL_DATA_REAL before it is valid to call this function.
+ * @param [in] op Valid optional data pointer
+ * @param [in] key Key that exists
+ * @return Value, MAX on errors. To determine if value is valid call
+ * lsm_optional_data_type_get first, then you are ensured return value is
+ * correct.
+ */
+long double LSM_DLL_EXPORT lsm_optional_data_real_get(lsm_optional_data *op,
+ const char *key);
+
+
+/**
+ * Set the value of a key with a string list
+ * @param[in] op Valid optional data pointer
+ * @param[in] key Key to set value for (key is copied)
+ * @param[in] value Value to set
+ * @return LSM_ERR_OK on success, else error reason
+ */
+int LSM_DLL_EXPORT lsm_optional_data_string_list_set(lsm_optional_data *op,
+ const char *key,
+ lsm_string_list *sl);
+
+/**
+ * Get the value of the key which is a string list.
+ * Note: lsm_optional_data_type_get needs to return
+ * LSM_OPTIONAL_DATA_STRING_LIST before it is valid to call this function.
+ * @param [in] op Valid optional data pointer
+ * @param [in] key Key that exists
+ * @return Value, NULL on errors. To determine if value is valid call
+ * lsm_optional_data_type_get first, then you are ensured return value is
+ * correct.
+ */
+lsm_string_list LSM_DLL_EXPORT *lsm_optional_data_string_list_get(
+ lsm_optional_data *op, const char *key);
#ifdef __cplusplus
}
diff --git a/c_binding/lsm_convert.cpp b/c_binding/lsm_convert.cpp
index 86e9e8f..8bb8684 100644
--- a/c_binding/lsm_convert.cpp
+++ b/c_binding/lsm_convert.cpp
@@ -662,15 +662,59 @@ Value capabilities_to_value(lsm_storage_capabilities *cap)
lsm_optional_data *value_to_optional_data(Value &op)
{
lsm_optional_data *rc = NULL;
+ int set_result = 0;
if( is_expected_object(op, "OptionalData") ) {
rc = lsm_optional_data_record_alloc();
if ( rc ) {
std::map<std::string, Value> v = op["values"].asObject();
std::map<std::string, Value>::iterator itr;
for(itr=v.begin(); itr != v.end(); ++itr) {
- if( LSM_ERR_OK != lsm_optional_data_string_set(rc,
- itr->first.c_str(),
- itr->second.asC_str())) {
+ const char *key = itr->first.c_str();
+ Value v = itr->second;
+
+ //TODO: Check return codes of all these sets!
+ switch(v.valueType()){
+ case(Value::string_t): {
+ set_result =
+ lsm_optional_data_string_set(rc, key, v.asC_str());
+ break;
+ }
+ case(Value::numeric_t): {
+ int num_rc = 0;
+ int64_t si = 0;
+ uint64_t ui = 0;
+ long double d = 0;
+
+ num_rc = number_convert(v.asNumString(), &si, &ui, &d);
+ if( num_rc > 0 ) {
+ if( 1 == num_rc ) {
+ set_result =
+ lsm_optional_data_int64_set(rc, key, si);
+ } else if( 2 == num_rc ) {
+ set_result =
+ lsm_optional_data_uint64_set(rc, key, ui);
+ } else if( 3 == num_rc ) {
+ set_result =
+ lsm_optional_data_real_set(rc, key, ui);
+ }
+ }
+ break;
+ }
+ case(Value::array_t): {
+ lsm_string_list *sl = value_to_string_list(v);
+ if( sl ) {
+ set_result =
+ lsm_optional_data_string_list_set(rc, key, sl);
+ lsm_string_list_free(sl);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* If the set failed free results and bail */
+ if( LSM_ERR_OK != set_result ) {
lsm_optional_data_record_free(rc);
rc = NULL;
break;
@@ -693,7 +737,32 @@ Value optional_data_to_value(lsm_optional_data *op)
g_hash_table_iter_init(&iter, op->data);
while(g_hash_table_iter_next(&iter, &key, &value)) {
- embedded_values[(const char*)key] = Value((const char*)(value));
+ struct optional_data *od = (struct optional_data *)value;
+ switch( od->t ) {
+ case( LSM_OPTIONAL_DATA_STRING ): {
+ embedded_values[(const char*)key] = Value(od->v.s);
+ break;
+ }
+ case( LSM_OPTIONAL_DATA_STRING_LIST ): {
+ embedded_values[(const char*)key] =
+ string_list_to_value(od->v.sl);
+ break;
+ }
+ case( LSM_OPTIONAL_DATA_SIGN_INT ): {
+ embedded_values[(const char*)key] = Value(od->v.si);
+ break;
+ }
+ case( LSM_OPTIONAL_DATA_UNSIGNED_INT ): {
+ embedded_values[(const char*)key] = Value(od->v.ui);
+ break;
+ }
+ case( LSM_OPTIONAL_DATA_REAL ): {
+ embedded_values[(const char*)key] = Value(od->v.d);
+ break;
+ }
+ default:
+ break;
+ }
}
c["class"] = Value("OptionalData");
diff --git a/c_binding/lsm_datatypes.cpp b/c_binding/lsm_datatypes.cpp
index 3ee76d0..9b004a9 100644
--- a/c_binding/lsm_datatypes.cpp
+++ b/c_binding/lsm_datatypes.cpp
@@ -45,6 +45,9 @@
#include <unistd.h>
#include <dlfcn.h>
#include <glib.h>
+#include <errno.h>
+#include <float.h>
+#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
@@ -1822,6 +1825,44 @@ char* capability_string(lsm_storage_capabilities *c)
return rc;
}
+void optional_data_free(void *d)
+{
+ struct optional_data *op = (struct optional_data *)d;
+ if (op->t == LSM_OPTIONAL_DATA_STRING_LIST ) {
+ lsm_string_list_free(op->v.sl);
+ } else if( op->t == LSM_OPTIONAL_DATA_STRING ) {
+ free(op->v.s);
+ }
+
+ free(d);
+}
+
+struct optional_data *optional_data_copy(struct optional_data *op)
+{
+ struct optional_data *copy = (struct optional_data*)
+ calloc(1, sizeof(optional_data));
+
+ if( copy ) {
+ copy->t = op->t;
+ copy->v = op->v;
+
+ if( op->t == LSM_OPTIONAL_DATA_STRING) {
+ copy->v.s = strdup(op->v.s);
+ if( !copy->v.s ) {
+ optional_data_free(copy);
+ copy = NULL;
+ }
+ } else if( op->t == LSM_OPTIONAL_DATA_STRING_LIST) {
+ copy->v.sl = lsm_string_list_copy(op->v.sl);
+ if( !copy->v.sl ) {
+ optional_data_free(copy);
+ copy = NULL;
+ }
+ }
+ }
+ return copy;
+}
+
lsm_optional_data *lsm_optional_data_record_alloc(void)
{
lsm_optional_data *rc = NULL;
@@ -1829,7 +1870,8 @@ lsm_optional_data *lsm_optional_data_record_alloc(void)
rc = (lsm_optional_data *)malloc(sizeof(lsm_optional_data));
if( rc ) {
rc->magic = LSM_OPTIONAL_DATA_MAGIC;
- rc->data = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
+ rc->data = g_hash_table_new_full(g_str_hash, g_str_equal, free,
+ optional_data_free);
if ( !rc->data ) {
lsm_optional_data_record_free(rc);
rc = NULL;
@@ -1851,11 +1893,19 @@ lsm_optional_data *lsm_optional_data_record_copy(lsm_optional_data *src)
/* Walk through each from src and duplicate it to dest*/
g_hash_table_iter_init(&iter, src->data);
while(g_hash_table_iter_next(&iter, &key, &value)) {
- if( LSM_ERR_OK != lsm_optional_data_string_set(dest,
- (const char*)key, (const char*)value))
- {
+ char *k_value = strdup((char*)key);
+ struct optional_data *d_value =
+ optional_data_copy((struct optional_data*)value);
+
+ if( k_value && d_value ) {
+ g_hash_table_insert(dest->data, (gpointer)k_value,
+ (gpointer)d_value);
+ } else {
+ free(k_value);
+ optional_data_free(d_value);
lsm_optional_data_record_free(dest);
dest = NULL;
+ break;
}
}
}
@@ -1878,22 +1928,22 @@ int lsm_optional_data_record_free(lsm_optional_data *op)
return LSM_ERR_INVALID_OPTIONAL_DATA;
}
-int lsm_optional_data_list_get(lsm_optional_data *op, lsm_string_list **l,
- uint32_t *count)
+int lsm_optional_data_keys(lsm_optional_data *op, lsm_string_list **l)
{
GHashTableIter iter;
gpointer key;
gpointer value;
+ uint32_t size = 0;
if( LSM_IS_OPTIONAL_DATA(op) ) {
- *count = g_hash_table_size(op->data);
+ size = g_hash_table_size(op->data);
- if( *count ) {
+ if( size ) {
*l = lsm_string_list_alloc(0);
g_hash_table_iter_init(&iter, op->data);
while(g_hash_table_iter_next(&iter, &key, &value)) {
if(LSM_ERR_OK != lsm_string_list_append(*l, (char *)key) ) {
- *count = 0;
+ size = 0;
lsm_string_list_free(*l);
*l = NULL;
return LSM_ERR_NO_MEMORY;
@@ -1905,13 +1955,52 @@ int lsm_optional_data_list_get(lsm_optional_data *op, lsm_string_list **l,
return LSM_ERR_INVALID_OPTIONAL_DATA;
}
-const char *lsm_optional_data_string_get(lsm_optional_data *op,
+lsm_optional_data_type lsm_optional_data_type_get(lsm_optional_data *op,
const char *key)
{
if( LSM_IS_OPTIONAL_DATA(op) ) {
- return (const char*)g_hash_table_lookup(op->data, key);
+ struct optional_data *od = (struct optional_data *)
+ g_hash_table_lookup(op->data, key);
+ if( od ) {
+ return od->t;
+ }
+ return LSM_OPTIONAL_DATA_NOT_FOUND;
}
- return NULL;
+ return LSM_OPTIONAL_DATA_INVALID;
+}
+
+
+#define OP_GETTER(name, return_type, type_value, member, error_value) \
+return_type name(lsm_optional_data *op, const char *key) \
+{ \
+ if( LSM_IS_OPTIONAL_DATA(op) ) { \
+ struct optional_data *od = (struct optional_data *) \
+ g_hash_table_lookup(op->data, key); \
+ if( od ) { \
+ if( od->t == type_value ) { \
+ return od->v.member; \
+ } \
+ } \
+ } \
+ return error_value; \
+} \
+
+OP_GETTER(lsm_optional_data_string_list_get, lsm_string_list *,
+ LSM_OPTIONAL_DATA_STRING_LIST, sl, NULL)
+OP_GETTER(lsm_optional_data_string_get, const char *, LSM_OPTIONAL_DATA_STRING,
+ s, NULL)
+OP_GETTER(lsm_optional_data_int64_get, int64_t, LSM_OPTIONAL_DATA_SIGN_INT, si,
+ LLONG_MAX)
+OP_GETTER(lsm_optional_data_uint64_get, uint64_t,
+ LSM_OPTIONAL_DATA_UNSIGNED_INT, ui, ULLONG_MAX)
+OP_GETTER(lsm_optional_data_real_get, long double, LSM_OPTIONAL_DATA_REAL, d,
+ LDBL_MAX)
+
+static void insert_value(GHashTable *ht, const char *key,
+ struct optional_data *value)
+{
+ g_hash_table_remove(ht, (gpointer)key);
+ g_hash_table_insert(ht, (gpointer)key, (gpointer)value);
}
int lsm_optional_data_string_set(lsm_optional_data *op,
@@ -1920,14 +2009,18 @@ int lsm_optional_data_string_set(lsm_optional_data *op,
{
if( LSM_IS_OPTIONAL_DATA(op) ) {
char *k_value = strdup(key);
- char *d_value = strdup(value);
-
- if( k_value && d_value ) {
- g_hash_table_remove(op->data, (gpointer)k_value);
- g_hash_table_insert(op->data, (gpointer)k_value, (gpointer)d_value);
+ char *op_value = strdup(value);
+ struct optional_data *d_value =
+ (struct optional_data *)calloc(1, sizeof(struct optional_data));
+
+ if( k_value && op_value && d_value) {
+ d_value->t = LSM_OPTIONAL_DATA_STRING;
+ d_value->v.s = op_value;
+ insert_value(op->data, k_value, d_value);
return LSM_ERR_OK;
} else {
free(k_value);
+ free(op_value);
free(d_value);
return LSM_ERR_NO_MEMORY;
}
@@ -1935,6 +2028,145 @@ int lsm_optional_data_string_set(lsm_optional_data *op,
return LSM_ERR_INVALID_OPTIONAL_DATA;
}
+int lsm_optional_data_string_list_set(lsm_optional_data *op, const char *key,
+ lsm_string_list *value)
+{
+ int rc = LSM_ERR_INVALID_OPTIONAL_DATA;
+ if( LSM_IS_OPTIONAL_DATA(op) ) {
+ char *k_value = strdup(key);
+ lsm_string_list *copy = lsm_string_list_copy(value);
+ struct optional_data *d_value =
+ (struct optional_data *)calloc(1, sizeof(struct optional_data));
+
+ if( k_value && copy && d_value ) {
+ d_value->t = LSM_OPTIONAL_DATA_STRING_LIST;
+ d_value->v.sl = copy;
+ insert_value(op->data, k_value, d_value);
+ rc = LSM_ERR_OK;
+ } else {
+ free(k_value);
+ free(d_value);
+ lsm_string_list_free(copy);
+ rc = LSM_ERR_NO_MEMORY;
+ }
+ }
+ return rc;
+}
+
+int lsm_optional_data_int64_set(lsm_optional_data *op, const char *key,
+ int64_t value)
+{
+ int rc = LSM_ERR_INVALID_OPTIONAL_DATA;
+ if( LSM_IS_OPTIONAL_DATA(op) ) {
+ char *k_value = strdup(key);
+ struct optional_data *d_value =
+ (struct optional_data *)calloc(1, sizeof(struct optional_data));
+
+ if( k_value && d_value ) {
+ d_value->t = LSM_OPTIONAL_DATA_SIGN_INT;
+ d_value->v.si = value;
+ insert_value(op->data, k_value, d_value);
+ rc = LSM_ERR_OK;
+ } else {
+ free(k_value);
+ free(d_value);
+ rc = LSM_ERR_NO_MEMORY;
+ }
+ }
+ return rc;
+}
+
+int lsm_optional_data_uint64_set(lsm_optional_data *op, const char *key,
+ uint64_t value)
+{
+ int rc = LSM_ERR_INVALID_OPTIONAL_DATA;
+ if( LSM_IS_OPTIONAL_DATA(op) ) {
+ char *k_value = strdup(key);
+ struct optional_data *d_value =
+ (struct optional_data *)calloc(1, sizeof(struct optional_data));
+
+ if( k_value && d_value ) {
+ d_value->t = LSM_OPTIONAL_DATA_UNSIGNED_INT;
+ d_value->v.ui = value;
+ insert_value(op->data, k_value, d_value);
+ rc = LSM_ERR_OK;
+ } else {
+ free(k_value);
+ free(d_value);
+ rc = LSM_ERR_NO_MEMORY;
+ }
+ }
+ return rc;
+}
+
+int lsm_optional_data_real_set(lsm_optional_data *op, const char *key,
+ long double value)
+{
+ int rc = LSM_ERR_INVALID_OPTIONAL_DATA;
+ if( LSM_IS_OPTIONAL_DATA(op) ) {
+ char *k_value = strdup(key);
+ struct optional_data *d_value =
+ (struct optional_data *)calloc(1, sizeof(struct optional_data));
+
+ if( k_value && d_value ) {
+ d_value->t = LSM_OPTIONAL_DATA_REAL;
+ d_value->v.d = value;
+ insert_value(op->data, k_value, d_value);
+ rc = LSM_ERR_OK;
+ } else {
+ free(k_value);
+ free(d_value);
+ rc = LSM_ERR_NO_MEMORY;
+ }
+ }
+ return rc;
+}
+
+int number_convert(const char *str_num, int64_t *si, uint64_t *ui,
+ long double *d)
+{
+ int rc = -1;
+ char *end = NULL;
+
+ if( str_num && str_num != '\0' && strlen(str_num) ) {
+ *si = 0;
+ *ui = 0;
+ *d = 0.0;
+
+ errno = 0;
+ *si = strtoll(str_num, &end, 10);
+ if( errno == 0 && *end == '\0' ) {
+ rc = 1; /* Signed number */
+ }
+
+ /* strtoull will convert negative, not wanted so skip if it has '-' */
+ if( -1 == rc && str_num[0] != '-') {
+ end = NULL;
+ errno = 0;
+ *ui = strtoull(str_num, &end, 10);
+
+ if( errno == 0 && *end == '\0' ) {
+ rc = 2; /* Unsigned number */
+ }
+ }
+
+ if( -1 == rc ) {
+ end = NULL;
+ errno = 0;
+
+ *d = strtold(str_num, &end);
+ if( errno == 0 && *end == '\0' ) {
+ rc = 3; /* Real number */
+ }
+ }
+
+ if( -1 == rc ) {
+ rc = 0; /* Not a number */
+ }
+ }
+ return rc;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/lsm_datatypes.hpp b/c_binding/lsm_datatypes.hpp
index cc6f65f..c6ac9c5 100644
--- a/c_binding/lsm_datatypes.hpp
+++ b/c_binding/lsm_datatypes.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Red Hat, Inc.
+ * Copyright (C) 2011-2014 Red Hat, Inc.
* 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
@@ -303,6 +303,18 @@ struct LSM_DLL_LOCAL _lsm_optional_data {
GHashTable *data;
};
+union optional_value {
+ char *s;
+ long double d;
+ int64_t si;
+ uint64_t ui;
+ lsm_string_list *sl;
+};
+struct optional_data {
+ lsm_optional_data_type t;
+ union optional_value v;
+};
+
/**
* Returns a pointer to a newly created connection structure.
* @return NULL on memory exhaustion, else new connection.
@@ -336,6 +348,23 @@ LSM_DLL_LOCAL char* capability_string(lsm_storage_capabilities *c);
LSM_DLL_LOCAL const char *uds_path(void);
+/**
+ * Take a character string and tries to convert to a number.
+ * Note: Number is defined as what is acceptable for JSON number. The number
+ * is represented by int64_t if possible, else uint64_t and then long double.
+ * @param str_num Character string containing number
+ * @param si Signed 64 bit number
+ * @param ui Unsigned 64 bit number
+ * @param d Long double
+ * @return -1 = Invalid string pointer
+ * 0 = Not a number
+ * 1 = Number converted to signed integer, value in si
+ * 2 = Number converted to unsigned integer, value in ui
+ * 3 = Number converted to long double, value in d
+ */
+int LSM_DLL_LOCAL number_convert(const char *str_num, int64_t *si, uint64_t *ui,
+ long double *d);
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/lsm_ipc.cpp b/c_binding/lsm_ipc.cpp
index de856e0..59684bf 100644
--- a/c_binding/lsm_ipc.cpp
+++ b/c_binding/lsm_ipc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Red Hat, Inc.
+ * Copyright (C) 2011-2014 Red Hat, Inc.
* 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
@@ -224,6 +224,10 @@ Value::Value(double v) : t(numeric_t), s(to_string(v))
{
}
+Value::Value(long double v) : t(numeric_t), s(to_string(v))
+{
+}
+
Value::Value(uint32_t v) : t(numeric_t), s(to_string(v))
{
}
@@ -342,6 +346,16 @@ Value Value::getValue( const char* key )
return Value();
}
+const char * Value::asNumString()
+{
+ const char *rc = NULL;
+
+ if (t == numeric_t) {
+ rc = s.c_str();
+ }
+ return rc;
+}
+
void * Value::asVoid()
{
if (t == null_t) {
@@ -371,6 +385,19 @@ double Value::asDouble()
throw ValueException("Value not numeric");
}
+long double Value::asLongDouble()
+{
+ if (t == numeric_t) {
+ long double rc;
+
+ if (sscanf(s.c_str(), "%Lf", &rc) > 0) {
+ return rc;
+ }
+ throw ValueException("Value not a long double");
+ }
+ throw ValueException("Value not numeric");
+}
+
int32_t Value::asInt32_t()
{
if (t == numeric_t) {
diff --git a/c_binding/lsm_ipc.hpp b/c_binding/lsm_ipc.hpp
index 54f53de..c250efc 100644
--- a/c_binding/lsm_ipc.hpp
+++ b/c_binding/lsm_ipc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Red Hat, Inc.
+ * Copyright (C) 2011-2014 Red Hat, Inc.
* 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
@@ -200,6 +200,7 @@ public:
* @param v value
*/
Value(double v);
+ Value(long double v);
/**
* Numeric unsigned 32 constructor
@@ -301,6 +302,10 @@ public:
*/
Value getValue(const char* key);
+ /**
+ * Returns a numeric as the string holding it.
+ */
+ const char* asNumString();
/**
* Returns NULL if void type, else ValueException
@@ -319,6 +324,7 @@ public:
* @return double value else ValueException on error
*/
double asDouble();
+ long double asLongDouble();
/**
* Signed 32 integer value represented by object.
diff --git a/plugin/simc/simc_lsmplugin.c b/plugin/simc/simc_lsmplugin.c
index a9321d2..045a360 100644
--- a/plugin/simc/simc_lsmplugin.c
+++ b/plugin/simc/simc_lsmplugin.c
@@ -2574,7 +2574,7 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
snprintf(name, sizeof(name), "Sim C disk %d", i);
- snprintf(sn, sizeof(sn), "SIMDISKSN00000%04d\n", i);
+ snprintf(sn, sizeof(sn), "SIMDISKSN00000%04d", i);
lsm_optional_data_string_set(od, "sn", sn);
diff --git a/test/tester.c b/test/tester.c
index 07136bf..7b8e528 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -1039,7 +1039,6 @@ START_TEST(test_disks)
const char *name;
const char *system_id;
int i = 0;
- uint32_t key_count = 0;
lsm_string_list *keys = NULL;
const char *key = NULL;
const char *data = NULL;
@@ -1048,7 +1047,8 @@ START_TEST(test_disks)
fail_unless(c!=NULL);
- int rc = lsm_disk_list(c, NULL, NULL, &d, &count, 0);
+ int rc = lsm_disk_list(c, NULL, NULL, &d, &count,
+ LSM_DISK_FLAG_RETRIEVE_FULL_INFO);
if( LSM_ERR_OK == rc ) {
fail_unless(LSM_ERR_OK == rc, "%d", rc);
@@ -1080,16 +1080,36 @@ START_TEST(test_disks)
od = lsm_disk_optional_data_get(d[i]);
if( od ) {
+ lsm_optional_data_type t;
+
/* Iterate through the keys, grabbing the data */
- rc = lsm_optional_data_list_get(od, &keys, &key_count);
- if( LSM_ERR_OK == rc && keys != NULL && key_count > 0 ) {
- //uint32_t num_keys = lsmStringListSize(keys);
- //fail_unless( num_keys == key_count, "%d != %d", num_keys, key_count);
- for(j = 0; j < key_count; ++j ) {
+ rc = lsm_optional_data_keys(od, &keys);
+ if( LSM_ERR_OK == rc && keys != NULL &&
+ lsm_string_list_size(keys) > 0 ) {
+ for(j = 0; j < lsm_string_list_size(keys); ++j ) {
key = lsm_string_list_elem_get(keys, j);
- data = lsm_optional_data_string_get(od, key);
+
fail_unless(key != NULL && strlen(key) > 0);
- fail_unless(data != NULL && strlen(data) > 0);
+
+ t = lsm_optional_data_type_get(od, key);
+ if( LSM_OPTIONAL_DATA_STRING == t ) {
+ data = lsm_optional_data_string_get(od, key);
+ printf("Key=%s, Data=%s\n", key, data);
+ fail_unless(data != NULL && strlen(data) > 0);
+ } else if( LSM_OPTIONAL_DATA_STRING_LIST == t ) {
+ lsm_string_list *sl = lsm_optional_data_string_list_get(od, key);
+ if( sl ) {
+ int size = lsm_string_list_size(sl);
+ int j;
+
+ printf("Key=%s, Data=", key);
+
+ for( j = 0; j < size; j++ ) {
+ printf("%s ", lsm_string_list_elem_get(sl, j));
+ }
+ printf("\n");
+ }
+ }
}
if( keys ) {
@@ -3096,6 +3116,68 @@ START_TEST(test_search_fs)
}
END_TEST
+START_TEST(test_pool_listing)
+{
+ lsm_pool **pools = NULL;
+ uint32_t count = 0;
+ lsm_optional_data *op = NULL;
+ uint32_t i,j = 0;
+ lsm_optional_data_type t;
+ lsm_string_list *keys = NULL;
+
+ int rc = lsm_pool_list(c, NULL, NULL, &pools, &count,
+ LSM_POOL_FLAG_RETRIEVE_FULL_INFO);
+ if( LSM_ERR_OK == rc ) {
+ for( i = 0; i < count; ++i ) {
+ op = lsm_pool_optional_data_get(pools[i]);
+
+ if( op ) {
+ rc = lsm_optional_data_keys(op, &keys);
+ fail_unless(LSM_ERR_OK == rc, "lsm_optional_data_keys %d", rc);
+
+ if(LSM_ERR_OK == rc ) {
+
+ for(j = 0; j < lsm_string_list_size(keys); ++j ) {
+ const char *key = lsm_string_list_elem_get(keys, j);
+ t = lsm_optional_data_type_get(op, key);
+ if( LSM_OPTIONAL_DATA_STRING == t ) {
+ const char *value = lsm_optional_data_string_get(op, key);
+ fail_unless(value != NULL && strlen(value) > 0);
+ printf("%s=%s\n", key, value);
+ } else if( LSM_OPTIONAL_DATA_STRING_LIST == t ) {
+ lsm_string_list *v = lsm_optional_data_string_list_get(op, key);
+ if( v ) {
+ uint32_t k;
+
+ printf("%s=[", key);
+ for( k = 0; k < lsm_string_list_size(v); ++k ) {
+ printf("%s ",
+ lsm_string_list_elem_get(v, k));
+ }
+ printf("]\n");
+ lsm_string_list_free(v);
+ }
+ } else if( LSM_OPTIONAL_DATA_SIGN_INT == t ) {
+ int64_t value = lsm_optional_data_int64_get(op, key);
+ printf("%s:%" PRId64 "\n", key, value);
+ }
+ }
+
+ rc = lsm_string_list_free(keys);
+ fail_unless(LSM_ERR_OK == rc, "lsm_string_list_free %d", rc);
+ }
+
+ rc = lsm_optional_data_record_free(op);
+ fail_unless(LSM_ERR_OK == rc, "lsm_optional_data_record_free %d", rc);
+ }
+ }
+
+ rc = lsm_pool_record_array_free(pools, count);
+ fail_unless(LSM_ERR_OK == rc, "lsm_pool_record_array_free %d", rc);
+ }
+}
+END_TEST
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
@@ -3103,6 +3185,7 @@ Suite * lsm_suite(void)
TCase *basic = tcase_create("Basic");
tcase_add_checked_fixture (basic, setup, teardown);
+ tcase_add_test(basic, test_pool_listing);
tcase_add_test(basic, test_search_fs);
tcase_add_test(basic, test_search_access_groups);
tcase_add_test(basic, test_search_disks);
--
1.8.2.1