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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fc0de8c was 5a5269d, checked in by GitHub <noreply@…>, 6 years ago

Change type of uspace pointers in kernel from pointer type to numeric (#170)

From kernel's perspective, userspace addresses are not valid pointers,
and can only be used in calls to copy_to/from_uspace().
Therefore, we change the type of those arguments and variables to
uspace_addr_t which is an alias for sysarg_t.

This allows the compiler to catch accidental direct accesses to
userspace addresses.

Additionally, to avoid losing the type information in code,
a macro uspace_ptr(type) is used that translates to uspace_addr_t.
I makes no functional difference, but allows keeping the type information
in code in case we implement some sort of static checking for it in the future.

However, ccheck doesn't like that, so instead of using uspace_ptr(char),
we use uspace_ptr_char which is defined as
#define uspace_ptr_char uspace_ptr(char).

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