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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since efb8d15 was efb8d15, checked in by Martin Decky <martin@…>, 13 years ago

dump sysinfo in a more compact way

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