Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/sysinfo/sysinfo.c

    ra71c158 r311bc25  
    3737#include <print.h>
    3838#include <syscall/copy.h>
     39#include <synch/mutex.h>
     40#include <arch/asm.h>
     41#include <errno.h>
     42#include <macros.h>
     43
     44/** Maximal sysinfo path length */
     45#define SYSINFO_MAX_PATH  2048
    3946
    4047bool fb_exported = false;
    41 sysinfo_item_t *_root = NULL;
    42 
    43 static sysinfo_item_t *sysinfo_find_item(const char *name, sysinfo_item_t *subtree)
    44 {
    45         if (subtree == NULL)
    46                 return NULL;
    47        
    48         while (subtree != NULL) {
    49                 int i = 0;
    50                 char *a = (char *) name;
    51                 char *b = subtree->name;
    52                
    53                 while ((a[i] == b[i]) && (b[i]))
     48
     49/** Global sysinfo tree root item */
     50static sysinfo_item_t *global_root = NULL;
     51
     52/** Sysinfo SLAB cache */
     53static slab_cache_t *sysinfo_item_slab;
     54
     55/** Sysinfo lock */
     56static mutex_t sysinfo_lock;
     57
     58/** Sysinfo item constructor
     59 *
     60 */
     61NO_TRACE static int sysinfo_item_constructor(void *obj, unsigned int kmflag)
     62{
     63        sysinfo_item_t *item = (sysinfo_item_t *) obj;
     64       
     65        item->name = NULL;
     66        item->val_type = SYSINFO_VAL_UNDEFINED;
     67        item->subtree_type = SYSINFO_SUBTREE_NONE;
     68        item->subtree.table = NULL;
     69        item->next = NULL;
     70       
     71        return 0;
     72}
     73
     74/** Sysinfo item destructor
     75 *
     76 * Note that the return value is not perfectly correct
     77 * since more space might get actually freed thanks
     78 * to the disposal of item->name
     79 *
     80 */
     81NO_TRACE static size_t sysinfo_item_destructor(void *obj)
     82{
     83        sysinfo_item_t *item = (sysinfo_item_t *) obj;
     84       
     85        if (item->name != NULL)
     86                free(item->name);
     87       
     88        return 0;
     89}
     90
     91/** Initialize sysinfo subsystem
     92 *
     93 * Create SLAB cache for sysinfo items.
     94 *
     95 */
     96void sysinfo_init(void)
     97{
     98        sysinfo_item_slab = slab_cache_create("sysinfo_item_slab",
     99            sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
     100            sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
     101
     102        mutex_initialize(&sysinfo_lock, MUTEX_ACTIVE);
     103}
     104
     105/** Recursively find an item in sysinfo tree
     106 *
     107 * Should be called with sysinfo_lock held.
     108 *
     109 * @param name    Current sysinfo path suffix.
     110 * @param subtree Current sysinfo (sub)tree root item.
     111 * @param ret     If the return value is NULL, this argument
     112 *                can be either also NULL (i.e. no item was
     113 *                found and no data was generated) or the
     114 *                original pointer is used to store the value
     115 *                generated by a generated subtree function.
     116 * @param dry_run Do not actually get any generated
     117 *                binary data, just calculate the size.
     118 *
     119 * @return Found item or NULL if no item in the fixed tree
     120 *         was found (N.B. ret).
     121 *
     122 */
     123NO_TRACE static sysinfo_item_t *sysinfo_find_item(const char *name,
     124    sysinfo_item_t *subtree, sysinfo_return_t **ret, bool dry_run)
     125{
     126        ASSERT(subtree != NULL);
     127        ASSERT(ret != NULL);
     128       
     129        sysinfo_item_t *cur = subtree;
     130       
     131        /* Walk all siblings */
     132        while (cur != NULL) {
     133                size_t i = 0;
     134               
     135                /* Compare name with path */
     136                while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
    54137                        i++;
    55138               
    56                 if ((!a[i]) && (!b[i]))  /* Last name in path matches */
    57                         return subtree;
    58                
    59                 if ((a[i] == '.') && (!b[i])) { /* Middle name in path matches */
    60                         if (subtree->subinfo_type == SYSINFO_SUBINFO_TABLE)
    61                                 return sysinfo_find_item(a + i + 1, subtree->subinfo.table);
     139                /* Check for perfect name and path match */
     140                if ((name[i] == 0) && (cur->name[i] == 0))
     141                        return cur;
     142               
     143                /* Partial match up to the delimiter */
     144                if ((name[i] == '.') && (cur->name[i] == 0)) {
     145                        /* Look into the subtree */
     146                        switch (cur->subtree_type) {
     147                        case SYSINFO_SUBTREE_TABLE:
     148                                /* Recursively find in subtree */
     149                                return sysinfo_find_item(name + i + 1,
     150                                    cur->subtree.table, ret, dry_run);
     151                        case SYSINFO_SUBTREE_FUNCTION:
     152                                /* Get generated data */
     153                                **ret = cur->subtree.get_data(name + i + 1, dry_run);
     154                                return NULL;
     155                        default:
     156                                /* Not found, no data generated */
     157                                *ret = NULL;
     158                                return NULL;
     159                        }
     160                }
     161               
     162                cur = cur->next;
     163        }
     164       
     165        /* Not found, no data generated */
     166        *ret = NULL;
     167        return NULL;
     168}
     169
     170/** Recursively create items in sysinfo tree
     171 *
     172 * Should be called with sysinfo_lock held.
     173 *
     174 * @param name     Current sysinfo path suffix.
     175 * @param psubtree Pointer to an already existing (sub)tree root
     176 *                 item or where to store a new tree root item.
     177 *
     178 * @return Existing or newly allocated sysinfo item or NULL
     179 *         if the current tree configuration does not allow to
     180 *         create a new item.
     181 *
     182 */
     183NO_TRACE static sysinfo_item_t *sysinfo_create_path(const char *name,
     184    sysinfo_item_t **psubtree)
     185{
     186        ASSERT(psubtree != NULL);
     187       
     188        if (*psubtree == NULL) {
     189                /* No parent */
     190               
     191                size_t i = 0;
     192               
     193                /* Find the first delimiter in name */
     194                while ((name[i] != 0) && (name[i] != '.'))
     195                        i++;
     196               
     197                *psubtree =
     198                    (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
     199                ASSERT(*psubtree);
     200               
     201                /* Fill in item name up to the delimiter */
     202                (*psubtree)->name = str_ndup(name, i);
     203                ASSERT((*psubtree)->name);
     204               
     205                /* Create subtree items */
     206                if (name[i] == '.') {
     207                        (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
     208                        return sysinfo_create_path(name + i + 1,
     209                            &((*psubtree)->subtree.table));
     210                }
     211               
     212                /* No subtree needs to be created */
     213                return *psubtree;
     214        }
     215       
     216        sysinfo_item_t *cur = *psubtree;
     217       
     218        /* Walk all siblings */
     219        while (cur != NULL) {
     220                size_t i = 0;
     221               
     222                /* Compare name with path */
     223                while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
     224                        i++;
     225               
     226                /* Check for perfect name and path match
     227                 * -> item is already present.
     228                 */
     229                if ((name[i] == 0) && (cur->name[i] == 0))
     230                        return cur;
     231               
     232                /* Partial match up to the delimiter */
     233                if ((name[i] == '.') && (cur->name[i] == 0)) {
     234                        switch (cur->subtree_type) {
     235                        case SYSINFO_SUBTREE_NONE:
     236                                /* No subtree yet, create one */
     237                                cur->subtree_type = SYSINFO_SUBTREE_TABLE;
     238                                return sysinfo_create_path(name + i + 1,
     239                                    &(cur->subtree.table));
     240                        case SYSINFO_SUBTREE_TABLE:
     241                                /* Subtree already created, add new sibling */
     242                                return sysinfo_create_path(name + i + 1,
     243                                    &(cur->subtree.table));
     244                        default:
     245                                /* Subtree items handled by a function, this
     246                                 * cannot be overriden by a constant item.
     247                                 */
     248                                return NULL;
     249                        }
     250                }
     251               
     252                /* No match and no more siblings to check
     253                 * -> create a new sibling item.
     254                 */
     255                if (cur->next == NULL) {
     256                        /* Find the first delimiter in name */
     257                        i = 0;
     258                        while ((name[i] != 0) && (name[i] != '.'))
     259                                i++;
    62260                       
    63                         //if (subtree->subinfo_type == SYSINFO_SUBINFO_FUNCTION) /* Subinfo managed by subsystem */
    64                         //      return NULL;
     261                        sysinfo_item_t *item =
     262                            (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
     263                        ASSERT(item);
    65264                       
    66                         return NULL; /* No subinfo */
    67                 }
    68                 /* No matches try next */
    69                 subtree = subtree->next;
    70                 i = 0;
    71         }
    72         return NULL;
    73 }
    74 
    75 static sysinfo_item_t *sysinfo_create_path(const char *name, sysinfo_item_t **psubtree)
    76 {
    77         sysinfo_item_t *subtree;
    78         subtree = *psubtree;
    79        
    80         if (subtree == NULL) {
    81                 sysinfo_item_t *item = malloc(sizeof(sysinfo_item_t), 0);
    82                 int i = 0, j;
     265                        cur->next = item;
    83266                       
    84                 ASSERT(item);
    85                 *psubtree = item;
    86                 item->next = NULL;
    87                 item->val_type = SYSINFO_VAL_UNDEFINED;
    88                 item->subinfo.table = NULL;
    89 
    90                 while (name[i] && (name[i] != '.'))
    91                         i++;
     267                        /* Fill in item name up to the delimiter */
     268                        item->name = str_ndup(name, i);
     269                        ASSERT(item->name);
    92270                       
    93                 item->name = malloc(i, 0);
    94                 ASSERT(item->name);
    95 
    96                 for (j = 0; j < i; j++)
    97                         item->name[j] = name[j];
    98                 item->name[j] = 0;
    99                        
    100                 if (name[i]) { /* =='.' */
    101                         item->subinfo_type = SYSINFO_SUBINFO_TABLE;
    102                         return sysinfo_create_path(name + i + 1, &(item->subinfo.table));
    103                 }
    104                 item->subinfo_type = SYSINFO_SUBINFO_NONE;
    105                 return item;
    106         }
    107 
    108         while (subtree != NULL) {
    109                 int i = 0, j;
    110                 char *a = (char *) name;
    111                 char *b = subtree->name;
    112                
    113                 while ((a[i] == b[i]) && (b[i]))
    114                         i++;
    115                
    116                 if ((!a[i]) && (!b[i])) /* Last name in path matches */
    117                         return subtree;
    118                
    119                 if ((a[i] == '.') && (!b[i])) { /* Middle name in path matches */
    120                         if (subtree->subinfo_type == SYSINFO_SUBINFO_TABLE)
    121                                 return sysinfo_create_path(a + i + 1, &(subtree->subinfo.table));
    122                        
    123                         if (subtree->subinfo_type == SYSINFO_SUBINFO_NONE) {
    124                                 subtree->subinfo_type = SYSINFO_SUBINFO_TABLE;
    125                                 return sysinfo_create_path(a + i + 1,&(subtree->subinfo.table));
     271                        /* Create subtree items */
     272                        if (name[i] == '.') {
     273                                item->subtree_type = SYSINFO_SUBTREE_TABLE;
     274                                return sysinfo_create_path(name + i + 1,
     275                                    &(item->subtree.table));
    126276                        }
    127277                       
    128                         //if (subtree->subinfo_type == SYSINFO_SUBINFO_FUNCTION) /* Subinfo managed by subsystem */
    129                         //      return NULL;
    130                        
    131                         return NULL;
     278                        /* No subtree needs to be created */
     279                        return item;
    132280                }
    133                 /* No matches try next or create new*/
    134                 if (subtree->next == NULL) {
    135                         sysinfo_item_t *item = malloc(sizeof(sysinfo_item_t), 0);
    136                        
    137                         ASSERT(item);
    138                         subtree->next = item;
    139                         item->next = NULL;
    140                         item->val_type = SYSINFO_VAL_UNDEFINED;
    141                         item->subinfo.table = NULL;
    142 
    143                         i = 0;
    144                         while (name[i] && (name[i] != '.'))
    145                                 i++;
    146 
    147                         item->name = malloc(i, 0);
    148                         ASSERT(item->name);
    149                        
    150                         for (j = 0; j < i; j++)
    151                                 item->name[j] = name[j];
    152                        
    153                         item->name[j] = 0;
    154 
    155                         if(name[i]) { /* =='.' */
    156                                 item->subinfo_type = SYSINFO_SUBINFO_TABLE;
    157                                 return sysinfo_create_path(name + i + 1, &(item->subinfo.table));
    158                         }
    159                         item->subinfo_type = SYSINFO_SUBINFO_NONE;
    160                         return item;
    161                 } else {
    162                         subtree = subtree->next;
    163                         i = 0;
    164                 }       
    165         }
    166 
    167         panic("Not reached.");
     281               
     282                cur = cur->next;
     283        }
     284       
     285        /* Unreachable */
     286        ASSERT(false);
    168287        return NULL;
    169288}
    170289
    171 void sysinfo_set_item_val(const char *name, sysinfo_item_t **root, unative_t val)
    172 {
     290/** Set sysinfo item with a constant numeric value
     291 *
     292 * @param name Sysinfo path.
     293 * @param root Pointer to the root item or where to store
     294 *             a new root item (NULL for global sysinfo root).
     295 * @param val  Value to store in the item.
     296 *
     297 */
     298void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
     299    sysarg_t val)
     300{
     301        /* Protect sysinfo tree consistency */
     302        mutex_lock(&sysinfo_lock);
     303       
    173304        if (root == NULL)
    174                 root = &_root;
    175        
    176         /* If already created create only returns pointer
    177            If not, create it */
     305                root = &global_root;
     306       
    178307        sysinfo_item_t *item = sysinfo_create_path(name, root);
    179        
    180         if (item != NULL) { /* If in subsystem, unable to create or return so unable to set */
    181                 item->val.val = val;                   
     308        if (item != NULL) {
    182309                item->val_type = SYSINFO_VAL_VAL;
    183         }
    184 }
    185 
    186 void sysinfo_set_item_function(const char *name, sysinfo_item_t **root, sysinfo_val_fn_t fn)
    187 {
     310                item->val.val = val;
     311        }
     312       
     313        mutex_unlock(&sysinfo_lock);
     314}
     315
     316/** Set sysinfo item with a constant binary data
     317 *
     318 * Note that sysinfo only stores the pointer to the
     319 * binary data and does not touch it in any way. The
     320 * data should be static and immortal.
     321 *
     322 * @param name Sysinfo path.
     323 * @param root Pointer to the root item or where to store
     324 *             a new root item (NULL for global sysinfo root).
     325 * @param data Binary data.
     326 * @param size Size of the binary data.
     327 *
     328 */
     329void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
     330    void *data, size_t size)
     331{
     332        /* Protect sysinfo tree consistency */
     333        mutex_lock(&sysinfo_lock);
     334       
    188335        if (root == NULL)
    189                 root = &_root;
    190        
    191         /* If already created create only returns pointer
    192            If not, create it */
     336                root = &global_root;
     337       
    193338        sysinfo_item_t *item = sysinfo_create_path(name, root);
    194        
    195         if (item != NULL) { /* If in subsystem, unable to create or return so  unable to set */
    196                 item->val.fn = fn;                   
    197                 item->val_type = SYSINFO_VAL_FUNCTION;
    198         }
    199 }
    200 
    201 
     339        if (item != NULL) {
     340                item->val_type = SYSINFO_VAL_DATA;
     341                item->val.data.data = data;
     342                item->val.data.size = size;
     343        }
     344       
     345        mutex_unlock(&sysinfo_lock);
     346}
     347
     348/** Set sysinfo item with a generated numeric value
     349 *
     350 * @param name Sysinfo path.
     351 * @param root Pointer to the root item or where to store
     352 *             a new root item (NULL for global sysinfo root).
     353 * @param fn   Numeric value generator function.
     354 *
     355 */
     356void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
     357    sysinfo_fn_val_t fn)
     358{
     359        /* Protect sysinfo tree consistency */
     360        mutex_lock(&sysinfo_lock);
     361       
     362        if (root == NULL)
     363                root = &global_root;
     364       
     365        sysinfo_item_t *item = sysinfo_create_path(name, root);
     366        if (item != NULL) {
     367                item->val_type = SYSINFO_VAL_FUNCTION_VAL;
     368                item->val.fn_val = fn;
     369        }
     370       
     371        mutex_unlock(&sysinfo_lock);
     372}
     373
     374/** Set sysinfo item with a generated binary data
     375 *
     376 * Note that each time the generator function is called
     377 * it is supposed to return a new dynamically allocated
     378 * data. This data is then freed by sysinfo in the context
     379 * of the current sysinfo request.
     380 *
     381 * @param name Sysinfo path.
     382 * @param root Pointer to the root item or where to store
     383 *             a new root item (NULL for global sysinfo root).
     384 * @param fn   Binary data generator function.
     385 *
     386 */
     387void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
     388    sysinfo_fn_data_t fn)
     389{
     390        /* Protect sysinfo tree consistency */
     391        mutex_lock(&sysinfo_lock);
     392       
     393        if (root == NULL)
     394                root = &global_root;
     395       
     396        sysinfo_item_t *item = sysinfo_create_path(name, root);
     397        if (item != NULL) {
     398                item->val_type = SYSINFO_VAL_FUNCTION_DATA;
     399                item->val.fn_data = fn;
     400        }
     401       
     402        mutex_unlock(&sysinfo_lock);
     403}
     404
     405/** Set sysinfo item with an undefined value
     406 *
     407 * @param name Sysinfo path.
     408 * @param root Pointer to the root item or where to store
     409 *             a new root item (NULL for global sysinfo root).
     410 *
     411 */
    202412void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
    203413{
     414        /* Protect sysinfo tree consistency */
     415        mutex_lock(&sysinfo_lock);
     416       
    204417        if (root == NULL)
    205                 root = &_root;
    206        
    207         /* If already created create only returns pointer
    208            If not, create it */
     418                root = &global_root;
     419       
    209420        sysinfo_item_t *item = sysinfo_create_path(name, root);
    210        
    211421        if (item != NULL)
    212422                item->val_type = SYSINFO_VAL_UNDEFINED;
    213 }
    214 
    215 
    216 void sysinfo_dump(sysinfo_item_t **proot, int depth)
    217 {
    218         sysinfo_item_t *root;
    219         if (proot == NULL)
    220                 proot = &_root;
    221        
    222         root = *proot;
    223        
    224         while (root != NULL) {
    225                 int i;
    226                 unative_t val = 0;
    227                 char *vtype = NULL;
    228                
    229                
    230                 for (i = 0; i < depth; i++)
    231                         printf("  ");
    232                
    233                 switch (root->val_type) {
     423       
     424        mutex_unlock(&sysinfo_lock);
     425}
     426
     427/** Set sysinfo item with a generated subtree
     428 *
     429 * @param name Sysinfo path.
     430 * @param root Pointer to the root item or where to store
     431 *             a new root item (NULL for global sysinfo root).
     432 * @param fn   Subtree generator function.
     433 *
     434 */
     435void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
     436    sysinfo_fn_subtree_t fn)
     437{
     438        /* Protect sysinfo tree consistency */
     439        mutex_lock(&sysinfo_lock);
     440       
     441        if (root == NULL)
     442                root = &global_root;
     443       
     444        sysinfo_item_t *item = sysinfo_create_path(name, root);
     445       
     446        /* Change the type of the subtree only if it is not already
     447           a fixed subtree */
     448        if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
     449                item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
     450                item->subtree.get_data = fn;
     451        }
     452       
     453        mutex_unlock(&sysinfo_lock);
     454}
     455
     456/** Sysinfo dump indentation helper routine
     457 *
     458 * @param depth Number of indentation characters to print.
     459 *
     460 */
     461NO_TRACE static void sysinfo_indent(unsigned int depth)
     462{
     463        unsigned int i;
     464        for (i = 0; i < depth; i++)
     465                printf("  ");
     466}
     467
     468/** Dump the structure of sysinfo tree
     469 *
     470 * Should be called with sysinfo_lock held.
     471 *
     472 * @param root  Root item of the current (sub)tree.
     473 * @param depth Current depth in the sysinfo tree.
     474 *
     475 */
     476NO_TRACE static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
     477{
     478        sysinfo_item_t *cur = root;
     479       
     480        /* Walk all siblings */
     481        while (cur != NULL) {
     482                sysinfo_indent(depth);
     483               
     484                sysarg_t val;
     485                size_t size;
     486               
     487                /* Display node value and type */
     488                switch (cur->val_type) {
    234489                case SYSINFO_VAL_UNDEFINED:
    235                         val = 0;
    236                         vtype = "UND";
     490                        printf("+ %s\n", cur->name);
    237491                        break;
    238492                case SYSINFO_VAL_VAL:
    239                         val = root->val.val;
    240                         vtype = "VAL";
    241                         break;
    242                 case SYSINFO_VAL_FUNCTION:
    243                         val = ((sysinfo_val_fn_t) (root->val.fn)) (root);
    244                         vtype = "FUN";
    245                         break;
     493                        printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
     494                            cur->val.val, cur->val.val);
     495                        break;
     496                case SYSINFO_VAL_DATA:
     497                        printf("+ %s (%zu bytes)\n", cur->name,
     498                            cur->val.data.size);
     499                        break;
     500                case SYSINFO_VAL_FUNCTION_VAL:
     501                        val = cur->val.fn_val(cur);
     502                        printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
     503                            cur->name, val, val);
     504                        break;
     505                case SYSINFO_VAL_FUNCTION_DATA:
     506                        /* N.B.: No data was actually returned (only a dry run) */
     507                        (void) cur->val.fn_data(cur, &size, true);
     508                        printf("+ %s (%zu bytes) [generated]\n", cur->name,
     509                            size);
     510                        break;
     511                default:
     512                        printf("+ %s [unknown]\n", cur->name);
    246513                }
    247514               
    248                 printf("%s    %s val:%" PRIun "(%" PRIxn ") sub:%s\n", root->name, vtype, val,
    249                         val, (root->subinfo_type == SYSINFO_SUBINFO_NONE) ?
    250                         "NON" : ((root->subinfo_type == SYSINFO_SUBINFO_TABLE) ?
    251                         "TAB" : "FUN"));
    252                
    253                 if (root->subinfo_type == SYSINFO_SUBINFO_TABLE)
    254                         sysinfo_dump(&(root -> subinfo.table), depth + 1);
    255                
    256                 root = root->next;
    257         }
    258 }
    259 
    260 sysinfo_rettype_t sysinfo_get_val(const char *name, sysinfo_item_t **root)
    261 {
    262         // TODO: Implement Subsystem subinfo (by function implemented subinfo)
    263 
    264         sysinfo_rettype_t ret = {0, false};
    265 
     515                /* Recursivelly nest into the subtree */
     516                switch (cur->subtree_type) {
     517                case SYSINFO_SUBTREE_NONE:
     518                        break;
     519                case SYSINFO_SUBTREE_TABLE:
     520                        sysinfo_dump_internal(cur->subtree.table, depth + 1);
     521                        break;
     522                case SYSINFO_SUBTREE_FUNCTION:
     523                        sysinfo_indent(depth + 1);
     524                        printf("+ [generated subtree]\n");
     525                        break;
     526                default:
     527                        sysinfo_indent(depth + 1);
     528                        printf("+ [unknown subtree]\n");
     529                }
     530               
     531                cur = cur->next;
     532        }
     533}
     534
     535/** Dump the structure of sysinfo tree
     536 *
     537 * @param root  Root item of the sysinfo (sub)tree.
     538 *              If it is NULL then consider the global
     539 *              sysinfo tree.
     540 *
     541 */
     542void sysinfo_dump(sysinfo_item_t *root)
     543{
     544        /* Avoid other functions to mess with sysinfo
     545           while we are dumping it */
     546        mutex_lock(&sysinfo_lock);
     547       
    266548        if (root == NULL)
    267                 root = &_root;
    268        
    269         sysinfo_item_t *item = sysinfo_find_item(name, *root);
     549                sysinfo_dump_internal(global_root, 0);
     550        else
     551                sysinfo_dump_internal(root, 0);
     552       
     553        mutex_unlock(&sysinfo_lock);
     554}
     555
     556/** Return sysinfo item value determined by name
     557 *
     558 * Should be called with sysinfo_lock held.
     559 *
     560 * @param name    Sysinfo path.
     561 * @param root    Root item of the sysinfo (sub)tree.
     562 *                If it is NULL then consider the global
     563 *                sysinfo tree.
     564 * @param dry_run Do not actually get any generated
     565 *                binary data, just calculate the size.
     566 *
     567 * @return Item value (constant or generated).
     568 *
     569 */
     570NO_TRACE static sysinfo_return_t sysinfo_get_item(const char *name,
     571    sysinfo_item_t **root, bool dry_run)
     572{
     573        if (root == NULL)
     574                root = &global_root;
     575       
     576        /* Try to find the item or generate data */
     577        sysinfo_return_t ret;
     578        sysinfo_return_t *ret_ptr = &ret;
     579        sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr,
     580            dry_run);
    270581       
    271582        if (item != NULL) {
    272                 if (item->val_type == SYSINFO_VAL_UNDEFINED)
    273                         return ret;
    274                 else
    275                         ret.valid = true;
    276                
    277                 if (item->val_type == SYSINFO_VAL_VAL)
     583                /* Item found in the fixed sysinfo tree */
     584               
     585                ret.tag = item->val_type;
     586                switch (item->val_type) {
     587                case SYSINFO_VAL_UNDEFINED:
     588                        break;
     589                case SYSINFO_VAL_VAL:
    278590                        ret.val = item->val.val;
    279                 else
    280                         ret.val = ((sysinfo_val_fn_t) (item->val.fn)) (item);
    281         }
     591                        break;
     592                case SYSINFO_VAL_DATA:
     593                        ret.data = item->val.data;
     594                        break;
     595                case SYSINFO_VAL_FUNCTION_VAL:
     596                        ret.val = item->val.fn_val(item);
     597                        break;
     598                case SYSINFO_VAL_FUNCTION_DATA:
     599                        ret.data.data = item->val.fn_data(item, &ret.data.size,
     600                            dry_run);
     601                        break;
     602                }
     603        } else {
     604                /* No item in the fixed sysinfo tree */
     605                if (ret_ptr == NULL) {
     606                        /* Even no data was generated */
     607                        ret.tag = SYSINFO_VAL_UNDEFINED;
     608                }
     609        }
     610       
    282611        return ret;
    283612}
    284613
    285 #define SYSINFO_MAX_LEN 1024
    286 
    287 unative_t sys_sysinfo_valid(unative_t ptr, unative_t len)
    288 {
    289         char *str;
    290         sysinfo_rettype_t ret = {0, 0};
    291 
    292         if (len > SYSINFO_MAX_LEN)
    293                 return ret.valid;
    294         str = malloc(len + 1, 0);
    295        
    296         ASSERT(str);
    297         if (!((copy_from_uspace(str, (void *) ptr, len + 1)) || (str[len])))
    298                 ret = sysinfo_get_val(str, NULL);
    299        
    300         free(str);
    301         return ret.valid;
    302 }
    303 
    304 unative_t sys_sysinfo_value(unative_t ptr, unative_t len)
    305 {
    306         char *str;
    307         sysinfo_rettype_t ret = {0, 0};
    308        
    309         if (len > SYSINFO_MAX_LEN)
    310                 return ret.val;
    311         str = malloc(len + 1, 0);
    312        
    313         ASSERT(str);
    314         if (!((copy_from_uspace(str, (void *) ptr, len + 1)) || (str[len])))
    315                 ret = sysinfo_get_val(str, NULL);
    316        
    317         free(str);
    318         return ret.val;
     614/** Return sysinfo item determined by name from user space
     615 *
     616 * The path string passed from the user space has to be properly null-terminated
     617 * (the last passed character must be null).
     618 *
     619 * @param ptr     Sysinfo path in the user address space.
     620 * @param size    Size of the path string.
     621 * @param dry_run Do not actually get any generated
     622 *                binary data, just calculate the size.
     623 *
     624 */
     625NO_TRACE static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size,
     626    bool dry_run)
     627{
     628        sysinfo_return_t ret;
     629        ret.tag = SYSINFO_VAL_UNDEFINED;
     630       
     631        if (size > SYSINFO_MAX_PATH)
     632                return ret;
     633       
     634        char *path = (char *) malloc(size + 1, 0);
     635        ASSERT(path);
     636       
     637        if ((copy_from_uspace(path, ptr, size + 1) == 0)
     638            && (path[size] == 0)) {
     639                /*
     640                 * Prevent other functions from messing with sysinfo while we
     641                 * are reading it.
     642                 */
     643                mutex_lock(&sysinfo_lock);
     644                ret = sysinfo_get_item(path, NULL, dry_run);
     645                mutex_unlock(&sysinfo_lock);
     646        }
     647        free(path);
     648        return ret;
     649}
     650
     651/** Get the sysinfo value type (syscall)
     652 *
     653 * The path string passed from the user space has
     654 * to be properly null-terminated (the last passed
     655 * character must be null).
     656 *
     657 * @param path_ptr  Sysinfo path in the user address space.
     658 * @param path_size Size of the path string.
     659 *
     660 * @return Item value type.
     661 *
     662 */
     663sysarg_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
     664{
     665        /*
     666         * Get the item.
     667         *
     668         * N.B.: There is no need to free any potential generated
     669         * binary data since we request a dry run.
     670         */
     671        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     672       
     673        /*
     674         * Map generated value types to constant types (user space does not care
     675         * whether the value is constant or generated).
     676         */
     677        if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
     678                ret.tag = SYSINFO_VAL_VAL;
     679        else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
     680                ret.tag = SYSINFO_VAL_DATA;
     681       
     682        return (sysarg_t) ret.tag;
     683}
     684
     685/** Get the sysinfo numerical value (syscall)
     686 *
     687 * The path string passed from the user space has
     688 * to be properly null-terminated (the last passed
     689 * character must be null).
     690 *
     691 * @param path_ptr  Sysinfo path in the user address space.
     692 * @param path_size Size of the path string.
     693 * @param value_ptr User space pointer where to store the
     694 *                  numberical value.
     695 *
     696 * @return Error code (EOK in case of no error).
     697 *
     698 */
     699sysarg_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
     700    void *value_ptr)
     701{
     702        int rc;
     703
     704        /*
     705         * Get the item.
     706         *
     707         * N.B.: There is no need to free any potential generated binary data
     708         * since we request a dry run.
     709         */
     710        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     711       
     712        /* Only constant or generated numerical value is returned */
     713        if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
     714                rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
     715        else
     716                rc = EINVAL;
     717       
     718        return (sysarg_t) rc;
     719}
     720
     721/** Get the sysinfo binary data size (syscall)
     722 *
     723 * The path string passed from the user space has
     724 * to be properly null-terminated (the last passed
     725 * character must be null).
     726 *
     727 * @param path_ptr  Sysinfo path in the user address space.
     728 * @param path_size Size of the path string.
     729 * @param size_ptr  User space pointer where to store the
     730 *                  binary data size.
     731 *
     732 * @return Error code (EOK in case of no error).
     733 *
     734 */
     735sysarg_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
     736    void *size_ptr)
     737{
     738        int rc;
     739       
     740        /*
     741         * Get the item.
     742         *
     743         * N.B.: There is no need to free any potential generated binary data
     744         * since we request a dry run.
     745         */
     746        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size, true);
     747       
     748        /* Only the size of constant or generated binary data is considered */
     749        if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
     750                rc = copy_to_uspace(size_ptr, &ret.data.size,
     751                    sizeof(ret.data.size));
     752        else
     753                rc = EINVAL;
     754       
     755        return (sysarg_t) rc;
     756}
     757
     758/** Get the sysinfo binary data (syscall)
     759 *
     760 * The path string passed from the user space has
     761 * to be properly null-terminated (the last passed
     762 * character must be null).
     763 *
     764 * If the user space buffer size does not equal
     765 * the actual size of the returned data, the data
     766 * is truncated. Whether this is actually a fatal
     767 * error or the data can be still interpreted as valid
     768 * depends on the nature of the data and has to be
     769 * decided by the user space.
     770 *
     771 * The actual size of data returned is stored to
     772 * size_ptr.
     773 *
     774 * @param path_ptr    Sysinfo path in the user address space.
     775 * @param path_size   Size of the path string.
     776 * @param buffer_ptr  User space pointer to the buffer where
     777 *                    to store the binary data.
     778 * @param buffer_size User space buffer size.
     779 * @param size_ptr    User space pointer where to store the
     780 *                    binary data size.
     781 *
     782 * @return Error code (EOK in case of no error).
     783 *
     784 */
     785sysarg_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
     786    void *buffer_ptr, size_t buffer_size, size_t *size_ptr)
     787{
     788        int rc;
     789       
     790        /* Get the item */
     791        sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size,
     792            false);
     793       
     794        /* Only constant or generated binary data is considered */
     795        if ((ret.tag == SYSINFO_VAL_DATA) ||
     796            (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
     797                size_t size = min(ret.data.size, buffer_size);
     798                rc = copy_to_uspace(buffer_ptr, ret.data.data, size);
     799                if (rc == EOK)
     800                        rc = copy_to_uspace(size_ptr, &size, sizeof(size));
     801        } else
     802                rc = EINVAL;
     803       
     804        /* N.B.: The generated binary data should be freed */
     805        if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
     806                free(ret.data.data);
     807       
     808        return (sysarg_t) rc;
    319809}
    320810
Note: See TracChangeset for help on using the changeset viewer.