Changeset bb154c6 in mainline for uspace/srv/sysman/units/unit_cfg.c


Ignore:
Timestamp:
2019-08-03T08:15:25Z (6 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
09a8006
Parents:
6006f35
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-04-15 15:14:58)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-03 08:15:25)
Message:

Add skeleton for configuration files loading

  • Create content of /cfg directory,
  • create sample configuration file,
  • refactored polymorphism.

Conflicts:

boot/Makefile

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/sysman/units/unit_cfg.c

    r6006f35 rbb154c6  
     1#include <adt/list.h>
     2#include <assert.h>
     3#include <conf/configuration.h>
     4#include <conf/ini.h>
     5#include <conf/text_parse.h>
     6#include <dirent.h>
    17#include <errno.h>
    2 
    3 #include "unit_cfg.h"
     8#include <stdlib.h>
     9#include <str.h>
     10
     11#include "configuration.h"
     12#include "log.h"
     13#include "unit.h"
     14#include "util.h"
     15
     16static const char *section_name = "Configuration";
     17
     18static config_item_t unit_configuration[] = {
     19        {"Path", &config_parse_string, offsetof(unit_cfg_t, path), NULL},
     20        CONFIGURATION_ITEM_SENTINEL
     21};
     22
     23/**
     24 * TODO refactor path handling and rename to 'load from file'
     25 *
     26 * @param[out]  unit_ptr   Unit loaded from the file. Undefined when function fails.
     27 */
     28static int cfg_parse_file(const char *dirname, const char *filename,
     29    unit_t **unit_ptr)
     30{
     31        int rc = EOK;
     32        unit_t *new_unit = NULL;
     33        char *fn = NULL;
     34        ini_configuration_t ini_conf;
     35        text_parse_t text_parse;
     36
     37        ini_configuration_init(&ini_conf);
     38        text_parse_init(&text_parse);
     39
     40        const char *last_dot = str_rchr(filename, '.');
     41        if (last_dot == NULL) {
     42                rc = EINVAL;
     43                goto finish;
     44        }
     45
     46        const char *unit_name = filename;
     47        const char *unit_type_name = last_dot + 1;
     48
     49        unit_type_t unit_type = unit_type_name_to_type(unit_type_name);
     50        if (unit_type == UNIT_TYPE_INVALID) {
     51                rc = EINVAL;
     52                goto finish;
     53        }
     54       
     55        unit_t *u = configuration_find_unit_by_name(unit_name);
     56        if (u != NULL) {
     57                // TODO allow updating configuration of existing unit
     58                rc = EEXISTS;
     59                goto finish;
     60        } else {
     61                new_unit = u = unit_create(unit_type);
     62                new_unit->name = str_dup(unit_name);
     63                if (new_unit->name == NULL) {
     64                        rc = ENOMEM;
     65                        goto finish;
     66                }
     67        }
     68        if (u == NULL) {
     69                rc = ENOMEM;
     70                goto finish;
     71        }
     72        assert(u->type == unit_type);
     73
     74        fn = compose_path(dirname, filename);
     75        if (fn == NULL) {
     76                rc = ENOMEM;
     77                goto finish;
     78        }
     79
     80        /* Parse INI file to ini_conf structure */
     81        rc = ini_parse_file(fn, &ini_conf, &text_parse);
     82        switch (rc) {
     83        case EOK:
     84                /* This is fine */
     85                break;
     86        case EINVAL:
     87                goto dump_parse;
     88                break;
     89        default:
     90                sysman_log(LVL_WARN,
     91                    "Cannot parse '%s' (%i).", fn, rc);
     92                goto finish;
     93        }
     94
     95        /* Parse ini structure */
     96        rc = unit_load(u, &ini_conf, &text_parse);
     97        *unit_ptr = u;
     98
     99        /*
     100         * Here we just continue undisturbed by errors, they'll be returned in
     101         * 'finish' block and potential parse errors (or none) will be logged
     102         * in 'dump_parse' block.
     103         */
     104
     105dump_parse:
     106        list_foreach(text_parse.errors, link, text_parse_error_t, err) {
     107                sysman_log(LVL_WARN,
     108                    "Error (%i) when parsing '%s' on line %i.",
     109                    err->parse_errno, fn, err->lineno);
     110        }
     111
     112finish:
     113        free(fn);
     114        ini_configuration_deinit(&ini_conf);
     115        text_parse_deinit(&text_parse);
     116        if (rc != EOK) {
     117                unit_destroy(&new_unit);
     118        }
     119
     120        return rc;
     121}
     122
     123static int cfg_load_configuration(const char *path)
     124{
     125        DIR *dir;
     126        struct dirent *de;
     127
     128        dir = opendir(path);
     129        if (dir == NULL) {
     130                sysman_log(LVL_ERROR,
     131                    "Cannot open configuration directory '%s'", path);
     132                return EIO;
     133        }
     134
     135        configuration_start_update();
     136
     137        while ((de = readdir(dir))) {
     138                unit_t *unit = NULL;
     139                int rc = cfg_parse_file(path, de->d_name, &unit);
     140                if (rc != EOK) {
     141                        sysman_log(LVL_WARN, "Cannot load unit from file %s/%s",
     142                            path, de->d_name);
     143                        /*
     144                         * Ignore error for now, we'll fail only when we're
     145                         * unable to resolve dependency names.
     146                         */
     147                        continue;
     148                }
     149
     150                assert(unit->state = STATE_EMBRYO);
     151                configuration_add_unit(unit);
     152        }
     153        closedir(dir);
     154
     155        int rc = configuration_resolve_dependecies();
     156        if (rc != EOK) {
     157                configuration_rollback();
     158                return rc;
     159        }
     160
     161        configuration_commit();
     162        return EOK;
     163}
    4164
    5165static void unit_cfg_init(unit_t *unit)
    6166{
    7         // TODO
     167        unit_cfg_t *u_cfg = CAST_CFG(unit);
     168        assert(u_cfg);
     169
     170        u_cfg->path = NULL;
     171}
     172
     173
     174
     175static void unit_cfg_destroy(unit_t *unit)
     176{
     177        unit_cfg_t *u_cfg = CAST_CFG(unit);
     178        assert(u_cfg);
     179
     180        free(u_cfg->path);
     181}
     182
     183static int unit_cfg_load(unit_t *unit, ini_configuration_t *ini_conf,
     184    text_parse_t *text_parse)
     185{
     186        unit_cfg_t *u_cfg = CAST_CFG(unit);
     187        assert(u_cfg);
     188
     189        ini_section_t *section = ini_get_section(ini_conf, section_name);
     190        if (section == NULL) {
     191                sysman_log(LVL_ERROR,
     192                    "Expected section '%s' in configuration of unit '%s'",
     193                    section_name, unit_name(unit));
     194                return ENOENT;
     195        }
     196
     197        return config_load_ini_section(unit_configuration, section, u_cfg,
     198            text_parse);
    8199}
    9200
    10201static int unit_cfg_start(unit_t *unit)
    11202{
    12         //TODO
    13         return EOK;
    14 }
    15 
    16 static void unit_cfg_destroy(unit_t *unit)
    17 {
    18         //TODO
    19 }
    20 
    21 
    22 DEFINE_UNIT_OPS(unit_cfg)
    23 
     203        unit_cfg_t *u_cfg = CAST_CFG(unit);
     204        assert(u_cfg);
     205
     206        /*
     207         * Skip starting state and hold state lock during whole configuration
     208         * load.
     209         */
     210        fibril_mutex_lock(&unit->state_mtx);
     211        int rc = cfg_load_configuration(u_cfg->path);
     212       
     213        if (rc == EOK) {
     214                unit->state = STATE_STARTED;
     215        } else {
     216                unit->state = STATE_FAILED;
     217        }
     218        fibril_condvar_broadcast(&unit->state_cv);
     219        fibril_mutex_unlock(&unit->state_mtx);
     220
     221        return rc;
     222}
     223
     224DEFINE_UNIT_VMT(unit_cfg)
     225
Note: See TracChangeset for help on using the changeset viewer.