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

Last change on this file was 74b92e6, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 months ago

Fix sysinfo locking

Turns out sysinfo doesn't like spinlock

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