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

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

Remove nfmalloc()

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