#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <libintl.h>
#include <pthread.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <alloca.h>
#include <limits.h>
#include "libfru.h"
#include "libfrup.h"
#include "libfruds.h"
#include "Ancestor.h"
#include "libfrureg.h"
#include "Parser.h"
#include "PayloadReader.h"
#define DATA_SOURCE_OBJ_NAME "data_source"
#define ENCRYPTION_LIB_NAME "libfrucrypt.so.1"
#define FRU_ENCRYPT_FUNC_NAME "fru_encrypt_func"
#define UNKNOWN_PATH "UNKNOWN"
#define IS_UNKNOWN_PATH(path) \
((strcmp(path, "/UNKNOWN") == 0) || (strcmp(path, "UNKNOWN") == 0))
#define NODEHDL_TO_TREEHDL(nodehdl) (fru_treehdl_t)nodehdl
#define TREEHDL_TO_NODEHDL(treehdl) (fru_nodehdl_t)treehdl
struct cont_lock
{
fru_nodehdl_t handle;
pthread_rwlock_t lock;
struct cont_lock *next;
};
typedef struct cont_lock cont_lock_t;
fru_encrypt_func_t encrypt_func;
#define CONT_LOCK_HASH_NUM 128
cont_lock_t *cont_lock_hash[CONT_LOCK_HASH_NUM];
pthread_mutex_t cont_lock_hash_lock;
typedef enum { WRITE_LOCK, READ_LOCK } lock_mode_t;
static pthread_mutex_t ds_lock;
static fru_datasource_t *data_source = NULL;
static void *ds_lib = NULL;
static int ds_lib_ref_cnt = 0;
static char *ds_lib_name = NULL;
#define FRU_NORESPONSE_RETRY 500
#define RETRY(expr) \
{ for (int loop = 0; loop < FRU_NORESPONSE_RETRY && \
(expr) == FRU_NORESPONSE; loop++) ; \
}
static const char *fru_errmsg[] =
{
"Success",
"Node not found",
"IO error",
"No registry definition for this element",
"Not container",
"Invalid handle",
"Invalid Segment",
"Invalid Path",
"Invalid Element",
"Invalid Data size (does not match registry definition)",
"Duplicate Segment",
"Not Field",
"No space available",
"Data could not be found",
"Iteration full",
"Invalid Permisions",
"Feature not Supported",
"Element is not Tagged",
"Failed to read container device",
"Segment Corrupt",
"Data Corrupt",
"General LIBFRU FAILURE",
"Walk terminated",
"FRU No response",
"Unknown error"
};
fru_errno_t
fru_encryption_supported(void)
{
if (encrypt_func == NULL)
return (FRU_NOTSUP);
else
return (FRU_SUCCESS);
}
extern "C" {
void
init_libfru(void)
{
void *crypt_lib = NULL;
encrypt_func = NULL;
crypt_lib = dlopen(ENCRYPTION_LIB_NAME, RTLD_LAZY);
if (crypt_lib != NULL) {
encrypt_func = (fru_encrypt_func_t)dlsym(crypt_lib,
FRU_ENCRYPT_FUNC_NAME);
}
}
#pragma init(init_libfru)
}
static void
add_cont_lock(cont_lock_t *lock)
{
cont_lock_t *prev = NULL;
int hash_bucket = lock->handle % CONT_LOCK_HASH_NUM;
if (cont_lock_hash[hash_bucket] == NULL) {
cont_lock_hash[hash_bucket] = lock;
} else {
cont_lock_t *prev = cont_lock_hash[hash_bucket];
while (prev->next != NULL) {
prev = prev->next;
}
prev->next = lock;
}
}
static cont_lock_t *
find_cont_lock(fru_nodehdl_t handle)
{
int hash_bucket = handle % CONT_LOCK_HASH_NUM;
cont_lock_t *which = cont_lock_hash[hash_bucket];
while (which != NULL) {
if (which->handle == handle) {
break;
}
which = which->next;
}
return (which);
}
static cont_lock_t *
alloc_cont_lock(fru_nodehdl_t handle)
{
cont_lock_t *lock = (cont_lock_t *)malloc(sizeof (cont_lock_t));
if (lock == NULL) {
return (NULL);
}
lock->handle = handle;
if (pthread_rwlock_init(&(lock->lock), NULL) != 0) {
free(lock);
return (NULL);
}
lock->next = NULL;
return (lock);
}
static fru_errno_t
lock_container(lock_mode_t mode, fru_nodehdl_t handle)
{
cont_lock_t *which = NULL;
int hash_bucket = 0;
int lock_rc;
pthread_mutex_lock(&cont_lock_hash_lock);
which = find_cont_lock(handle);
if (which == NULL) {
if ((which = alloc_cont_lock(handle)) == NULL) {
pthread_mutex_unlock(&cont_lock_hash_lock);
return (FRU_FAILURE);
}
add_cont_lock(which);
}
lock_rc = 0;
switch (mode) {
case READ_LOCK:
lock_rc = pthread_rwlock_rdlock(&(which->lock));
break;
case WRITE_LOCK:
lock_rc = pthread_rwlock_wrlock(&(which->lock));
break;
}
pthread_mutex_unlock(&cont_lock_hash_lock);
if (lock_rc != 0) {
return (FRU_FAILURE);
}
return (FRU_SUCCESS);
}
#define CHK_UNLOCK_CONTAINER(handle) \
if (unlock_container(handle) != FRU_SUCCESS) { \
return (FRU_FAILURE); \
}
static fru_errno_t
unlock_container(fru_nodehdl_t handle)
{
cont_lock_t *which = NULL;
pthread_mutex_lock(&cont_lock_hash_lock);
which = find_cont_lock(handle);
if (which == NULL) {
pthread_mutex_unlock(&cont_lock_hash_lock);
return (FRU_NODENOTFOUND);
}
if (pthread_rwlock_unlock(&(which->lock)) != 0) {
pthread_mutex_unlock(&cont_lock_hash_lock);
return (FRU_FAILURE);
}
pthread_mutex_unlock(&cont_lock_hash_lock);
return (FRU_SUCCESS);
}
static fru_errno_t
clear_cont_locks(void)
{
pthread_mutex_lock(&cont_lock_hash_lock);
for (int i = 0; i < CONT_LOCK_HASH_NUM; i++) {
cont_lock_t *cur = cont_lock_hash[i];
while (cur != NULL) {
cont_lock_t *tmp = cur;
cur = cur->next;
pthread_rwlock_destroy(&(tmp->lock));
free(tmp);
}
cont_lock_hash[i] = NULL;
}
pthread_mutex_unlock(&cont_lock_hash_lock);
return (FRU_SUCCESS);
}
fru_errno_t
fru_open_data_source(const char *name, ...)
{
fru_errno_t err = FRU_SUCCESS;
va_list args;
int num_args = 0;
char **init_args = NULL;
char *tmp;
int i = 0;
char ds_name[PATH_MAX];
fru_datasource_t *ds = NULL;
void *tmp_lib = NULL;
pthread_mutex_lock(&ds_lock);
if ((ds_lib_name != NULL) && (data_source != NULL)) {
if ((strcmp(ds_lib_name, name) == 0)) {
ds_lib_ref_cnt++;
pthread_mutex_unlock(&ds_lock);
return (FRU_SUCCESS);
} else {
pthread_mutex_unlock(&ds_lock);
return (FRU_FAILURE);
}
}
snprintf(ds_name, sizeof (ds_name), "libfru%s.so.%d",
name, LIBFRU_DS_VER);
tmp_lib = dlopen(ds_name, RTLD_LAZY);
if (tmp_lib == NULL) {
pthread_mutex_unlock(&ds_lock);
return (FRU_NOTSUP);
}
ds = (fru_datasource_t *)dlsym(tmp_lib,
DATA_SOURCE_OBJ_NAME);
if (ds == NULL) {
pthread_mutex_unlock(&ds_lock);
return (FRU_FAILURE);
}
va_start(args, name);
tmp = va_arg(args, char *);
while (tmp != NULL) {
num_args++;
tmp = va_arg(args, char *);
}
va_end(args);
init_args = (char **)malloc(sizeof (char *) * num_args);
if (init_args == NULL) {
pthread_mutex_unlock(&ds_lock);
return (FRU_FAILURE);
}
va_start(args, name);
for (tmp = va_arg(args, char *), i = 0;
(tmp != NULL) && (i < num_args);
tmp = va_arg(args, char *), i++) {
init_args[i] = tmp;
}
va_end(args);
if ((err = ds->initialize(num_args, init_args)) == FRU_SUCCESS) {
ds_lib = tmp_lib;
data_source = ds;
ds_lib_name = strdup(name);
ds_lib_ref_cnt++;
}
free(init_args);
pthread_mutex_unlock(&ds_lock);
return (err);
}
fru_errno_t
fru_close_data_source(void)
{
fru_errno_t err = FRU_SUCCESS;
if (ds_lib_ref_cnt == 0) {
return (FRU_FAILURE);
}
pthread_mutex_lock(&ds_lock);
if ((--ds_lib_ref_cnt) == 0) {
err = data_source->shutdown();
clear_cont_locks();
dlclose(ds_lib);
ds_lib = NULL;
free(ds_lib_name);
ds_lib_name = NULL;
data_source = NULL;
}
pthread_mutex_unlock(&ds_lock);
return (err);
}
int
segment_is_encrypted(fru_nodehdl_t container, const char *seg_name)
{
fru_errno_t err = FRU_SUCCESS;
fru_segdef_t segdef;
if (data_source == NULL) {
return (0);
}
RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container),
seg_name, &segdef))
if (err != FRU_SUCCESS) {
return (0);
}
return (segdef.desc.field.encrypted == 1);
}
static fru_errno_t
get_seg_list_from_ds(fru_nodehdl_t node, fru_strlist_t *list)
{
fru_errno_t err = FRU_SUCCESS;
fru_strlist_t raw_list;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_seg_list(NODEHDL_TO_TREEHDL(node),
&raw_list))
if (err != FRU_SUCCESS) {
return (err);
}
list->num = 0;
list->strs = (char **)malloc(sizeof (*(list->strs)) * raw_list.num);
if (list->strs == NULL) {
fru_destroy_strlist(&raw_list);
return (err);
}
for (int i = 0; i < raw_list.num; i++) {
if (segment_is_encrypted(node, raw_list.strs[i])) {
if (fru_encryption_supported() == FRU_SUCCESS) {
list->strs[list->num]
= strdup(raw_list.strs[i]);
list->num++;
}
} else {
list->strs[list->num] = strdup(raw_list.strs[i]);
list->num++;
}
}
fru_destroy_strlist(&raw_list);
return (FRU_SUCCESS);
}
const char *
fru_strerror(fru_errno_t errnum)
{
if ((errnum < (sizeof (fru_errmsg)/sizeof (*fru_errmsg))) &&
(errnum >= 0)) {
return (gettext(fru_errmsg[errnum]));
}
return (gettext
(fru_errmsg[(sizeof (fru_errmsg)/sizeof (*fru_errmsg))]));
}
fru_errno_t
fru_get_root(fru_nodehdl_t *handle)
{
fru_errno_t err = FRU_SUCCESS;
fru_treehdl_t tr_root;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_root(&tr_root))
if (err == FRU_SUCCESS) {
*handle = TREEHDL_TO_NODEHDL(tr_root);
}
return (err);
}
fru_errno_t
fru_get_child(fru_nodehdl_t handle, fru_nodehdl_t *child)
{
fru_errno_t err = FRU_SUCCESS;
fru_treehdl_t tr_child;
fru_node_t type;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_child(NODEHDL_TO_TREEHDL(handle),
&tr_child))
if (err != FRU_SUCCESS) {
return (err);
}
RETRY(err = data_source->get_node_type(tr_child, &type))
if (err != FRU_SUCCESS) {
return (err);
}
if ((type == FRU_NODE_LOCATION) ||
(type == FRU_NODE_FRU) ||
(type == FRU_NODE_CONTAINER)) {
*child = TREEHDL_TO_NODEHDL(tr_child);
return (FRU_SUCCESS);
}
do {
RETRY(err = data_source->get_peer(tr_child, &tr_child))
if (err != FRU_SUCCESS) {
return (err);
}
RETRY(err = data_source->get_node_type(tr_child, &type))
if (err != FRU_SUCCESS) {
return (err);
}
if ((type == FRU_NODE_LOCATION) ||
(type == FRU_NODE_FRU) ||
(type == FRU_NODE_CONTAINER)) {
*child = TREEHDL_TO_NODEHDL(tr_child);
return (FRU_SUCCESS);
}
} while (1);
}
fru_errno_t
fru_get_peer(fru_nodehdl_t handle, fru_nodehdl_t *peer)
{
fru_errno_t err = FRU_SUCCESS;
fru_treehdl_t tr_peer = NODEHDL_TO_TREEHDL(handle);
fru_node_t type;
if (data_source == NULL) {
return (FRU_FAILURE);
}
do {
RETRY(err = data_source->get_peer(tr_peer, &tr_peer))
if (err != FRU_SUCCESS) {
return (err);
}
RETRY(err = data_source->get_node_type(tr_peer, &type))
if (err != FRU_SUCCESS) {
return (err);
}
if ((type == FRU_NODE_LOCATION) ||
(type == FRU_NODE_FRU) ||
(type == FRU_NODE_CONTAINER)) {
*peer = TREEHDL_TO_NODEHDL(tr_peer);
return (FRU_SUCCESS);
}
} while (1);
}
fru_errno_t
fru_get_parent(fru_nodehdl_t handle, fru_nodehdl_t *parent)
{
fru_errno_t err = FRU_SUCCESS;
fru_treehdl_t tr_parent;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_parent(NODEHDL_TO_TREEHDL(handle),
&tr_parent))
if (err == FRU_SUCCESS) {
*parent = TREEHDL_TO_NODEHDL(tr_parent);
}
return (err);
}
fru_errno_t
fru_get_name_from_hdl(fru_nodehdl_t handle, char **name)
{
fru_errno_t err = FRU_SUCCESS;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_name_from_hdl(NODEHDL_TO_TREEHDL(handle),
name))
return (err);
}
extern "C" fru_errno_t
fru_walk_tree(fru_nodehdl_t node, const char *prior_path,
fru_errno_t (*process_node)(fru_nodehdl_t node,
const char *path,
const char *name, void *args,
end_node_fp_t *end_node,
void **end_args),
void *args)
{
void *end_args = NULL;
char *name = NULL, *path;
int prior_length;
fru_errno_t status;
fru_nodehdl_t next;
end_node_fp_t end_node = NULL;
if ((status = fru_get_name_from_hdl(node, &name)) != FRU_SUCCESS)
return (status);
else if (name == NULL)
return (FRU_FAILURE);
prior_length = strlen(prior_path);
path = (char *)alloca(prior_length + sizeof ("/") + strlen(name));
(void) sprintf(path, "%s/%s", prior_path, name);
free(name);
name = path + prior_length + 1;
assert(process_node != NULL);
if ((status = process_node(node, path, name, args,
&end_node, &end_args))
!= FRU_SUCCESS) {
if (end_node) end_node(node, path, name, end_args);
return (status);
}
if ((status = fru_get_child(node, &next)) == FRU_SUCCESS)
status = fru_walk_tree(next, path, process_node, args);
else if (status == FRU_NODENOTFOUND)
status = FRU_SUCCESS;
if (end_node) end_node(node, path, name, end_args);
if (status != FRU_SUCCESS)
return (status);
if ((status = fru_get_peer(node, &next)) == FRU_SUCCESS)
status = fru_walk_tree(next, prior_path, process_node, args);
else if (status == FRU_NODENOTFOUND)
status = FRU_SUCCESS;
return (status);
}
int
fru_pathmatch(const char *path, const char *searchpath)
{
const char *match;
if (((match = strstr(path, searchpath)) != NULL) &&
((match + strlen(searchpath)) == (path + strlen(path))) &&
((match == path) || (*(match - 1) == '/')))
return (1);
return (0);
}
fru_errno_t
fru_get_node_type(fru_nodehdl_t handle, fru_node_t *type)
{
fru_errno_t err = FRU_SUCCESS;
fru_node_t tmp;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_node_type(NODEHDL_TO_TREEHDL(handle),
&tmp))
if (err == FRU_SUCCESS) {
*type = tmp;
}
return (err);
}
static fru_errno_t
is_container(fru_nodehdl_t handle)
{
fru_errno_t err = FRU_SUCCESS;
fru_node_t type;
if ((err = fru_get_node_type(handle, &type)) != FRU_SUCCESS) {
return (err);
}
if (type == FRU_NODE_CONTAINER) {
return (FRU_SUCCESS);
}
return (FRU_NOTCONTAINER);
}
fru_errno_t
fru_destroy_enum(fru_enum_t *e)
{
if (e == NULL) {
return (FRU_SUCCESS);
}
if (e->text != NULL)
free(e->text);
return (FRU_SUCCESS);
}
fru_errno_t
fru_destroy_strlist(fru_strlist_t *list)
{
if (list == NULL) {
return (FRU_SUCCESS);
}
if (list->strs != NULL) {
for (int i = 0; i < list->num; i++) {
if (list->strs[i] != NULL)
free(list->strs[i]);
}
free(list->strs);
}
list->num = 0;
return (FRU_SUCCESS);
}
fru_errno_t
fru_destroy_elemdef(fru_elemdef_t *def)
{
if (def == NULL) {
return (FRU_SUCCESS);
}
if (def->enum_table != NULL) {
for (int i = 0; i < def->enum_count; i++)
fru_destroy_enum(&(def->enum_table[i]));
free(def->enum_table);
}
def->enum_count = 0;
if (def->example_string != NULL)
free(def->example_string);
return (FRU_SUCCESS);
}
fru_errno_t
fru_list_segments(fru_nodehdl_t container, fru_strlist_t *list)
{
fru_errno_t err = FRU_SUCCESS;
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
err = get_seg_list_from_ds(container, list);
CHK_UNLOCK_CONTAINER(container);
return (err);
}
fru_errno_t
fru_create_segment(fru_nodehdl_t container, fru_segdef_t *def)
{
fru_errno_t err = FRU_SUCCESS;
int i = 0;
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((def->desc.field.encrypted == 1) &&
(fru_encryption_supported() == FRU_NOTSUP)) {
return (FRU_NOTSUP);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
fru_strlist_t seg_list;
RETRY(err = data_source->get_seg_list(NODEHDL_TO_TREEHDL(container),
&seg_list))
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
return (err);
}
for (i = 0; i < seg_list.num; i++) {
if (strncmp(seg_list.strs[i], def->name, FRU_SEGNAMELEN)
== 0) {
fru_destroy_strlist(&seg_list);
CHK_UNLOCK_CONTAINER(container);
return (FRU_DUPSEG);
}
}
fru_destroy_strlist(&seg_list);
RETRY(err = data_source->add_seg(NODEHDL_TO_TREEHDL(container), def))
CHK_UNLOCK_CONTAINER(container);
return (err);
}
fru_errno_t
fru_remove_segment(fru_nodehdl_t container, const char *seg_name)
{
fru_errno_t err = FRU_SUCCESS;
if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
return (FRU_INVALSEG);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
if ((segment_is_encrypted(container, seg_name)) &&
(fru_encryption_supported() == FRU_NOTSUP)) {
err = FRU_INVALSEG;
} else {
RETRY(err =
data_source->delete_seg(NODEHDL_TO_TREEHDL(container),
seg_name))
}
CHK_UNLOCK_CONTAINER(container);
return (err);
}
fru_errno_t
fru_get_segment_def(fru_nodehdl_t container, const char *seg_name,
fru_segdef_t *definition)
{
fru_errno_t err = FRU_SUCCESS;
if ((seg_name == NULL) || (strlen(seg_name) > 2)) {
return (FRU_INVALSEG);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
fru_segdef_t segdef;
RETRY(err = data_source->get_seg_def(NODEHDL_TO_TREEHDL(container),
seg_name, &segdef))
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
return (err);
}
if ((segdef.desc.field.encrypted == 1) &&
(fru_encryption_supported() == FRU_NOTSUP)) {
CHK_UNLOCK_CONTAINER(container);
return (FRU_INVALSEG);
}
definition->version = segdef.version;
strlcpy(definition->name, segdef.name, FRU_SEGNAMELEN+1);
definition->desc = segdef.desc;
definition->size = segdef.size;
definition->address = segdef.address;
definition->hw_desc = segdef.hw_desc;
CHK_UNLOCK_CONTAINER(container);
return (FRU_SUCCESS);
}
fru_errno_t
fru_list_elems_in(fru_nodehdl_t container, const char *seg_name,
fru_strlist_t *list)
{
fru_errno_t err = FRU_SUCCESS;
fru_tag_t *tags = NULL;
int i = 0;
int num_tags = 0;
fru_strlist_t rc_list;
if ((seg_name == NULL) || (strlen(seg_name) > 2)) {
return (FRU_INVALSEG);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
if ((segment_is_encrypted(container, seg_name)) &&
(fru_encryption_supported() == FRU_NOTSUP)) {
CHK_UNLOCK_CONTAINER(container);
return (FRU_INVALSEG);
}
RETRY(err = data_source->get_tag_list(NODEHDL_TO_TREEHDL(container),
seg_name, &tags, &num_tags))
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
return (err);
}
if (num_tags == 0) {
CHK_UNLOCK_CONTAINER(container);
list->num = 0;
list->strs = NULL;
return (FRU_SUCCESS);
}
rc_list.num = 0;
rc_list.strs = (char **)malloc(num_tags * sizeof (char *));
if (rc_list.strs == NULL) {
CHK_UNLOCK_CONTAINER(container);
free(tags);
return (FRU_FAILURE);
}
for (i = 0; i < num_tags; i++) {
const fru_regdef_t *def = fru_reg_lookup_def_by_tag(tags[i]);
if (def != NULL) {
rc_list.strs[i] = strdup(def->name);
if (rc_list.strs[i] == NULL) {
CHK_UNLOCK_CONTAINER(container);
fru_destroy_strlist(&rc_list);
free(tags);
return (FRU_FAILURE);
}
} else {
rc_list.strs[i] = strdup(UNKNOWN_PATH);
if (rc_list.strs[i] == NULL) {
CHK_UNLOCK_CONTAINER(container);
fru_destroy_strlist(&rc_list);
free(tags);
return (FRU_FAILURE);
}
}
rc_list.num++;
}
CHK_UNLOCK_CONTAINER(container);
list->num = rc_list.num;
list->strs = rc_list.strs;
free(tags);
return (FRU_SUCCESS);
}
extern "C" fru_errno_t
fru_for_each_segment(fru_nodehdl_t container,
int (*function)(fru_seghdl_t segment, void *args),
void *args)
{
fru_errno_t status;
if (data_source == NULL) {
return (FRU_FAILURE);
}
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
RETRY(status =
data_source->for_each_segment(NODEHDL_TO_TREEHDL(container),
function, args))
CHK_UNLOCK_CONTAINER(container);
return (status);
}
fru_errno_t
fru_get_segment_name(fru_seghdl_t segment, char **name)
{
fru_errno_t err = FRU_SUCCESS;
assert(data_source != NULL);
RETRY(err = data_source->get_segment_name(NODEHDL_TO_TREEHDL(segment),
name))
return (err);
}
extern "C" fru_errno_t
fru_for_each_packet(fru_seghdl_t segment,
int (*function)(fru_tag_t *tag, uint8_t *payload,
size_t length, void *args),
void *args)
{
fru_errno_t err = FRU_SUCCESS;
assert(data_source != NULL);
RETRY(err = data_source->for_each_packet(NODEHDL_TO_TREEHDL(segment),
function, args))
return (err);
}
struct TagInstPair
{
int inst;
fru_tag_t tag;
};
struct tag_inst_hist_t
{
TagInstPair *pairs;
unsigned size;
unsigned numStored;
};
static fru_errno_t
update_tag_inst_hist(tag_inst_hist_t *hist, fru_tag_t tag)
{
int found = 0;
for (int s = 0; s < (hist->numStored); s++) {
if (tags_equal((hist->pairs)[s].tag, tag)) {
hist->pairs[s].inst++;
found = 1;
break;
}
}
if (!found) {
if (hist->numStored > hist->size) {
return (FRU_FAILURE);
}
(hist->pairs)[(hist->numStored)].tag.raw_data = tag.raw_data;
(hist->pairs)[(hist->numStored)].inst = 0;
(hist->numStored)++;
}
return (FRU_SUCCESS);
}
static fru_errno_t
get_tag_inst_from_hist(tag_inst_hist_t *hist, fru_tag_t tag, int *instance)
{
int j = 0;
for (j = 0; j < hist->numStored; j++) {
if (tags_equal((hist->pairs)[j].tag, tag)) {
*instance = (hist->pairs)[j].inst;
return (FRU_SUCCESS);
}
}
return (FRU_FAILURE);
}
static fru_errno_t
find_unknown_element(fru_tag_t *tags, int num_tags,
int *instance, fru_tag_t *tag)
{
fru_errno_t err = FRU_SUCCESS;
tag_inst_hist_t hist;
hist.pairs = (TagInstPair *)alloca(sizeof (TagInstPair) * num_tags);
if (hist.pairs == NULL) {
return (FRU_FAILURE);
}
hist.numStored = 0;
hist.size = num_tags;
int found = 0;
int instFound = 0;
int i = 0;
for (i = 0; i < num_tags; i++) {
const fru_regdef_t *def = fru_reg_lookup_def_by_tag(tags[i]);
if (def == NULL) {
if (update_tag_inst_hist(&hist, tags[i])
!= FRU_SUCCESS) {
return (FRU_FAILURE);
}
if ((instFound + 1) > (*instance)) {
found = 1;
break;
} else {
instFound++;
}
}
}
*instance -= instFound;
if (!found) {
return (FRU_DATANOTFOUND);
}
(*tag).raw_data = tags[i].raw_data;
if (get_tag_inst_from_hist(&hist, tags[i], instance) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
return (FRU_SUCCESS);
}
static fru_errno_t
find_known_element(fru_tag_t *tags, int num_tags, Ancestor *ants,
int *instance, Ancestor **correct,
int *tagInstance)
{
int j = 0;
Ancestor *cur = ants;
int num_posible = 0;
while (cur != NULL) {
num_posible++;
cur = cur->next;
}
tag_inst_hist_t hist;
hist.pairs = (TagInstPair *)alloca(sizeof (TagInstPair) * num_posible);
hist.size = num_posible;
if (hist.pairs == NULL) {
return (FRU_FAILURE);
}
hist.numStored = 0;
*correct = NULL;
int i = 0;
int found = 0;
int instancesFound = 0;
for (i = 0; i < num_tags; i++) {
cur = ants;
while (cur != NULL) {
if (tags_equal(cur->getTag(), tags[i])) {
if (update_tag_inst_hist(&hist, tags[i])
!= FRU_SUCCESS) {
return (FRU_FAILURE);
}
if ((instancesFound + cur->getNumInstances())
> (*instance)) {
*correct = cur;
found = 1;
break;
}
instancesFound += cur->getNumInstances();
}
cur = cur->next;
}
if (found == 1) {
break;
}
}
*instance -= instancesFound;
if (!found) {
return (FRU_DATANOTFOUND);
}
if (get_tag_inst_from_hist(&hist, tags[i], tagInstance)
!= FRU_SUCCESS) {
return (FRU_FAILURE);
}
return (FRU_SUCCESS);
}
static fru_errno_t
find_known_element_abs(fru_tag_t *tags, int num_tags, int *instance,
PathDef *head, Ancestor *ants, Ancestor **correct,
int *tagInstance)
{
*correct = NULL;
Ancestor *cur = ants;
while (cur != NULL) {
if (strcmp(cur->getDef()->name, head->def->name) == 0) {
*correct = cur;
break;
}
cur = cur->next;
}
if (cur == NULL) {
return (FRU_FAILURE);
}
int found = 0;
(*tagInstance) = 0;
for (int i = 0; i < num_tags; i++) {
if (tags_equal(cur->getTag(), tags[i])) {
if (((*tagInstance) +1) > (*instance)) {
*correct = cur;
found = 1;
break;
}
(*tagInstance)++;
}
}
*instance -= (*tagInstance);
if (!found) {
return (FRU_DATANOTFOUND);
}
return (FRU_SUCCESS);
}
#define READ_MODE 0
#define UPDATE_MODE 1
static fru_errno_t get_payload(fru_nodehdl_t container,
const char *seg_name,
int instance,
const char *field_path,
PathDef **pathDef,
Ancestor **ancestors,
Ancestor **correct,
int *tagInstance,
int *instLeft,
uint8_t **payload,
size_t *payloadLen,
int mode)
{
int abs_path_flg = 0;
fru_errno_t err = FRU_SUCCESS;
int num_tags = 0;
fru_tag_t *tags = NULL;
if (data_source == NULL) {
return (FRU_FAILURE);
}
RETRY(err = data_source->get_tag_list(NODEHDL_TO_TREEHDL(container),
seg_name, &tags, &num_tags))
if (err != FRU_SUCCESS) {
return (err);
}
if (num_tags == 0) {
*instLeft = instance;
return (FRU_DATANOTFOUND);
}
if (IS_UNKNOWN_PATH(field_path)) {
fru_tag_t tagToRead;
*pathDef = NULL;
*correct = *ancestors = NULL;
*tagInstance = 0;
int unknown_inst = instance;
if ((err = find_unknown_element(tags, num_tags, &unknown_inst,
&tagToRead)) != FRU_SUCCESS) {
*instLeft = unknown_inst;
free(tags);
return (err);
}
RETRY(err =
data_source->get_tag_data(NODEHDL_TO_TREEHDL(container),
seg_name, tagToRead, unknown_inst, payload,
payloadLen))
free(tags);
return (err);
}
err = fru_field_parser(field_path, ancestors,
&abs_path_flg, pathDef);
if (err != FRU_SUCCESS) {
free(tags);
return (err);
} else if (ancestors == NULL) {
free(tags);
delete pathDef;
return (FRU_INVALELEMENT);
}
if ((mode == UPDATE_MODE) && (abs_path_flg != 1)) {
free(tags);
delete *ancestors;
delete *pathDef;
return (FRU_INVALPATH);
}
if (abs_path_flg == 1) {
if ((err = find_known_element_abs(tags, num_tags, &instance,
*pathDef, *ancestors, correct, tagInstance))
!= FRU_SUCCESS) {
*instLeft = instance;
free(tags);
delete *ancestors;
delete *pathDef;
return (err);
}
} else {
if ((err = find_known_element(tags, num_tags, *ancestors,
&instance, correct, tagInstance))
!= FRU_SUCCESS) {
*instLeft = instance;
free(tags);
delete *ancestors;
delete *pathDef;
return (err);
}
}
*instLeft = instance;
RETRY(err = data_source->get_tag_data(NODEHDL_TO_TREEHDL(container),
seg_name, (*correct)->getTag(), (*tagInstance), payload,
payloadLen))
free(tags);
if (err != FRU_SUCCESS) {
delete *ancestors;
delete *pathDef;
}
return (err);
}
static fru_errno_t
do_decryption(fru_nodehdl_t container, const char *seg_name,
uint8_t *payload, size_t payloadLen)
{
fru_errno_t err = FRU_SUCCESS;
if (segment_is_encrypted(container, seg_name)) {
if (fru_encryption_supported() == FRU_SUCCESS) {
if ((err = encrypt_func(FRU_DECRYPT,
payload, payloadLen)) != FRU_SUCCESS) {
return (err);
}
} else {
return (FRU_FAILURE);
}
}
return (FRU_SUCCESS);
}
static fru_errno_t
get_seg_and_payload(fru_nodehdl_t container,
char **seg_name,
int instance,
const char *field_path,
PathDef **pathDef,
Ancestor **ancestors,
Ancestor **correct,
int *tagInstance,
int *instLeft,
uint8_t **payload,
size_t *payloadLen)
{
fru_errno_t err = FRU_SUCCESS;
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (field_path == NULL)
return (FRU_INVALPATH);
if ((*seg_name) != NULL) {
if (strlen((const char *)(*seg_name)) > FRU_SEGNAMELEN) {
return (FRU_INVALSEG);
}
if ((err = get_payload(container, (const char *)(*seg_name),
instance, field_path, pathDef, ancestors, correct,
tagInstance, instLeft, payload, payloadLen, READ_MODE))
!= FRU_SUCCESS) {
return (err);
}
return (do_decryption(container, (const char *)(*seg_name),
*payload, *payloadLen));
} else {
fru_strlist_t seg_list;
if ((err = get_seg_list_from_ds(container, &seg_list))
!= FRU_SUCCESS) {
return (err);
}
int found = 0;
for (int i = 0; i < seg_list.num; i++) {
err = get_payload(container,
seg_list.strs[i],
instance, field_path,
pathDef, ancestors, correct,
tagInstance, instLeft,
payload, payloadLen, READ_MODE);
if (err == FRU_SUCCESS) {
(*seg_name) = strdup(seg_list.strs[i]);
fru_destroy_strlist(&seg_list);
return (do_decryption(container,
(const char *)(*seg_name),
*payload, *payloadLen));
} else if (err == FRU_DATANOTFOUND) {
instance = *instLeft;
} else {
fru_destroy_strlist(&seg_list);
return (err);
}
}
fru_destroy_strlist(&seg_list);
return (FRU_DATANOTFOUND);
}
}
fru_errno_t
fru_read_field(fru_nodehdl_t container,
char **seg_name, unsigned int instance,
const char *field_path,
void **data, size_t *data_len,
char **found_path)
{
fru_errno_t err = FRU_SUCCESS;
*data = NULL;
*data_len = 0;
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
PathDef *pathDef;
Ancestor *ancestors;
Ancestor *correctAnt;
int tagInstance = 0;
int instWIPayload = 0;
uint8_t *payload;
size_t payloadLen = 0;
err = get_seg_and_payload(container, seg_name, instance, field_path,
&pathDef, &ancestors, &correctAnt, &tagInstance,
&instWIPayload, &payload, &payloadLen);
CHK_UNLOCK_CONTAINER(container);
if (err != FRU_SUCCESS) {
return (err);
}
if (pathDef == NULL) {
delete ancestors;
delete pathDef;
free(payload);
*data = (void *)malloc(payloadLen);
if ((*data) == NULL) {
return (FRU_FAILURE);
}
memcpy(*data, payload, payloadLen);
*data_len = payloadLen;
if (found_path != NULL) {
*found_path = strdup(UNKNOWN_PATH);
}
return (FRU_SUCCESS);
}
err = PayloadReader::readData(pathDef, correctAnt,
instWIPayload,
payload, payloadLen,
data, data_len);
delete pathDef;
free(payload);
if (err == FRU_SUCCESS) {
if (found_path != NULL) {
*found_path = (char *)malloc(
strlen(correctAnt->getPath(instWIPayload))
+ strlen(field_path) + 2);
if ((*found_path) == NULL) {
delete ancestors;
return (FRU_FAILURE);
}
sprintf(*found_path, "%s%s",
correctAnt->getPath(instWIPayload),
field_path);
}
}
delete ancestors;
return (err);
}
fru_errno_t
fru_update_field(fru_nodehdl_t container,
char *seg_name, unsigned int instance,
const char *field_path,
void *data, size_t length)
{
fru_errno_t err = FRU_SUCCESS;
if ((field_path == NULL) || IS_UNKNOWN_PATH(field_path)) {
return (FRU_INVALPATH);
} else if (seg_name == NULL) {
return (FRU_INVALSEG);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
PathDef *pathDef;
Ancestor *ancestors;
Ancestor *correctAnt;
int tagInstance = 0;
int instWIPayload = 0;
uint8_t *payload;
size_t payloadLen = 0;
err = get_payload(container, seg_name, instance, field_path,
&pathDef, &ancestors, &correctAnt, &tagInstance,
&instWIPayload, &payload, &payloadLen, UPDATE_MODE);
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
return (err);
}
if ((err = do_decryption(container, (const char *)seg_name,
payload, payloadLen)) != FRU_SUCCESS) {
free(payload);
return (err);
}
err = PayloadReader::updateData(pathDef, correctAnt, instWIPayload,
payload, payloadLen,
data, length);
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
delete ancestors;
delete pathDef;
free(payload);
return (err);
}
if ((segment_is_encrypted(container, seg_name)) &&
(fru_encryption_supported() == FRU_SUCCESS)) {
if ((err = encrypt_func(FRU_ENCRYPT, payload, payloadLen))
!= FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
delete ancestors;
delete pathDef;
free(payload);
return (err);
}
}
RETRY(err = data_source->set_tag_data(NODEHDL_TO_TREEHDL(container),
seg_name, correctAnt->getTag(),
tagInstance, payload, payloadLen))
CHK_UNLOCK_CONTAINER(container);
delete ancestors;
free(payload);
delete pathDef;
return (err);
}
fru_errno_t
fru_get_num_iterations(fru_nodehdl_t container,
char **seg_name,
unsigned int instance,
const char *iter_path,
int *num_there,
char **found_path)
{
fru_errno_t err = FRU_SUCCESS;
if (lock_container(READ_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
PathDef *pathDef;
Ancestor *ancestors;
Ancestor *correctAnt;
int tagInstance = 0;
int instWIPayload = 0;
uint8_t *payload;
size_t payloadLen = 0;
err = get_seg_and_payload(container, seg_name, instance, iter_path,
&pathDef, &ancestors, &correctAnt, &tagInstance,
&instWIPayload, &payload, &payloadLen);
CHK_UNLOCK_CONTAINER(container);
if (err != FRU_SUCCESS) {
return (err);
}
if (pathDef == NULL) {
err = FRU_INVALPATH;
} else {
err = PayloadReader::findIterThere(pathDef, correctAnt,
instWIPayload,
payload, payloadLen,
num_there);
}
delete pathDef;
free(payload);
if (err == FRU_SUCCESS) {
if (found_path != NULL) {
*found_path = (char *)malloc(
strlen(correctAnt->getPath(instWIPayload))
+ strlen(iter_path) + 2);
if ((*found_path) == NULL) {
delete ancestors;
return (FRU_FAILURE);
}
sprintf(*found_path, "%s%s",
correctAnt->getPath(instWIPayload),
iter_path);
}
}
delete ancestors;
return (err);
}
fru_errno_t
fill_in_iteration_control_bytes(uint8_t *data,
const fru_regdef_t *def,
int inIteration)
{
fru_errno_t rc = FRU_SUCCESS;
if ((def->iterationType == FRU_NOT_ITERATED) ||
(inIteration)) {
if (def->dataType == FDTYPE_Record) {
int offset = 0;
for (int i = 0; i < def->enumCount; i++) {
const fru_regdef_t *newDef
= fru_reg_lookup_def_by_name((char *)def->enumTable[i].text);
fru_errno_t rc2
= fill_in_iteration_control_bytes(&(data[offset]), newDef, 0);
if (rc2 != FRU_SUCCESS)
return (rc2);
offset += newDef->payloadLen;
}
}
} else {
data[3] = (char)def->iterationCount;
int offset = 3;
for (int i = 0; i < def->iterationCount; i++) {
fru_errno_t rc3
= fill_in_iteration_control_bytes(&(data[offset]), def, 1);
if (rc3 != FRU_SUCCESS)
return (rc3);
offset += ((def->payloadLen - 4)/(def->iterationCount));
}
}
return (rc);
}
fru_errno_t
fru_add_element(fru_nodehdl_t container,
const char *seg_name,
const char *element)
{
fru_errno_t err = FRU_SUCCESS;
if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
return (FRU_INVALSEG);
}
const fru_regdef_t *def
= fru_reg_lookup_def_by_name((char *)element);
if (def == NULL) {
return (FRU_NOREGDEF);
}
if (def->tagType == FRU_X) {
return (FRU_ELEMNOTTAGGED);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
fru_tag_t tag;
mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag);
uint8_t *data = new uint8_t[def->payloadLen];
memset(data, 0x00, def->payloadLen);
err = fill_in_iteration_control_bytes(data, def, 0);
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
delete[] data;
return (err);
}
if (segment_is_encrypted(container, seg_name)) {
if (fru_encryption_supported() == FRU_NOTSUP) {
CHK_UNLOCK_CONTAINER(container);
delete[] data;
return (FRU_INVALSEG);
}
if ((err = encrypt_func(FRU_ENCRYPT, data,
def->payloadLen)) != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
delete[] data;
return (err);
}
}
RETRY(err = data_source->add_tag_to_seg(NODEHDL_TO_TREEHDL(container),
seg_name, tag, data, def->payloadLen))
CHK_UNLOCK_CONTAINER(container);
delete[] data;
return (err);
}
fru_errno_t
fru_delete_element(fru_nodehdl_t container,
const char *seg_name,
unsigned int instance,
const char *element)
{
fru_errno_t err = FRU_SUCCESS;
if ((seg_name == NULL) || (strlen(seg_name) > FRU_SEGNAMELEN)) {
return (FRU_INVALSEG);
}
if (data_source == NULL) {
return (FRU_FAILURE);
}
if ((err = is_container(container)) != FRU_SUCCESS) {
return (err);
}
if (lock_container(WRITE_LOCK, container) != FRU_SUCCESS) {
return (FRU_FAILURE);
}
if ((segment_is_encrypted(container, seg_name)) &&
(fru_encryption_supported() == FRU_NOTSUP)) {
CHK_UNLOCK_CONTAINER(container);
return (FRU_INVALSEG);
}
fru_tag_t tag;
int localInst = instance;
if (strcmp(element, "UNKNOWN") == 0) {
fru_tag_t *tags = NULL;
int num_tags = 0;
RETRY(err =
data_source->get_tag_list(NODEHDL_TO_TREEHDL(container),
seg_name, &tags, &num_tags))
if (err != FRU_SUCCESS) {
CHK_UNLOCK_CONTAINER(container);
return (err);
}
if ((err = find_unknown_element(tags, num_tags,
&localInst, &tag)) != FRU_SUCCESS) {
free(tags);
CHK_UNLOCK_CONTAINER(container);
return (err);
}
free(tags);
} else {
const fru_regdef_t *def
= fru_reg_lookup_def_by_name((char *)element);
if (def == NULL) {
CHK_UNLOCK_CONTAINER(container);
return (FRU_NOREGDEF);
}
if (def->tagType == FRU_X) {
CHK_UNLOCK_CONTAINER(container);
return (FRU_ELEMNOTTAGGED);
}
mk_tag(def->tagType, def->tagDense, def->payloadLen, &tag);
}
RETRY(err = data_source->delete_tag(NODEHDL_TO_TREEHDL(container),
seg_name, tag, instance))
CHK_UNLOCK_CONTAINER(container);
return (err);
}
static fru_errno_t
make_definition(const fru_regdef_t *def, fru_elemdef_t *definition)
{
definition->version = FRU_ELEMDEF_REV;
definition->data_type = def->dataType;
if (def->tagType != FRU_X)
definition->tagged = FRU_Yes;
else
definition->tagged = FRU_No;
if (def->iterationType != FRU_NOT_ITERATED) {
int elemLen = ((def->dataLength-4)/def->iterationCount);
definition->data_length = elemLen;
} else {
definition->data_length = def->dataLength;
}
definition->disp_type = def->dispType;
definition->purgeable = def->purgeable;
definition->relocatable = def->relocatable;
definition->enum_count = 0;
definition->enum_table = NULL;
unsigned int count = def->enumCount;
if (count != 0) {
definition->enum_table = (fru_enum_t *)malloc(
(sizeof (fru_enum_t)) * count);
if ((definition->enum_table) == NULL) {
return (FRU_FAILURE);
}
memset(definition->enum_table, 0x00,
((sizeof (fru_enum_t)) * count));
}
for (int i = 0; i < count; i++) {
definition->enum_table[i].value = def->enumTable[i].value;
definition->enum_table[i].text = strdup(def->enumTable[i].text);
if ((definition->enum_table[i].text) == NULL) {
fru_destroy_elemdef(definition);
return (FRU_FAILURE);
}
(definition->enum_count)++;
}
definition->iteration_count = def->iterationCount;
definition->iteration_type = def->iterationType;
definition->example_string = strdup(def->exampleString);
if ((definition->example_string) == NULL) {
fru_destroy_elemdef(definition);
return (FRU_FAILURE);
}
return (FRU_SUCCESS);
}
fru_errno_t
fru_get_definition(const char *element_name,
fru_elemdef_t *definition)
{
int abs_path_flg = 0;
Ancestor *ancestors = NULL;
PathDef *pathDef = NULL;
fru_errno_t err = FRU_SUCCESS;
err = fru_field_parser(element_name, &ancestors,
&abs_path_flg, &pathDef);
if (err != FRU_SUCCESS) {
return (err);
}
PathDef *last = pathDef;
while (last->next != NULL)
last = last->next;
err = make_definition(last->def, definition);
delete ancestors;
delete pathDef;
return (err);
}
fru_errno_t
fru_get_registry(fru_strlist_t *list)
{
fru_errno_t err = FRU_SUCCESS;
unsigned int number = 0;
char **entries = fru_reg_list_entries(&number);
if (entries == NULL) {
return (FRU_FAILURE);
}
list->strs = entries;
list->num = number;
return (FRU_SUCCESS);
}
fru_errno_t
fru_get_tagged_parents(const char *element, fru_strlist_t *parents)
{
Ancestor *ancestors
= Ancestor::listTaggedAncestors((char *)element);
Ancestor *cur = ancestors;
int number = 0;
while (cur != NULL) {
number++;
cur = cur->next;
}
parents->num = 0;
parents->strs = NULL;
if (number == 0) {
return (FRU_SUCCESS);
}
parents->strs = (char **)malloc(number * sizeof (char *));
if (parents->strs == NULL) {
return (FRU_FAILURE);
}
memset(parents->strs, 0x00, (number * sizeof (char *)));
cur = ancestors;
for (int i = 0; i < number; i++) {
if (cur == NULL) {
fru_destroy_strlist(parents);
return (FRU_FAILURE);
}
parents->strs[i] = strdup(cur->getDef()->name);
if (parents->strs[i] == NULL) {
fru_destroy_strlist(parents);
return (FRU_FAILURE);
}
parents->num++;
cur = cur->next;
}
return (FRU_SUCCESS);
}
const char *
get_displaytype_str(fru_displaytype_t e)
{
switch (e) {
case FDISP_Binary:
return (gettext("Binary"));
case FDISP_Hex:
return (gettext("Hex"));
case FDISP_Decimal:
return (gettext("Decimal"));
case FDISP_Octal:
return (gettext("Octal"));
case FDISP_String:
return (gettext("String"));
case FDISP_Time:
return (gettext("Time"));
case FDISP_UNDEFINED:
return (gettext("UNDEFINED"));
}
return (gettext("UNDEFINED"));
}
const char *
get_datatype_str(fru_datatype_t e)
{
switch (e) {
case FDTYPE_Binary:
return (gettext("Binary"));
case FDTYPE_ByteArray:
return (gettext("Byte Array"));
case FDTYPE_ASCII:
return (gettext("ASCII"));
case FDTYPE_Unicode:
return (gettext("Unicode"));
case FDTYPE_Record:
return (gettext("Record"));
case FDTYPE_Enumeration:
return (gettext("Enumeration"));
case FDTYPE_UNDEFINED:
return (gettext("UNDEFINED"));
}
return (gettext("UNDEFINED"));
}
const char *
get_which_str(fru_which_t e)
{
switch (e) {
case FRU_No:
return (gettext("No"));
case FRU_Yes:
return (gettext("Yes"));
case FRU_WHICH_UNDEFINED:
return (gettext("WHICH UNDEFINED"));
}
return (gettext("WHICH UNDEFINED"));
}
const char *
get_itertype_str(fru_itertype_t e)
{
switch (e) {
case FRU_FIFO:
return (gettext("FIFO"));
case FRU_Circular:
return (gettext("Circular"));
case FRU_Linear:
return (gettext("Linear"));
case FRU_LIFO:
return (gettext("LIFO"));
case FRU_NOT_ITERATED:
return (gettext("NOT ITERATED"));
}
return (gettext("NOT ITERATED"));
}