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

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

Allow sysinfo_create_path() to fail gracefully

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