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

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

Mark unreachable consistently in kernel

At least in places that were commented as such.

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