source: mainline/kernel/generic/src/sysinfo/sysinfo.c@ aafed15

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aafed15 was aafed15, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Declare malloc() etc in standard <stdlib.h> rather than <mm/slab.h>

  • Property mode set to 100644
File size: 27.4 KB
RevLine 
[6326f5e6]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Vana
[196c253]3 * Copyright (c) 2012 Martin Decky
[6326f5e6]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[174156fd]30/** @addtogroup kernel_generic
[b45c443]31 * @{
32 */
33/** @file
34 */
35
[63e27ef]36#include <assert.h>
[2666daa]37#include <sysinfo/sysinfo.h>
38#include <mm/slab.h>
[bab75df6]39#include <stdio.h>
[35a96cf]40#include <syscall/copy.h>
[6b6626d3]41#include <synch/mutex.h>
[a80687e5]42#include <arch/asm.h>
[d9fae235]43#include <errno.h>
[311bc25]44#include <macros.h>
[aafed15]45#include <stdlib.h>
[d9fae235]46
[80bfb601]47/** Maximal sysinfo path length */
[d9fae235]48#define SYSINFO_MAX_PATH 2048
[2666daa]49
[a71c158]50bool fb_exported = false;
[2666daa]51
[80bfb601]52/** Global sysinfo tree root item */
[d9fae235]53static sysinfo_item_t *global_root = NULL;
[80bfb601]54
55/** Sysinfo SLAB cache */
[82d515e9]56static slab_cache_t *sysinfo_item_cache;
[d9fae235]57
[6b6626d3]58/** Sysinfo lock */
59static mutex_t sysinfo_lock;
[9dae191e]60
[80bfb601]61/** Sysinfo item constructor
62 *
63 */
[b7fd2a0]64NO_TRACE static errno_t sysinfo_item_constructor(void *obj, unsigned int kmflag)
[d9fae235]65{
66 sysinfo_item_t *item = (sysinfo_item_t *) obj;
[a35b458]67
[d9fae235]68 item->name = NULL;
69 item->val_type = SYSINFO_VAL_UNDEFINED;
70 item->subtree_type = SYSINFO_SUBTREE_NONE;
[b658c5d]71 item->subtree.table = NULL;
[d9fae235]72 item->next = NULL;
[a35b458]73
[7f11dc6]74 return EOK;
[d9fae235]75}
76
[80bfb601]77/** Sysinfo item destructor
78 *
79 * Note that the return value is not perfectly correct
80 * since more space might get actually freed thanks
81 * to the disposal of item->name
82 *
83 */
[7a0359b]84NO_TRACE static size_t sysinfo_item_destructor(void *obj)
[d9fae235]85{
86 sysinfo_item_t *item = (sysinfo_item_t *) obj;
[a35b458]87
[d9fae235]88 if (item->name != NULL)
89 free(item->name);
[a35b458]90
[d9fae235]91 return 0;
92}
93
[80bfb601]94/** Initialize sysinfo subsystem
95 *
96 * Create SLAB cache for sysinfo items.
97 *
98 */
[d9fae235]99void sysinfo_init(void)
100{
[82d515e9]101 sysinfo_item_cache = slab_cache_create("sysinfo_item_t",
[d9fae235]102 sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
103 sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
[a35b458]104
[6b6626d3]105 mutex_initialize(&sysinfo_lock, MUTEX_ACTIVE);
[d9fae235]106}
107
[80bfb601]108/** Recursively find an item in sysinfo tree
[9dae191e]109 *
[c6218327]110 * Should be called with sysinfo_lock held.
[9dae191e]111 *
[80bfb601]112 * @param name Current sysinfo path suffix.
113 * @param subtree Current sysinfo (sub)tree root item.
114 * @param ret If the return value is NULL, this argument
[0030eef]115 * can be set either to NULL (i.e. no item was
[80bfb601]116 * found and no data was generated) or the
117 * original pointer is used to store the value
118 * generated by a generated subtree function.
[e1b6742]119 * @param dry_run Do not actually get any generated
120 * binary data, just calculate the size.
[80bfb601]121 *
122 * @return Found item or NULL if no item in the fixed tree
123 * was found (N.B. ret).
124 *
[9dae191e]125 */
[7a0359b]126NO_TRACE static sysinfo_item_t *sysinfo_find_item(const char *name,
[e1b6742]127 sysinfo_item_t *subtree, sysinfo_return_t **ret, bool dry_run)
[2666daa]128{
[63e27ef]129 assert(subtree != NULL);
[a35b458]130
[d9fae235]131 sysinfo_item_t *cur = subtree;
[a35b458]132
[80bfb601]133 /* Walk all siblings */
[d9fae235]134 while (cur != NULL) {
135 size_t i = 0;
[a35b458]136
[d9fae235]137 /* Compare name with path */
138 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]139 i++;
[a35b458]140
[d9fae235]141 /* Check for perfect name and path match */
142 if ((name[i] == 0) && (cur->name[i] == 0))
143 return cur;
[a35b458]144
[d9fae235]145 /* Partial match up to the delimiter */
146 if ((name[i] == '.') && (cur->name[i] == 0)) {
147 /* Look into the subtree */
148 switch (cur->subtree_type) {
149 case SYSINFO_SUBTREE_TABLE:
150 /* Recursively find in subtree */
[9dae191e]151 return sysinfo_find_item(name + i + 1,
[e1b6742]152 cur->subtree.table, ret, dry_run);
[d9fae235]153 case SYSINFO_SUBTREE_FUNCTION:
[9dae191e]154 /* Get generated data */
[0030eef]155 if (ret != NULL)
156 **ret = cur->subtree.generator.fn(name + i + 1,
157 dry_run, cur->subtree.generator.data);
[a35b458]158
[9dae191e]159 return NULL;
[d9fae235]160 default:
[80bfb601]161 /* Not found, no data generated */
[0030eef]162 if (ret != NULL)
163 *ret = NULL;
[a35b458]164
[d9fae235]165 return NULL;
166 }
[2666daa]167 }
[a35b458]168
[d9fae235]169 cur = cur->next;
[2666daa]170 }
[a35b458]171
[80bfb601]172 /* Not found, no data generated */
[0030eef]173 if (ret != NULL)
174 *ret = NULL;
[a35b458]175
[2666daa]176 return NULL;
177}
178
[9dae191e]179/** Recursively create items in sysinfo tree
180 *
[c6218327]181 * Should be called with sysinfo_lock held.
[9dae191e]182 *
[80bfb601]183 * @param name Current sysinfo path suffix.
184 * @param psubtree Pointer to an already existing (sub)tree root
185 * item or where to store a new tree root item.
186 *
187 * @return Existing or newly allocated sysinfo item or NULL
188 * if the current tree configuration does not allow to
189 * create a new item.
190 *
[9dae191e]191 */
[7a0359b]192NO_TRACE static sysinfo_item_t *sysinfo_create_path(const char *name,
[d9fae235]193 sysinfo_item_t **psubtree)
[2666daa]194{
[63e27ef]195 assert(psubtree != NULL);
[a35b458]196
[d9fae235]197 if (*psubtree == NULL) {
198 /* No parent */
[a35b458]199
[d9fae235]200 size_t i = 0;
[a35b458]201
[d9fae235]202 /* Find the first delimiter in name */
203 while ((name[i] != 0) && (name[i] != '.'))
[7bb6b06]204 i++;
[a35b458]205
[d9fae235]206 *psubtree =
[abf6c01]207 (sysinfo_item_t *) slab_alloc(sysinfo_item_cache, FRAME_ATOMIC);
[c0ea739]208 if (!*psubtree)
209 return NULL;
[a35b458]210
[d9fae235]211 /* Fill in item name up to the delimiter */
212 (*psubtree)->name = str_ndup(name, i);
[c0ea739]213 if (!(*psubtree)->name) {
214 slab_free(sysinfo_item_cache, *psubtree);
215 return NULL;
216 }
[a35b458]217
[d9fae235]218 /* Create subtree items */
219 if (name[i] == '.') {
220 (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
[c0ea739]221 sysinfo_item_t *item = sysinfo_create_path(name + i + 1,
[d9fae235]222 &((*psubtree)->subtree.table));
[c0ea739]223 if (!item) {
224 free((*psubtree)->name);
225 slab_free(sysinfo_item_cache, *psubtree);
226 }
227 return item;
[7bb6b06]228 }
[a35b458]229
[d9fae235]230 /* No subtree needs to be created */
231 return *psubtree;
[2666daa]232 }
[a35b458]233
[d9fae235]234 sysinfo_item_t *cur = *psubtree;
[a35b458]235
[80bfb601]236 /* Walk all siblings */
[d9fae235]237 while (cur != NULL) {
238 size_t i = 0;
[a35b458]239
[d9fae235]240 /* Compare name with path */
241 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
[749122b]242 i++;
[a35b458]243
[7c3fb9b]244 /*
245 * Check for perfect name and path match
[d9fae235]246 * -> item is already present.
247 */
248 if ((name[i] == 0) && (cur->name[i] == 0))
249 return cur;
[a35b458]250
[d9fae235]251 /* Partial match up to the delimiter */
252 if ((name[i] == '.') && (cur->name[i] == 0)) {
253 switch (cur->subtree_type) {
254 case SYSINFO_SUBTREE_NONE:
255 /* No subtree yet, create one */
256 cur->subtree_type = SYSINFO_SUBTREE_TABLE;
257 return sysinfo_create_path(name + i + 1,
258 &(cur->subtree.table));
259 case SYSINFO_SUBTREE_TABLE:
260 /* Subtree already created, add new sibling */
261 return sysinfo_create_path(name + i + 1,
262 &(cur->subtree.table));
263 default:
[7c3fb9b]264 /*
265 * Subtree items handled by a function, this
[80bfb601]266 * cannot be overriden by a constant item.
[d9fae235]267 */
268 return NULL;
[749122b]269 }
[2666daa]270 }
[a35b458]271
[7c3fb9b]272 /*
273 * No match and no more siblings to check
[d9fae235]274 * -> create a new sibling item.
275 */
276 if (cur->next == NULL) {
277 /* Find the first delimiter in name */
[749122b]278 i = 0;
[d9fae235]279 while ((name[i] != 0) && (name[i] != '.'))
[749122b]280 i++;
[a35b458]281
[d9fae235]282 sysinfo_item_t *item =
[abf6c01]283 (sysinfo_item_t *) slab_alloc(sysinfo_item_cache, FRAME_ATOMIC);
[c0ea739]284 if (!item)
285 return NULL;
[a35b458]286
[d9fae235]287 cur->next = item;
[a35b458]288
[d9fae235]289 /* Fill in item name up to the delimiter */
290 item->name = str_ndup(name, i);
[c0ea739]291 if (!item->name) {
292 slab_free(sysinfo_item_cache, item);
293 return NULL;
294 }
[a35b458]295
[d9fae235]296 /* Create subtree items */
297 if (name[i] == '.') {
298 item->subtree_type = SYSINFO_SUBTREE_TABLE;
[c0ea739]299 sysinfo_item_t *sub = sysinfo_create_path(
300 name + i + 1, &(item->subtree.table));
301 if (!sub) {
302 free(item->name);
303 slab_free(sysinfo_item_cache, item);
304 return NULL;
305 }
306 return sub;
[2666daa]307 }
[a35b458]308
[d9fae235]309 /* No subtree needs to be created */
[2666daa]310 return item;
[d9fae235]311 }
[a35b458]312
[d9fae235]313 cur = cur->next;
[2666daa]314 }
[a35b458]315
[88e43bc]316 unreachable();
[2666daa]317}
318
[80bfb601]319/** Set sysinfo item with a constant numeric value
320 *
321 * @param name Sysinfo path.
322 * @param root Pointer to the root item or where to store
323 * a new root item (NULL for global sysinfo root).
324 * @param val Value to store in the item.
325 *
326 */
[d9fae235]327void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
[96b02eb9]328 sysarg_t val)
[2666daa]329{
[80bfb601]330 /* Protect sysinfo tree consistency */
[6b6626d3]331 mutex_lock(&sysinfo_lock);
[a35b458]332
[749122b]333 if (root == NULL)
[d9fae235]334 root = &global_root;
[a35b458]335
[749122b]336 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]337 if (item != NULL) {
[749122b]338 item->val_type = SYSINFO_VAL_VAL;
[d9fae235]339 item->val.val = val;
[c0ea739]340 } else {
341 printf("Could not set sysinfo item %s.\n", name);
[749122b]342 }
[a35b458]343
[6b6626d3]344 mutex_unlock(&sysinfo_lock);
[2666daa]345}
346
[80bfb601]347/** Set sysinfo item with a constant binary data
348 *
349 * Note that sysinfo only stores the pointer to the
350 * binary data and does not touch it in any way. The
351 * data should be static and immortal.
352 *
353 * @param name Sysinfo path.
354 * @param root Pointer to the root item or where to store
355 * a new root item (NULL for global sysinfo root).
356 * @param data Binary data.
357 * @param size Size of the binary data.
358 *
359 */
[d9fae235]360void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
361 void *data, size_t size)
[2666daa]362{
[80bfb601]363 /* Protect sysinfo tree consistency */
[6b6626d3]364 mutex_lock(&sysinfo_lock);
[a35b458]365
[749122b]366 if (root == NULL)
[d9fae235]367 root = &global_root;
[a35b458]368
[749122b]369 sysinfo_item_t *item = sysinfo_create_path(name, root);
[d9fae235]370 if (item != NULL) {
371 item->val_type = SYSINFO_VAL_DATA;
372 item->val.data.data = data;
373 item->val.data.size = size;
[c0ea739]374 } else {
375 printf("Could not set sysinfo item %s.\n", name);
[d9fae235]376 }
[a35b458]377
[6b6626d3]378 mutex_unlock(&sysinfo_lock);
[d9fae235]379}
380
[80bfb601]381/** Set sysinfo item with a generated numeric value
382 *
383 * @param name Sysinfo path.
384 * @param root Pointer to the root item or where to store
385 * a new root item (NULL for global sysinfo root).
386 * @param fn Numeric value generator function.
[196c253]387 * @param data Private data.
[80bfb601]388 *
389 */
[196c253]390void sysinfo_set_item_gen_val(const char *name, sysinfo_item_t **root,
391 sysinfo_fn_val_t fn, void *data)
[d9fae235]392{
[80bfb601]393 /* Protect sysinfo tree consistency */
[6b6626d3]394 mutex_lock(&sysinfo_lock);
[a35b458]395
[d9fae235]396 if (root == NULL)
397 root = &global_root;
[a35b458]398
[d9fae235]399 sysinfo_item_t *item = sysinfo_create_path(name, root);
400 if (item != NULL) {
401 item->val_type = SYSINFO_VAL_FUNCTION_VAL;
[196c253]402 item->val.gen_val.fn = fn;
403 item->val.gen_val.data = data;
[c0ea739]404 } else {
405 printf("Could not set sysinfo item %s.\n", name);
[749122b]406 }
[a35b458]407
[6b6626d3]408 mutex_unlock(&sysinfo_lock);
[2666daa]409}
410
[80bfb601]411/** Set sysinfo item with a generated binary data
412 *
413 * Note that each time the generator function is called
414 * it is supposed to return a new dynamically allocated
415 * data. This data is then freed by sysinfo in the context
416 * of the current sysinfo request.
417 *
418 * @param name Sysinfo path.
419 * @param root Pointer to the root item or where to store
420 * a new root item (NULL for global sysinfo root).
421 * @param fn Binary data generator function.
[196c253]422 * @param data Private data.
[80bfb601]423 *
424 */
[196c253]425void sysinfo_set_item_gen_data(const char *name, sysinfo_item_t **root,
426 sysinfo_fn_data_t fn, void *data)
[d9fae235]427{
[80bfb601]428 /* Protect sysinfo tree consistency */
[6b6626d3]429 mutex_lock(&sysinfo_lock);
[a35b458]430
[d9fae235]431 if (root == NULL)
432 root = &global_root;
[a35b458]433
[d9fae235]434 sysinfo_item_t *item = sysinfo_create_path(name, root);
435 if (item != NULL) {
436 item->val_type = SYSINFO_VAL_FUNCTION_DATA;
[196c253]437 item->val.gen_data.fn = fn;
438 item->val.gen_data.data = data;
[c0ea739]439 } else {
440 printf("Could not set sysinfo item %s.\n", name);
[d9fae235]441 }
[a35b458]442
[6b6626d3]443 mutex_unlock(&sysinfo_lock);
[d9fae235]444}
[2666daa]445
[80bfb601]446/** Set sysinfo item with an undefined value
447 *
448 * @param name Sysinfo path.
449 * @param root Pointer to the root item or where to store
450 * a new root item (NULL for global sysinfo root).
451 *
452 */
[749122b]453void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
[2666daa]454{
[80bfb601]455 /* Protect sysinfo tree consistency */
[6b6626d3]456 mutex_lock(&sysinfo_lock);
[a35b458]457
[749122b]458 if (root == NULL)
[d9fae235]459 root = &global_root;
[a35b458]460
[749122b]461 sysinfo_item_t *item = sysinfo_create_path(name, root);
462 if (item != NULL)
463 item->val_type = SYSINFO_VAL_UNDEFINED;
[c0ea739]464 else
465 printf("Could not set sysinfo item %s.\n", name);
[a35b458]466
[6b6626d3]467 mutex_unlock(&sysinfo_lock);
[2666daa]468}
469
[80bfb601]470/** Set sysinfo item with a generated subtree
471 *
472 * @param name Sysinfo path.
473 * @param root Pointer to the root item or where to store
474 * a new root item (NULL for global sysinfo root).
475 * @param fn Subtree generator function.
[5869ce0]476 * @param data Private data to be passed to the generator.
[80bfb601]477 *
478 */
[9dae191e]479void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
[5869ce0]480 sysinfo_fn_subtree_t fn, void *data)
[9dae191e]481{
[80bfb601]482 /* Protect sysinfo tree consistency */
[6b6626d3]483 mutex_lock(&sysinfo_lock);
[a35b458]484
[9dae191e]485 if (root == NULL)
486 root = &global_root;
[a35b458]487
[9dae191e]488 sysinfo_item_t *item = sysinfo_create_path(name, root);
[a35b458]489
[7c3fb9b]490 /*
491 * Change the type of the subtree only if it is not already
492 * a fixed subtree
493 */
[9dae191e]494 if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
495 item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
[5869ce0]496 item->subtree.generator.fn = fn;
497 item->subtree.generator.data = data;
[c0ea739]498 } else {
499 printf("Could not set sysinfo item %s.\n", name);
[9dae191e]500 }
[a35b458]501
[6b6626d3]502 mutex_unlock(&sysinfo_lock);
[9dae191e]503}
504
505/** Sysinfo dump indentation helper routine
[80bfb601]506 *
[efb8d15]507 * @param depth Number of spaces to print.
[9dae191e]508 *
509 */
[efb8d15]510NO_TRACE static void sysinfo_indent(size_t spaces)
[d9fae235]511{
[efb8d15]512 for (size_t i = 0; i < spaces; i++)
513 printf(" ");
[d9fae235]514}
[2666daa]515
[9dae191e]516/** Dump the structure of sysinfo tree
517 *
[c6218327]518 * Should be called with sysinfo_lock held.
[9dae191e]519 *
[efb8d15]520 * @param root Root item of the current (sub)tree.
521 * @param spaces Current indentation level.
[80bfb601]522 *
[9dae191e]523 */
[efb8d15]524NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, size_t spaces)
[2666daa]525{
[80bfb601]526 /* Walk all siblings */
[efb8d15]527 for (sysinfo_item_t *cur = root; cur; cur = cur->next) {
528 size_t length;
[a35b458]529
[efb8d15]530 if (spaces == 0) {
531 printf("%s", cur->name);
532 length = str_length(cur->name);
533 } else {
534 sysinfo_indent(spaces);
535 printf(".%s", cur->name);
536 length = str_length(cur->name) + 1;
537 }
[a35b458]538
[96b02eb9]539 sysarg_t val;
[d9fae235]540 size_t size;
[a35b458]541
[80bfb601]542 /* Display node value and type */
[d9fae235]543 switch (cur->val_type) {
[f8ddd17]544 case SYSINFO_VAL_UNDEFINED:
[efb8d15]545 printf(" [undefined]\n");
[f8ddd17]546 break;
547 case SYSINFO_VAL_VAL:
[8ebe212]548 printf(" -> %" PRIun " (%#" PRIxn ")\n", cur->val.val,
[efb8d15]549 cur->val.val);
[f8ddd17]550 break;
[d9fae235]551 case SYSINFO_VAL_DATA:
[efb8d15]552 printf(" (%zu bytes)\n", cur->val.data.size);
[f8ddd17]553 break;
[d9fae235]554 case SYSINFO_VAL_FUNCTION_VAL:
[196c253]555 val = cur->val.gen_val.fn(cur, cur->val.gen_val.data);
[8ebe212]556 printf(" -> %" PRIun " (%#" PRIxn ") [generated]\n", val,
[efb8d15]557 val);
[d9fae235]558 break;
559 case SYSINFO_VAL_FUNCTION_DATA:
[70e2b2d]560 /* N.B.: No data was actually returned (only a dry run) */
[196c253]561 (void) cur->val.gen_data.fn(cur, &size, true,
562 cur->val.gen_data.data);
[efb8d15]563 printf(" (%zu bytes) [generated]\n", size);
[d9fae235]564 break;
565 default:
566 printf("+ %s [unknown]\n", cur->name);
[749122b]567 }
[a35b458]568
[80bfb601]569 /* Recursivelly nest into the subtree */
[d9fae235]570 switch (cur->subtree_type) {
571 case SYSINFO_SUBTREE_NONE:
572 break;
573 case SYSINFO_SUBTREE_TABLE:
[efb8d15]574 sysinfo_dump_internal(cur->subtree.table, spaces + length);
[d9fae235]575 break;
576 case SYSINFO_SUBTREE_FUNCTION:
[efb8d15]577 sysinfo_indent(spaces + length);
578 printf("<generated subtree>\n");
[d9fae235]579 break;
580 default:
[efb8d15]581 sysinfo_indent(spaces + length);
582 printf("<unknown subtree>\n");
[d9fae235]583 }
[749122b]584 }
[2666daa]585}
586
[80bfb601]587/** Dump the structure of sysinfo tree
588 *
589 * @param root Root item of the sysinfo (sub)tree.
590 * If it is NULL then consider the global
591 * sysinfo tree.
592 *
593 */
[9dae191e]594void sysinfo_dump(sysinfo_item_t *root)
595{
[7c3fb9b]596 /*
597 * Avoid other functions to mess with sysinfo
598 * while we are dumping it
599 */
[6b6626d3]600 mutex_lock(&sysinfo_lock);
[a35b458]601
[9dae191e]602 if (root == NULL)
603 sysinfo_dump_internal(global_root, 0);
604 else
605 sysinfo_dump_internal(root, 0);
[a35b458]606
[6b6626d3]607 mutex_unlock(&sysinfo_lock);
[9dae191e]608}
609
[80bfb601]610/** Return sysinfo item value determined by name
[9dae191e]611 *
[c6218327]612 * Should be called with sysinfo_lock held.
[9dae191e]613 *
[70e2b2d]614 * @param name Sysinfo path.
615 * @param root Root item of the sysinfo (sub)tree.
616 * If it is NULL then consider the global
617 * sysinfo tree.
618 * @param dry_run Do not actually get any generated
619 * binary data, just calculate the size.
[80bfb601]620 *
621 * @return Item value (constant or generated).
622 *
[9dae191e]623 */
[7a0359b]624NO_TRACE static sysinfo_return_t sysinfo_get_item(const char *name,
[70e2b2d]625 sysinfo_item_t **root, bool dry_run)
[2666daa]626{
[749122b]627 if (root == NULL)
[d9fae235]628 root = &global_root;
[a35b458]629
[80bfb601]630 /* Try to find the item or generate data */
[d9fae235]631 sysinfo_return_t ret;
[9dae191e]632 sysinfo_return_t *ret_ptr = &ret;
[e1b6742]633 sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr,
634 dry_run);
[a35b458]635
[749122b]636 if (item != NULL) {
[80bfb601]637 /* Item found in the fixed sysinfo tree */
[a35b458]638
[9dae191e]639 ret.tag = item->val_type;
[d9fae235]640 switch (item->val_type) {
641 case SYSINFO_VAL_UNDEFINED:
642 break;
643 case SYSINFO_VAL_VAL:
[749122b]644 ret.val = item->val.val;
[d9fae235]645 break;
646 case SYSINFO_VAL_DATA:
647 ret.data = item->val.data;
648 break;
649 case SYSINFO_VAL_FUNCTION_VAL:
[196c253]650 ret.val = item->val.gen_val.fn(item, item->val.gen_val.data);
[d9fae235]651 break;
652 case SYSINFO_VAL_FUNCTION_DATA:
[196c253]653 ret.data.data = item->val.gen_data.fn(item, &ret.data.size,
654 dry_run, item->val.gen_data.data);
[d9fae235]655 break;
656 }
[9dae191e]657 } else {
[80bfb601]658 /* No item in the fixed sysinfo tree */
659 if (ret_ptr == NULL) {
660 /* Even no data was generated */
[9dae191e]661 ret.tag = SYSINFO_VAL_UNDEFINED;
[80bfb601]662 }
[9dae191e]663 }
[a35b458]664
[d9fae235]665 return ret;
666}
667
[9dae191e]668/** Return sysinfo item determined by name from user space
669 *
[b4ad39f]670 * The path string passed from the user space has to be properly null-terminated
[80bfb601]671 * (the last passed character must be null).
672 *
[70e2b2d]673 * @param ptr Sysinfo path in the user address space.
674 * @param size Size of the path string.
675 * @param dry_run Do not actually get any generated
676 * binary data, just calculate the size.
[9dae191e]677 *
678 */
[7a0359b]679NO_TRACE static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size,
[70e2b2d]680 bool dry_run)
[d9fae235]681{
682 sysinfo_return_t ret;
683 ret.tag = SYSINFO_VAL_UNDEFINED;
[a35b458]684
[d9fae235]685 if (size > SYSINFO_MAX_PATH)
686 return ret;
[a35b458]687
[4f3aa76]688 // TODO: Change this so that allocation is not needed.
689 char *path = malloc(size + 1);
690 if (!path)
691 return ret;
[a35b458]692
[3d23553]693 if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
694 (path[size] == 0)) {
[b4ad39f]695 /*
696 * Prevent other functions from messing with sysinfo while we
697 * are reading it.
698 */
[6b6626d3]699 mutex_lock(&sysinfo_lock);
[70e2b2d]700 ret = sysinfo_get_item(path, NULL, dry_run);
[6b6626d3]701 mutex_unlock(&sysinfo_lock);
[b4ad39f]702 }
[a35b458]703
[9dae191e]704 free(path);
[2666daa]705 return ret;
706}
[35a96cf]707
[0030eef]708/** Return sysinfo keys determined by name
709 *
710 * Should be called with sysinfo_lock held.
711 *
712 * @param name Sysinfo path.
713 * @param root Root item of the sysinfo (sub)tree.
714 * If it is NULL then consider the global
715 * sysinfo tree.
716 * @param dry_run Do not actually get any generated
717 * binary data, just calculate the size.
718 *
719 * @return Item value (constant or generated).
720 *
721 */
722NO_TRACE static sysinfo_return_t sysinfo_get_keys(const char *name,
723 sysinfo_item_t **root, bool dry_run)
724{
725 if (root == NULL)
726 root = &global_root;
[a35b458]727
[76f382b]728 sysinfo_item_t *subtree = NULL;
[a35b458]729
[76f382b]730 if (name[0] != 0) {
731 /* Try to find the item */
732 sysinfo_item_t *item =
733 sysinfo_find_item(name, *root, NULL, dry_run);
734 if ((item != NULL) &&
735 (item->subtree_type == SYSINFO_SUBTREE_TABLE))
736 subtree = item->subtree.table;
737 } else
738 subtree = *root;
[a35b458]739
[0030eef]740 sysinfo_return_t ret;
[dd20cbb]741 ret.tag = SYSINFO_VAL_UNDEFINED;
[a35b458]742
[76f382b]743 if (subtree != NULL) {
[0030eef]744 /*
745 * Calculate the size of subkeys.
746 */
747 size_t size = 0;
[76f382b]748 for (sysinfo_item_t *cur = subtree; cur; cur = cur->next)
[0030eef]749 size += str_size(cur->name) + 1;
[a35b458]750
[0030eef]751 if (dry_run) {
[76f382b]752 ret.tag = SYSINFO_VAL_DATA;
[0030eef]753 ret.data.data = NULL;
754 ret.data.size = size;
755 } else {
756 /* Allocate buffer for subkeys */
[11b285d]757 char *names = (char *) malloc(size);
[68f4671]758 if (names == NULL)
[0030eef]759 return ret;
[a35b458]760
[0030eef]761 size_t pos = 0;
[76f382b]762 for (sysinfo_item_t *cur = subtree; cur; cur = cur->next) {
[0030eef]763 str_cpy(names + pos, size - pos, cur->name);
764 pos += str_size(cur->name) + 1;
765 }
[a35b458]766
[0030eef]767 /* Correct return value */
[76f382b]768 ret.tag = SYSINFO_VAL_DATA;
[0030eef]769 ret.data.data = (void *) names;
770 ret.data.size = size;
771 }
772 }
[a35b458]773
[0030eef]774 return ret;
775}
776
777/** Return sysinfo keys determined by name from user space
778 *
779 * The path string passed from the user space has to be properly
780 * null-terminated (the last passed character must be null).
781 *
782 * @param ptr Sysinfo path in the user address space.
783 * @param size Size of the path string.
784 * @param dry_run Do not actually get any generated
785 * binary data, just calculate the size.
786 *
787 */
788NO_TRACE static sysinfo_return_t sysinfo_get_keys_uspace(void *ptr, size_t size,
789 bool dry_run)
790{
791 sysinfo_return_t ret;
792 ret.tag = SYSINFO_VAL_UNDEFINED;
[2a08005]793 ret.data.data = NULL;
794 ret.data.size = 0;
[a35b458]795
[0030eef]796 if (size > SYSINFO_MAX_PATH)
797 return ret;
[a35b458]798
[4f3aa76]799 // TODO: Change this so that allocation is not needed.
800 char *path = malloc(size + 1);
801 if (!path)
802 return ret;
[a35b458]803
[0030eef]804 if ((copy_from_uspace(path, ptr, size + 1) == 0) &&
805 (path[size] == 0)) {
806 /*
807 * Prevent other functions from messing with sysinfo while we
808 * are reading it.
809 */
810 mutex_lock(&sysinfo_lock);
811 ret = sysinfo_get_keys(path, NULL, dry_run);
812 mutex_unlock(&sysinfo_lock);
813 }
[a35b458]814
[0030eef]815 free(path);
816 return ret;
817}
818
819/** Get the sysinfo keys size (syscall)
820 *
821 * The path string passed from the user space has
822 * to be properly null-terminated (the last passed
823 * character must be null).
824 *
825 * @param path_ptr Sysinfo path in the user address space.
826 * @param path_size Size of the path string.
827 * @param size_ptr User space pointer where to store the
828 * keys size.
829 *
830 * @return Error code (EOK in case of no error).
831 *
832 */
[b7fd2a0]833sys_errno_t sys_sysinfo_get_keys_size(void *path_ptr, size_t path_size,
[0030eef]834 void *size_ptr)
835{
[b7fd2a0]836 errno_t rc;
[a35b458]837
[0030eef]838 /*
839 * Get the keys.
840 *
841 * N.B.: There is no need to free any potential keys
842 * since we request a dry run.
843 */
844 sysinfo_return_t ret =
845 sysinfo_get_keys_uspace(path_ptr, path_size, true);
[a35b458]846
[0030eef]847 /* Check return data tag */
848 if (ret.tag == SYSINFO_VAL_DATA)
849 rc = copy_to_uspace(size_ptr, &ret.data.size,
850 sizeof(ret.data.size));
851 else
852 rc = EINVAL;
[a35b458]853
[b7fd2a0]854 return (sys_errno_t) rc;
[0030eef]855}
856
857/** Get the sysinfo keys (syscall)
858 *
859 * The path string passed from the user space has
860 * to be properly null-terminated (the last passed
861 * character must be null).
862 *
863 * If the user space buffer size does not equal
864 * the actual size of the returned data, the data
865 * is truncated.
866 *
867 * The actual size of data returned is stored to
868 * size_ptr.
869 *
870 * @param path_ptr Sysinfo path in the user address space.
871 * @param path_size Size of the path string.
872 * @param buffer_ptr User space pointer to the buffer where
873 * to store the binary data.
874 * @param buffer_size User space buffer size.
875 * @param size_ptr User space pointer where to store the
876 * binary data size.
877 *
878 * @return Error code (EOK in case of no error).
879 *
880 */
[b7fd2a0]881sys_errno_t sys_sysinfo_get_keys(void *path_ptr, size_t path_size,
[0030eef]882 void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
883{
[b7fd2a0]884 errno_t rc;
[a35b458]885
[0030eef]886 /* Get the keys */
887 sysinfo_return_t ret = sysinfo_get_keys_uspace(path_ptr, path_size,
888 false);
[a35b458]889
[0030eef]890 /* Check return data tag */
891 if (ret.tag == SYSINFO_VAL_DATA) {
892 size_t size = min(ret.data.size, buffer_size);
893 rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
894 if (rc == EOK)
895 rc = copy_to_uspace(size_ptr, &size, sizeof(size));
[a35b458]896
[0030eef]897 free(ret.data.data);
898 } else
899 rc = EINVAL;
[a35b458]900
[b7fd2a0]901 return (sys_errno_t) rc;
[0030eef]902}
903
[80bfb601]904/** Get the sysinfo value type (syscall)
905 *
906 * The path string passed from the user space has
907 * to be properly null-terminated (the last passed
908 * character must be null).
909 *
910 * @param path_ptr Sysinfo path in the user address space.
911 * @param path_size Size of the path string.
912 *
913 * @return Item value type.
914 *
915 */
[9a426d1f]916sysarg_t sys_sysinfo_get_val_type(void *path_ptr, size_t path_size)
[d9fae235]917{
[b4ad39f]918 /*
919 * Get the item.
920 *
921 * N.B.: There is no need to free any potential generated
922 * binary data since we request a dry run.
923 */
[70e2b2d]924 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[a35b458]925
[b4ad39f]926 /*
[3d23553]927 * Map generated value types to constant types (user space does
928 * not care whether the value is constant or generated).
[b4ad39f]929 */
[9dae191e]930 if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
931 ret.tag = SYSINFO_VAL_VAL;
932 else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
933 ret.tag = SYSINFO_VAL_DATA;
[a35b458]934
[96b02eb9]935 return (sysarg_t) ret.tag;
[d9fae235]936}
[5719f6d]937
[80bfb601]938/** Get the sysinfo numerical value (syscall)
939 *
940 * The path string passed from the user space has
941 * to be properly null-terminated (the last passed
942 * character must be null).
943 *
944 * @param path_ptr Sysinfo path in the user address space.
945 * @param path_size Size of the path string.
946 * @param value_ptr User space pointer where to store the
947 * numberical value.
948 *
949 * @return Error code (EOK in case of no error).
950 *
951 */
[b7fd2a0]952sys_errno_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
[d9fae235]953 void *value_ptr)
[35a96cf]954{
[b7fd2a0]955 errno_t rc;
[a35b458]956
[b4ad39f]957 /*
958 * Get the item.
959 *
[3d23553]960 * N.B.: There is no need to free any potential generated binary
961 * data since we request a dry run.
[b4ad39f]962 */
963 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[a35b458]964
[80bfb601]965 /* Only constant or generated numerical value is returned */
[9dae191e]966 if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
967 rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
968 else
969 rc = EINVAL;
[a35b458]970
[b7fd2a0]971 return (sys_errno_t) rc;
[d9fae235]972}
[5719f6d]973
[80bfb601]974/** Get the sysinfo binary data size (syscall)
975 *
976 * The path string passed from the user space has
977 * to be properly null-terminated (the last passed
978 * character must be null).
979 *
980 * @param path_ptr Sysinfo path in the user address space.
981 * @param path_size Size of the path string.
982 * @param size_ptr User space pointer where to store the
983 * binary data size.
984 *
985 * @return Error code (EOK in case of no error).
986 *
987 */
[b7fd2a0]988sys_errno_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
[d9fae235]989 void *size_ptr)
990{
[b7fd2a0]991 errno_t rc;
[a35b458]992
[b4ad39f]993 /*
994 * Get the item.
995 *
[3d23553]996 * N.B.: There is no need to free any potential generated binary
997 * data since we request a dry run.
[b4ad39f]998 */
[70e2b2d]999 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
[a35b458]1000
[80bfb601]1001 /* Only the size of constant or generated binary data is considered */
[9dae191e]1002 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
1003 rc = copy_to_uspace(size_ptr, &ret.data.size,
1004 sizeof(ret.data.size));
1005 else
1006 rc = EINVAL;
[a35b458]1007
[b7fd2a0]1008 return (sys_errno_t) rc;
[35a96cf]1009}
1010
[80bfb601]1011/** Get the sysinfo binary data (syscall)
1012 *
1013 * The path string passed from the user space has
1014 * to be properly null-terminated (the last passed
1015 * character must be null).
1016 *
[311bc25]1017 * If the user space buffer size does not equal
1018 * the actual size of the returned data, the data
1019 * is truncated. Whether this is actually a fatal
1020 * error or the data can be still interpreted as valid
1021 * depends on the nature of the data and has to be
1022 * decided by the user space.
1023 *
1024 * The actual size of data returned is stored to
1025 * size_ptr.
[80bfb601]1026 *
1027 * @param path_ptr Sysinfo path in the user address space.
1028 * @param path_size Size of the path string.
1029 * @param buffer_ptr User space pointer to the buffer where
1030 * to store the binary data.
1031 * @param buffer_size User space buffer size.
[311bc25]1032 * @param size_ptr User space pointer where to store the
1033 * binary data size.
[80bfb601]1034 *
1035 * @return Error code (EOK in case of no error).
1036 *
1037 */
[b7fd2a0]1038sys_errno_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
[311bc25]1039 void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
[35a96cf]1040{
[b7fd2a0]1041 errno_t rc;
[a35b458]1042
[80bfb601]1043 /* Get the item */
[311bc25]1044 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size,
1045 false);
[a35b458]1046
[80bfb601]1047 /* Only constant or generated binary data is considered */
[311bc25]1048 if ((ret.tag == SYSINFO_VAL_DATA) ||
1049 (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
1050 size_t size = min(ret.data.size, buffer_size);
1051 rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
1052 if (rc == EOK)
1053 rc = copy_to_uspace(size_ptr, &size, sizeof(size));
[9dae191e]1054 } else
1055 rc = EINVAL;
[a35b458]1056
[80bfb601]1057 /* N.B.: The generated binary data should be freed */
[9dae191e]1058 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
1059 free(ret.data.data);
[a35b458]1060
[b7fd2a0]1061 return (sys_errno_t) rc;
[35a96cf]1062}
[b45c443]1063
[cc73a8a1]1064/** @}
[b45c443]1065 */
Note: See TracBrowser for help on using the repository browser.