source: mainline/kernel/generic/src/sysinfo/sysinfo.c@ 88e43bc

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

Mark unreachable consistently in kernel

At least in places that were commented as such.

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