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

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

fix possible garbage dereference (subtree.table always needs to be initialized to NULL)

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Vana
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup generic
30 * @{
31 */
32/** @file
33 */
34
35#include <sysinfo/sysinfo.h>
36#include <mm/slab.h>
37#include <print.h>
38#include <syscall/copy.h>
39#include <errno.h>
40
41#define SYSINFO_MAX_PATH 2048
42
43bool fb_exported = false;
44
45static sysinfo_item_t *global_root = NULL;
46static slab_cache_t *sysinfo_item_slab;
47
48static int sysinfo_item_constructor(void *obj, int kmflag)
49{
50 sysinfo_item_t *item = (sysinfo_item_t *) obj;
51
52 item->name = NULL;
53 item->val_type = SYSINFO_VAL_UNDEFINED;
54 item->subtree_type = SYSINFO_SUBTREE_NONE;
55 item->subtree.table = NULL;
56 item->next = NULL;
57
58 return 0;
59}
60
61static int sysinfo_item_destructor(void *obj)
62{
63 sysinfo_item_t *item = (sysinfo_item_t *) obj;
64
65 if (item->name != NULL)
66 free(item->name);
67
68 return 0;
69}
70
71void sysinfo_init(void)
72{
73 sysinfo_item_slab = slab_cache_create("sysinfo_item_slab",
74 sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
75 sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
76}
77
78static sysinfo_item_t *sysinfo_find_item(const char *name,
79 sysinfo_item_t *subtree)
80{
81 sysinfo_item_t *cur = subtree;
82
83 while (cur != NULL) {
84 size_t i = 0;
85
86 /* Compare name with path */
87 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
88 i++;
89
90 /* Check for perfect name and path match */
91 if ((name[i] == 0) && (cur->name[i] == 0))
92 return cur;
93
94 /* Partial match up to the delimiter */
95 if ((name[i] == '.') && (cur->name[i] == 0)) {
96 /* Look into the subtree */
97 switch (cur->subtree_type) {
98 case SYSINFO_SUBTREE_TABLE:
99 /* Recursively find in subtree */
100 return sysinfo_find_item(name + i + 1, cur->subtree.table);
101 case SYSINFO_SUBTREE_FUNCTION:
102 /* Get generated item */
103 return cur->subtree.find_item(name + i + 1);
104 default:
105 /* Not found */
106 return NULL;
107 }
108 }
109
110 cur = cur->next;
111 }
112
113 return NULL;
114}
115
116static sysinfo_item_t *sysinfo_create_path(const char *name,
117 sysinfo_item_t **psubtree)
118{
119 ASSERT(psubtree != NULL);
120
121 if (*psubtree == NULL) {
122 /* No parent */
123
124 size_t i = 0;
125
126 /* Find the first delimiter in name */
127 while ((name[i] != 0) && (name[i] != '.'))
128 i++;
129
130 *psubtree =
131 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
132 ASSERT(*psubtree);
133
134 /* Fill in item name up to the delimiter */
135 (*psubtree)->name = str_ndup(name, i);
136 ASSERT((*psubtree)->name);
137
138 /* Create subtree items */
139 if (name[i] == '.') {
140 (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
141 return sysinfo_create_path(name + i + 1,
142 &((*psubtree)->subtree.table));
143 }
144
145 /* No subtree needs to be created */
146 return *psubtree;
147 }
148
149 sysinfo_item_t *cur = *psubtree;
150
151 while (cur != NULL) {
152 size_t i = 0;
153
154 /* Compare name with path */
155 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
156 i++;
157
158 /* Check for perfect name and path match
159 * -> item is already present.
160 */
161 if ((name[i] == 0) && (cur->name[i] == 0))
162 return cur;
163
164 /* Partial match up to the delimiter */
165 if ((name[i] == '.') && (cur->name[i] == 0)) {
166 switch (cur->subtree_type) {
167 case SYSINFO_SUBTREE_NONE:
168 /* No subtree yet, create one */
169 cur->subtree_type = SYSINFO_SUBTREE_TABLE;
170 return sysinfo_create_path(name + i + 1,
171 &(cur->subtree.table));
172 case SYSINFO_SUBTREE_TABLE:
173 /* Subtree already created, add new sibling */
174 return sysinfo_create_path(name + i + 1,
175 &(cur->subtree.table));
176 default:
177 /* Subtree items handled by a function, this
178 * cannot be overriden.
179 */
180 return NULL;
181 }
182 }
183
184 /* No match and no more siblings to check
185 * -> create a new sibling item.
186 */
187 if (cur->next == NULL) {
188 /* Find the first delimiter in name */
189 i = 0;
190 while ((name[i] != 0) && (name[i] != '.'))
191 i++;
192
193 sysinfo_item_t *item =
194 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
195 ASSERT(item);
196
197 cur->next = item;
198
199 /* Fill in item name up to the delimiter */
200 item->name = str_ndup(name, i);
201 ASSERT(item->name);
202
203 /* Create subtree items */
204 if (name[i] == '.') {
205 item->subtree_type = SYSINFO_SUBTREE_TABLE;
206 return sysinfo_create_path(name + i + 1,
207 &(item->subtree.table));
208 }
209
210 /* No subtree needs to be created */
211 return item;
212 }
213
214 /* Get next sibling */
215 cur = cur->next;
216 }
217
218 /* Unreachable */
219 ASSERT(false);
220 return NULL;
221}
222
223void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
224 unative_t val)
225{
226 if (root == NULL)
227 root = &global_root;
228
229 sysinfo_item_t *item = sysinfo_create_path(name, root);
230 if (item != NULL) {
231 item->val_type = SYSINFO_VAL_VAL;
232 item->val.val = val;
233 }
234}
235
236void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
237 void *data, size_t size)
238{
239 if (root == NULL)
240 root = &global_root;
241
242 sysinfo_item_t *item = sysinfo_create_path(name, root);
243 if (item != NULL) {
244 item->val_type = SYSINFO_VAL_DATA;
245 item->val.data.data = data;
246 item->val.data.size = size;
247 }
248}
249
250void sysinfo_set_item_val_fn(const char *name, sysinfo_item_t **root,
251 sysinfo_fn_val_t fn)
252{
253 if (root == NULL)
254 root = &global_root;
255
256 sysinfo_item_t *item = sysinfo_create_path(name, root);
257 if (item != NULL) {
258 item->val_type = SYSINFO_VAL_FUNCTION_VAL;
259 item->val.fn_val = fn;
260 }
261}
262
263void sysinfo_set_item_data_fn(const char *name, sysinfo_item_t **root,
264 sysinfo_fn_data_t fn)
265{
266 if (root == NULL)
267 root = &global_root;
268
269 sysinfo_item_t *item = sysinfo_create_path(name, root);
270 if (item != NULL) {
271 item->val_type = SYSINFO_VAL_FUNCTION_DATA;
272 item->val.fn_data = fn;
273 }
274}
275
276void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
277{
278 if (root == NULL)
279 root = &global_root;
280
281 sysinfo_item_t *item = sysinfo_create_path(name, root);
282 if (item != NULL)
283 item->val_type = SYSINFO_VAL_UNDEFINED;
284}
285
286static void sysinfo_indent(unsigned int depth)
287{
288 unsigned int i;
289 for (i = 0; i < depth; i++)
290 printf(" ");
291}
292
293void sysinfo_dump(sysinfo_item_t **proot, unsigned int depth)
294{
295 if (proot == NULL)
296 proot = &global_root;
297
298 sysinfo_item_t *cur = *proot;
299
300 while (cur != NULL) {
301 sysinfo_indent(depth);
302
303 unative_t val;
304 size_t size;
305
306 switch (cur->val_type) {
307 case SYSINFO_VAL_UNDEFINED:
308 printf("+ %s\n", cur->name);
309 break;
310 case SYSINFO_VAL_VAL:
311 printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
312 cur->val.val, cur->val.val);
313 break;
314 case SYSINFO_VAL_DATA:
315 printf("+ %s (%" PRIs" bytes)\n", cur->name,
316 cur->val.data.size);
317 break;
318 case SYSINFO_VAL_FUNCTION_VAL:
319 val = cur->val.fn_val(cur);
320 printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
321 cur->name, val, val);
322 break;
323 case SYSINFO_VAL_FUNCTION_DATA:
324 cur->val.fn_data(cur, &size);
325 printf("+ %s (%" PRIs" bytes) [generated]\n", cur->name,
326 size);
327 break;
328 default:
329 printf("+ %s [unknown]\n", cur->name);
330 }
331
332 switch (cur->subtree_type) {
333 case SYSINFO_SUBTREE_NONE:
334 break;
335 case SYSINFO_SUBTREE_TABLE:
336 sysinfo_dump(&(cur->subtree.table), depth + 1);
337 break;
338 case SYSINFO_SUBTREE_FUNCTION:
339 sysinfo_indent(depth + 1);
340 printf(" [generated subtree]\n");
341 break;
342 default:
343 sysinfo_indent(depth + 1);
344 printf(" [unknown subtree]\n");
345 }
346
347 cur = cur->next;
348 }
349}
350
351sysinfo_return_t sysinfo_get_item(const char *name, sysinfo_item_t **root)
352{
353 if (root == NULL)
354 root = &global_root;
355
356 sysinfo_item_t *item = sysinfo_find_item(name, *root);
357 sysinfo_return_t ret;
358
359 if (item != NULL) {
360 switch (item->val_type) {
361 case SYSINFO_VAL_UNDEFINED:
362 ret.tag = SYSINFO_VAL_UNDEFINED;
363 break;
364 case SYSINFO_VAL_VAL:
365 ret.tag = SYSINFO_VAL_VAL;
366 ret.val = item->val.val;
367 break;
368 case SYSINFO_VAL_DATA:
369 ret.tag = SYSINFO_VAL_DATA;
370 ret.data = item->val.data;
371 break;
372 case SYSINFO_VAL_FUNCTION_VAL:
373 ret.tag = SYSINFO_VAL_VAL;
374 ret.val = item->val.fn_val(item);
375 break;
376 case SYSINFO_VAL_FUNCTION_DATA:
377 ret.tag = SYSINFO_VAL_DATA;
378 ret.data.data = item->val.fn_data(item, &ret.data.size);
379 break;
380 }
381 } else
382 ret.tag = SYSINFO_VAL_UNDEFINED;
383
384 return ret;
385}
386
387static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size)
388{
389 sysinfo_return_t ret;
390 ret.tag = SYSINFO_VAL_UNDEFINED;
391
392 if (size > SYSINFO_MAX_PATH)
393 return ret;
394
395 char *path = (char *) malloc(size + 1, 0);
396 ASSERT(path);
397
398 if ((copy_from_uspace(path, ptr, size + 1) == 0)
399 && (path[size] == 0)) {
400 ret = sysinfo_get_item(path, NULL);
401 free(path);
402 }
403
404 return ret;
405}
406
407unative_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
408{
409 return (unative_t) sysinfo_get_item_uspace(path_ptr, path_size).tag;
410}
411
412unative_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
413 void *value_ptr)
414{
415 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
416
417 if (ret.tag != SYSINFO_VAL_VAL)
418 return (unative_t) EINVAL;
419
420 return (unative_t) copy_to_uspace(value_ptr, &ret.val,
421 sizeof(ret.val));
422}
423
424unative_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
425 void *size_ptr)
426{
427 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
428
429 if (ret.tag != SYSINFO_VAL_DATA)
430 return (unative_t) EINVAL;
431
432 return (unative_t) copy_to_uspace(size_ptr, &ret.data.size,
433 sizeof(ret.data.size));
434}
435
436unative_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
437 void *buffer_ptr, size_t buffer_size)
438{
439 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
440
441 if (ret.tag != SYSINFO_VAL_DATA)
442 return (unative_t) EINVAL;
443
444 if (ret.data.size != buffer_size)
445 return ENOMEM;
446
447 return (unative_t) copy_to_uspace(buffer_ptr, ret.data.data,
448 ret.data.size);
449}
450
451/** @}
452 */
Note: See TracBrowser for help on using the repository browser.