HelenOS sources
This source file includes following definitions.
- sysinfo_item_constructor
- sysinfo_item_destructor
- sysinfo_init
- sysinfo_find_item
- sysinfo_create_path
- sysinfo_set_item_val
- sysinfo_set_item_data
- sysinfo_set_item_gen_val
- sysinfo_set_item_gen_data
- sysinfo_set_item_undefined
- sysinfo_set_subtree_fn
- sysinfo_indent
- sysinfo_dump_internal
- sysinfo_dump
- sysinfo_get_item
- sysinfo_get_item_uspace
- sysinfo_get_keys
- sysinfo_get_keys_uspace
- sys_sysinfo_get_keys_size
- sys_sysinfo_get_keys
- sys_sysinfo_get_val_type
- sys_sysinfo_get_value
- sys_sysinfo_get_data_size
- sys_sysinfo_get_data
#include <assert.h>
#include <sysinfo/sysinfo.h>
#include <mm/slab.h>
#include <stdio.h>
#include <syscall/copy.h>
#include <synch/mutex.h>
#include <arch/asm.h>
#include <errno.h>
#include <macros.h>
#include <stdlib.h>
#define SYSINFO_MAX_PATH 2048
bool fb_exported = false;
static sysinfo_item_t *global_root = NULL;
static slab_cache_t *sysinfo_item_cache;
static mutex_t sysinfo_lock;
_NO_TRACE static errno_t sysinfo_item_constructor(void *obj, unsigned int kmflag)
{
sysinfo_item_t *item = (sysinfo_item_t *) obj;
item->name = NULL;
item->val_type = SYSINFO_VAL_UNDEFINED;
item->subtree_type = SYSINFO_SUBTREE_NONE;
item->subtree.table = NULL;
item->next = NULL;
return EOK;
}
_NO_TRACE static size_t sysinfo_item_destructor(void *obj)
{
sysinfo_item_t *item = (sysinfo_item_t *) obj;
if (item->name != NULL)
free(item->name);
return 0;
}
void sysinfo_init(void)
{
sysinfo_item_cache = slab_cache_create("sysinfo_item_t",
sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
mutex_initialize(&sysinfo_lock, MUTEX_ACTIVE);
}
_NO_TRACE static sysinfo_item_t *sysinfo_find_item(const char *name,
sysinfo_item_t *subtree, sysinfo_return_t **ret, bool dry_run)
{
assert(subtree != NULL);
sysinfo_item_t *cur = subtree;
while (cur != NULL) {
size_t i = 0;
while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
i++;
if ((name[i] == 0) && (cur->name[i] == 0))
return cur;
if ((name[i] == '.') && (cur->name[i] == 0)) {
switch (cur->subtree_type) {
case SYSINFO_SUBTREE_TABLE:
return sysinfo_find_item(name + i + 1,
cur->subtree.table, ret, dry_run);
case SYSINFO_SUBTREE_FUNCTION:
if (ret != NULL)
**ret = cur->subtree.generator.fn(name + i + 1,
dry_run, cur->subtree.generator.data);
return NULL;
default:
if (ret != NULL)
*ret = NULL;
return NULL;
}
}
cur = cur->next;
}
if (ret != NULL)
*ret = NULL;
return NULL;
}
_NO_TRACE static sysinfo_item_t *sysinfo_create_path(const char *name,
sysinfo_item_t **psubtree)
{
assert(psubtree != NULL);
if (*psubtree == NULL) {
size_t i = 0;
while ((name[i] != 0) && (name[i] != '.'))
i++;
*psubtree =
(sysinfo_item_t *) slab_alloc(sysinfo_item_cache, FRAME_ATOMIC);
if (!*psubtree)
return NULL;
(*psubtree)->name = str_ndup(name, i);
if (!(*psubtree)->name) {
slab_free(sysinfo_item_cache, *psubtree);
return NULL;
}
if (name[i] == '.') {
(*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
sysinfo_item_t *item = sysinfo_create_path(name + i + 1,
&((*psubtree)->subtree.table));
if (!item) {
free((*psubtree)->name);
slab_free(sysinfo_item_cache, *psubtree);
}
return item;
}
return *psubtree;
}
sysinfo_item_t *cur = *psubtree;
while (cur != NULL) {
size_t i = 0;
while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
i++;
if ((name[i] == 0) && (cur->name[i] == 0))
return cur;
if ((name[i] == '.') && (cur->name[i] == 0)) {
switch (cur->subtree_type) {
case SYSINFO_SUBTREE_NONE:
cur->subtree_type = SYSINFO_SUBTREE_TABLE;
return sysinfo_create_path(name + i + 1,
&(cur->subtree.table));
case SYSINFO_SUBTREE_TABLE:
return sysinfo_create_path(name + i + 1,
&(cur->subtree.table));
default:
return NULL;
}
}
if (cur->next == NULL) {
i = 0;
while ((name[i] != 0) && (name[i] != '.'))
i++;
sysinfo_item_t *item =
(sysinfo_item_t *) slab_alloc(sysinfo_item_cache, FRAME_ATOMIC);
if (!item)
return NULL;
cur->next = item;
item->name = str_ndup(name, i);
if (!item->name) {
slab_free(sysinfo_item_cache, item);
return NULL;
}
if (name[i] == '.') {
item->subtree_type = SYSINFO_SUBTREE_TABLE;
sysinfo_item_t *sub = sysinfo_create_path(
name + i + 1, &(item->subtree.table));
if (!sub) {
free(item->name);
slab_free(sysinfo_item_cache, item);
return NULL;
}
return sub;
}
return item;
}
cur = cur->next;
}
unreachable();
}
void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
sysarg_t val)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) {
item->val_type = SYSINFO_VAL_VAL;
item->val.val = val;
} else {
printf("Could not set sysinfo item %s.\n", name);
}
mutex_unlock(&sysinfo_lock);
}
void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
void *data, size_t size)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) {
item->val_type = SYSINFO_VAL_DATA;
item->val.data.data = data;
item->val.data.size = size;
} else {
printf("Could not set sysinfo item %s.\n", name);
}
mutex_unlock(&sysinfo_lock);
}
void sysinfo_set_item_gen_val(const char *name, sysinfo_item_t **root,
sysinfo_fn_val_t fn, void *data)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) {
item->val_type = SYSINFO_VAL_FUNCTION_VAL;
item->val.gen_val.fn = fn;
item->val.gen_val.data = data;
} else {
printf("Could not set sysinfo item %s.\n", name);
}
mutex_unlock(&sysinfo_lock);
}
void sysinfo_set_item_gen_data(const char *name, sysinfo_item_t **root,
sysinfo_fn_data_t fn, void *data)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL) {
item->val_type = SYSINFO_VAL_FUNCTION_DATA;
item->val.gen_data.fn = fn;
item->val.gen_data.data = data;
} else {
printf("Could not set sysinfo item %s.\n", name);
}
mutex_unlock(&sysinfo_lock);
}
void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if (item != NULL)
item->val_type = SYSINFO_VAL_UNDEFINED;
else
printf("Could not set sysinfo item %s.\n", name);
mutex_unlock(&sysinfo_lock);
}
void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
sysinfo_fn_subtree_t fn, void *data)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
root = &global_root;
sysinfo_item_t *item = sysinfo_create_path(name, root);
if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
item->subtree.generator.fn = fn;
item->subtree.generator.data = data;
} else {
printf("Could not set sysinfo item %s.\n", name);
}
mutex_unlock(&sysinfo_lock);
}
_NO_TRACE static void sysinfo_indent(size_t spaces)
{
for (size_t i = 0; i < spaces; i++)
printf(" ");
}
_NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, size_t spaces)
{
for (sysinfo_item_t *cur = root; cur; cur = cur->next) {
size_t length;
if (spaces == 0) {
printf("%s", cur->name);
length = str_length(cur->name);
} else {
sysinfo_indent(spaces);
printf(".%s", cur->name);
length = str_length(cur->name) + 1;
}
sysarg_t val;
size_t size;
switch (cur->val_type) {
case SYSINFO_VAL_UNDEFINED:
printf(" [undefined]\n");
break;
case SYSINFO_VAL_VAL:
printf(" -> %" PRIun " (%#" PRIxn ")\n", cur->val.val,
cur->val.val);
break;
case SYSINFO_VAL_DATA:
printf(" (%zu bytes)\n", cur->val.data.size);
break;
case SYSINFO_VAL_FUNCTION_VAL:
val = cur->val.gen_val.fn(cur, cur->val.gen_val.data);
printf(" -> %" PRIun " (%#" PRIxn ") [generated]\n", val,
val);
break;
case SYSINFO_VAL_FUNCTION_DATA:
(void) cur->val.gen_data.fn(cur, &size, true,
cur->val.gen_data.data);
printf(" (%zu bytes) [generated]\n", size);
break;
default:
printf("+ %s [unknown]\n", cur->name);
}
switch (cur->subtree_type) {
case SYSINFO_SUBTREE_NONE:
break;
case SYSINFO_SUBTREE_TABLE:
sysinfo_dump_internal(cur->subtree.table, spaces + length);
break;
case SYSINFO_SUBTREE_FUNCTION:
sysinfo_indent(spaces + length);
printf("<generated subtree>\n");
break;
default:
sysinfo_indent(spaces + length);
printf("<unknown subtree>\n");
}
}
}
void sysinfo_dump(sysinfo_item_t *root)
{
mutex_lock(&sysinfo_lock);
if (root == NULL)
sysinfo_dump_internal(global_root, 0);
else
sysinfo_dump_internal(root, 0);
mutex_unlock(&sysinfo_lock);
}
_NO_TRACE static sysinfo_return_t sysinfo_get_item(const char *name,
sysinfo_item_t **root, bool dry_run)
{
if (root == NULL)
root = &global_root;
sysinfo_return_t ret;
sysinfo_return_t *ret_ptr = &ret;
sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr,
dry_run);
if (item != NULL) {
ret.tag = item->val_type;
switch (item->val_type) {
case SYSINFO_VAL_UNDEFINED:
break;
case SYSINFO_VAL_VAL:
ret.val = item->val.val;
break;
case SYSINFO_VAL_DATA:
ret.data = item->val.data;
break;
case SYSINFO_VAL_FUNCTION_VAL:
ret.val = item->val.gen_val.fn(item, item->val.gen_val.data);
break;
case SYSINFO_VAL_FUNCTION_DATA:
ret.data.data = item->val.gen_data.fn(item, &ret.data.size,
dry_run, item->val.gen_data.data);
break;
}
} else {
if (ret_ptr == NULL) {
ret.tag = SYSINFO_VAL_UNDEFINED;
}
}
return ret;
}
_NO_TRACE static sysinfo_return_t sysinfo_get_item_uspace(uspace_addr_t ptr, size_t size,
bool dry_run)
{
sysinfo_return_t ret;
ret.tag = SYSINFO_VAL_UNDEFINED;
if (size > SYSINFO_MAX_PATH)
return ret;
char *path = malloc(size + 1);
if (!path)
return ret;
if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
(path[size] == 0)) {
mutex_lock(&sysinfo_lock);
ret = sysinfo_get_item(path, NULL, dry_run);
mutex_unlock(&sysinfo_lock);
}
free(path);
return ret;
}
_NO_TRACE static sysinfo_return_t sysinfo_get_keys(const char *name,
sysinfo_item_t **root, bool dry_run)
{
if (root == NULL)
root = &global_root;
sysinfo_item_t *subtree = NULL;
if (name[0] != 0) {
sysinfo_item_t *item =
sysinfo_find_item(name, *root, NULL, dry_run);
if ((item != NULL) &&
(item->subtree_type == SYSINFO_SUBTREE_TABLE))
subtree = item->subtree.table;
} else
subtree = *root;
sysinfo_return_t ret;
ret.tag = SYSINFO_VAL_UNDEFINED;
if (subtree != NULL) {
size_t size = 0;
for (sysinfo_item_t *cur = subtree; cur; cur = cur->next)
size += str_size(cur->name) + 1;
if (dry_run) {
ret.tag = SYSINFO_VAL_DATA;
ret.data.data = NULL;
ret.data.size = size;
} else {
char *names = (char *) malloc(size);
if (names == NULL)
return ret;
size_t pos = 0;
for (sysinfo_item_t *cur = subtree; cur; cur = cur->next) {
str_cpy(names + pos, size - pos, cur->name);
pos += str_size(cur->name) + 1;
}
ret.tag = SYSINFO_VAL_DATA;
ret.data.data = (void *) names;
ret.data.size = size;
}
}
return ret;
}
_NO_TRACE static sysinfo_return_t sysinfo_get_keys_uspace(uspace_addr_t ptr, size_t size,
bool dry_run)
{
sysinfo_return_t ret;
ret.tag = SYSINFO_VAL_UNDEFINED;
ret.data.data = NULL;
ret.data.size = 0;
if (size > SYSINFO_MAX_PATH)
return ret;
char *path = malloc(size + 1);
if (!path)
return ret;
if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
(path[size] == 0)) {
mutex_lock(&sysinfo_lock);
ret = sysinfo_get_keys(path, NULL, dry_run);
mutex_unlock(&sysinfo_lock);
}
free(path);
return ret;
}
sys_errno_t sys_sysinfo_get_keys_size(uspace_addr_t path_ptr, size_t path_size,
uspace_addr_t size_ptr)
{
errno_t rc;
sysinfo_return_t ret =
sysinfo_get_keys_uspace(path_ptr, path_size, true);
if (ret.tag == SYSINFO_VAL_DATA)
rc = copy_to_uspace(size_ptr, &ret.data.size,
sizeof(ret.data.size));
else
rc = EINVAL;
return (sys_errno_t) rc;
}
sys_errno_t sys_sysinfo_get_keys(uspace_addr_t path_ptr, size_t path_size,
uspace_addr_t buffer_ptr, size_t buffer_size, uspace_ptr_size_t size_ptr)
{
errno_t rc;
sysinfo_return_t ret = sysinfo_get_keys_uspace(path_ptr, path_size,
false);
if (ret.tag == SYSINFO_VAL_DATA) {
size_t size = min(ret.data.size, buffer_size);
rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
if (rc == EOK)
rc = copy_to_uspace(size_ptr, &size, sizeof(size));
free(ret.data.data);
} else
rc = EINVAL;
return (sys_errno_t) rc;
}
sysarg_t sys_sysinfo_get_val_type(uspace_addr_t path_ptr, size_t path_size)
{
sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
ret.tag = SYSINFO_VAL_VAL;
else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
ret.tag = SYSINFO_VAL_DATA;
return (sysarg_t) ret.tag;
}
sys_errno_t sys_sysinfo_get_value(uspace_addr_t path_ptr, size_t path_size,
uspace_addr_t value_ptr)
{
errno_t rc;
sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
else
rc = EINVAL;
return (sys_errno_t) rc;
}
sys_errno_t sys_sysinfo_get_data_size(uspace_addr_t path_ptr, size_t path_size,
uspace_addr_t size_ptr)
{
errno_t rc;
sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
rc = copy_to_uspace(size_ptr, &ret.data.size,
sizeof(ret.data.size));
else
rc = EINVAL;
return (sys_errno_t) rc;
}
sys_errno_t sys_sysinfo_get_data(uspace_addr_t path_ptr, size_t path_size,
uspace_addr_t buffer_ptr, size_t buffer_size, uspace_ptr_size_t size_ptr)
{
errno_t rc;
sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size,
false);
if ((ret.tag == SYSINFO_VAL_DATA) ||
(ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
size_t size = min(ret.data.size, buffer_size);
rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
if (rc == EOK)
rc = copy_to_uspace(size_ptr, &size, sizeof(size));
} else
rc = EINVAL;
if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
free(ret.data.data);
return (sys_errno_t) rc;
}
HelenOS homepage, sources at GitHub