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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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