source: mainline/uspace/srv/sysman/units/unit_cfg.c@ 241f1985

Last change on this file since 241f1985 was 241f1985, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Correcting failure from previous merge

The commits from Michal Koutný from the branch system-daemon
where built on a old version of Helenos. Because of this
many types and API functions have changed. This commit
upgrades the merge code

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
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#include <adt/list.h>
30#include <assert.h>
31#include <conf/configuration.h>
32#include <conf/ini.h>
33#include <conf/text_parse.h>
34#include <dirent.h>
35#include <errno.h>
36#include <stdlib.h>
37#include <str.h>
38#include <sysman/unit.h>
39
40#include "repo.h"
41#include "log.h"
42#include "unit.h"
43#include "util.h"
44
45static const char *section_name = "Configuration";
46
47static config_item_t unit_configuration[] = {
48 {"Path", &config_parse_string, offsetof(unit_cfg_t, path), NULL},
49 CONFIGURATION_ITEM_SENTINEL
50};
51
52/**
53 * TODO refactor path handling and rename to 'load from file'
54 *
55 * @param[out] unit_ptr Unit loaded from the file. Undefined when function fails.
56 */
57static errno_t cfg_parse_file(const char *dirname, const char *filename,
58 unit_t **unit_ptr)
59{
60 errno_t rc = EOK;
61 unit_t *new_unit = NULL;
62 char *fn = NULL;
63 ini_configuration_t ini_conf;
64 text_parse_t text_parse;
65
66 ini_configuration_init(&ini_conf);
67 text_parse_init(&text_parse);
68
69 const char *last_sep = str_rchr(filename, UNIT_NAME_SEPARATOR);
70 if (last_sep == NULL) {
71 rc = EINVAL;
72 goto finish;
73 }
74
75 const char *unit_name = filename;
76 const char *unit_type_name = last_sep + 1;
77
78 unit_type_t unit_type = unit_type_name_to_type(unit_type_name);
79 if (unit_type == UNIT_TYPE_INVALID) {
80 rc = EINVAL;
81 goto finish;
82 }
83
84 /* We parse files as part of ongoing repo transaction (locked). */
85 unit_t *u = repo_find_unit_by_name_unsafe(unit_name);
86 if (u != NULL) {
87 // TODO allow updating configuration of existing unit
88 rc = EEXIST;
89 goto finish;
90 } else {
91 new_unit = u = unit_create(unit_type);
92 new_unit->name = str_dup(unit_name);
93 if (new_unit->name == NULL) {
94 rc = ENOMEM;
95 goto finish;
96 }
97 }
98 if (u == NULL) {
99 rc = ENOMEM;
100 goto finish;
101 }
102 assert(u->type == unit_type);
103
104 fn = util_compose_path(dirname, filename);
105 if (fn == NULL) {
106 rc = ENOMEM;
107 goto finish;
108 }
109
110 /* Parse INI file to ini_conf structure */
111 rc = ini_parse_file(fn, &ini_conf, &text_parse);
112 switch (rc) {
113 case EOK:
114 /* This is fine */
115 break;
116 case EINVAL:
117 goto dump_parse;
118 break;
119 default:
120 sysman_log(LVL_WARN,
121 "Cannot parse '%s' (%i).", fn, rc);
122 goto finish;
123 }
124
125 /* Parse ini structure */
126 rc = unit_load(u, &ini_conf, &text_parse);
127 *unit_ptr = u;
128
129 /*
130 * Here we just continue undisturbed by errors, they'll be returned in
131 * 'finish' block and potential parse errors (or none) will be logged
132 * in 'dump_parse' block.
133 */
134
135dump_parse:
136 list_foreach(text_parse.errors, link, text_parse_error_t, err) {
137 sysman_log(LVL_WARN,
138 "Error (%i) when parsing '%s' on line %lu.",
139 err->parse_errno, fn, err->lineno);
140 }
141
142finish:
143 free(fn);
144 ini_configuration_deinit(&ini_conf);
145 text_parse_deinit(&text_parse);
146 if (rc != EOK) {
147 unit_destroy(&new_unit);
148 }
149
150 return rc;
151}
152
153static errno_t cfg_load_configuration(const char *path)
154{
155 DIR *dir;
156 struct dirent *de;
157
158 dir = opendir(path);
159 if (dir == NULL) {
160 sysman_log(LVL_ERROR,
161 "Cannot open configuration directory '%s'", path);
162 return EIO;
163 }
164
165 repo_begin_update();
166
167 while ((de = readdir(dir))) {
168 unit_t *unit = NULL;
169 errno_t rc = cfg_parse_file(path, de->d_name, &unit);
170 if (rc != EOK) {
171 sysman_log(LVL_WARN, "Cannot load unit from file %s/%s",
172 path, de->d_name);
173 /*
174 * Ignore error for now, we'll fail only when we're
175 * unable to resolve dependency names.
176 */
177 continue;
178 }
179
180 assert(unit->repo_state == REPO_EMBRYO);
181 repo_add_unit(unit);
182 }
183 closedir(dir);
184
185 errno_t rc = repo_resolve_references();
186 if (rc != EOK) {
187 repo_rollback();
188 return rc;
189 }
190
191 repo_commit();
192 return EOK;
193}
194
195static void unit_cfg_init(unit_t *unit)
196{
197 unit_cfg_t *u_cfg = CAST_CFG(unit);
198 assert(u_cfg);
199}
200
201static void unit_cfg_destroy(unit_t *unit)
202{
203 unit_cfg_t *u_cfg = CAST_CFG(unit);
204 assert(u_cfg);
205
206 free(u_cfg->path);
207}
208
209static errno_t unit_cfg_load(unit_t *unit, ini_configuration_t *ini_conf,
210 text_parse_t *text_parse)
211{
212 unit_cfg_t *u_cfg = CAST_CFG(unit);
213 assert(u_cfg);
214
215 ini_section_t *section = ini_get_section(ini_conf, section_name);
216 if (section == NULL) {
217 sysman_log(LVL_ERROR,
218 "Expected section '%s' in configuration of unit '%s'",
219 section_name, unit_name(unit));
220 return ENOENT;
221 }
222
223 return config_load_ini_section(unit_configuration, section, u_cfg,
224 text_parse);
225}
226
227static errno_t unit_cfg_start(unit_t *unit)
228{
229 unit_cfg_t *u_cfg = CAST_CFG(unit);
230 assert(u_cfg);
231
232 errno_t rc = cfg_load_configuration(u_cfg->path);
233
234 if (rc == EOK) {
235 unit->state = STATE_STARTED;
236 } else {
237 unit->state = STATE_FAILED;
238 }
239
240 return rc;
241}
242
243static errno_t unit_cfg_stop(unit_t *unit)
244{
245 unit_cfg_t *u_cfg = CAST_CFG(unit);
246 assert(u_cfg);
247
248 /*
249 * It makes no sense to stop configuration (i.e. unload it), however,
250 * lets virtually stop it not to make obstructions for potential
251 * restart = reload of configuration.
252 */
253 unit->state = STATE_STOPPED;
254 return EOK;
255}
256
257static void unit_cfg_exposee_created(unit_t *unit)
258{
259 /* Configuration has no exposees. */
260 assert(false);
261}
262
263static void unit_cfg_fail(unit_t *unit)
264{
265 /* Configuration cannot async fail. */
266 assert(false);
267}
268
269DEFINE_UNIT_VMT(unit_cfg)
270
Note: See TracBrowser for help on using the repository browser.