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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bab75df6 was bab75df6, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Let kernel code get printf via the standard stdio header. Clean up unused includes.

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