Fix YANG feature installation.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / context.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "context.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include <sysrepo.h>
24 #include "core/session.h"
25 #include <dirent.h>
26 #include <libgen.h>
27 #include <assert.h>
28
29 //private variables for context state
30 struct lys_ident_with_childcount {
31     struct lys_ident *ident;
32     int children;
33 };
34 static struct lys_ident_with_childcount *identities;
35 static int identities_size;                 //number of found identities
36
37 struct features_with_info {
38     char *name;
39     bool enabled;
40 };
41 static struct features_with_info *features;
42 static int features_size;
43
44
45 //private functions
46 static bool check_identity_of_type(const struct lys_ident *ident, const struct lys_ident *type);
47 static int identity_get_id(const struct lys_ident *ident);
48
49 int context_init(const struct ly_ctx *ly_ctx) {
50     log_add_verbose(2, "context_init() begin\n");
51
52     identities = 0;
53     identities_size = 0;
54
55     features = 0;
56     features_size = 0;
57
58     log_add_verbose(2, "loading modules\n");
59     uint32_t idx = 0;
60     struct lys_module *module;
61     while((module = (struct lys_module *)ly_ctx_get_module_iter(ly_ctx, &idx)) != 0) {
62         log_add_verbose(2, "MODULE %s\n", module->name);
63         log_add_verbose(2, "  prefix: %s\n", module->prefix);
64         log_add_verbose(2, "  namespace: %s\n", module->ns);
65         log_add_verbose(2, "  imports [%d]", module->imp_size);
66         if(module->imp_size) {
67             log_add(2, ": ");
68             for(int i = 0; i < module->imp_size; i++) {
69                 log_add(2, "%s(%s), ", module->imp[i].module->name, module->imp[i].module->prefix);
70             }
71         }
72         log_add(2, "\n");
73         log_add_verbose(2, "  implemented: %d\n", module->implemented);
74
75         if(module->implemented) {
76             log_add_verbose(2, "  IDENT count: %d\n", module->ident_size);
77             if(module->ident_size) {
78                 //add to list of identities
79                 identities = (struct lys_ident_with_childcount *)realloc(identities, sizeof(struct lys_ident_with_childcount) * (identities_size + module->ident_size));
80                 if(!identities) {
81                     log_error("bad realloc\n");
82                     return 1;
83                 }
84
85                 for(int i = 0; i < module->ident_size; i++) {
86                     identities[identities_size].ident = &module->ident[i];
87                     identities[identities_size].children = 0;
88                     identities_size++;
89
90                     if(module->ident[i].base_size) {
91                         log_add_verbose(2, "  IDENT[%d]  %s with base %s:%s\n", i, module->ident[i].name, module->ident[i].base[0]->module->name, module->ident[i].base[0]->name);
92                         int id = identity_get_id(module->ident[i].base[0]);
93                         if(id != -1) {
94                             identities[id].children++;
95                         }
96                     }
97                     else {
98                         log_add_verbose(2, "  IDENT[%d]  %s as base\n", i, module->ident[i].name);
99                     }
100                 }
101             }
102
103
104             log_add_verbose(2, "  FEATURES count: %d\n", module->features_size);
105             if(module->features_size) {
106                 //add to list of features
107                 features = (struct features_with_info *)realloc(features, sizeof(struct features_with_info) * (features_size + module->features_size));
108                 if(!features) {
109                     log_error("bad realloc\n");
110                     return 1;
111                 }
112
113                 for(int i = 0; i < module->features_size; i++) {
114                     asprintf(&features[features_size].name, "%s:%s", module->name, module->features[i].name);
115                     features[features_size].enabled = (lys_features_state(module, module->features[i].name) == 1);
116                     log_add_verbose(2, "  FEATURE[%d]  %s iffeature_size=%d enabled=%d\n", i, module->features[i].name, module->features[i].iffeature_size, features[features_size].enabled);
117                     features_size++;
118                 }
119             }
120         }
121         else {
122             log_add_verbose(2, "-> module not implemented, skipping...\n");
123         }
124
125         log_add_verbose(2, " ----\n");
126     }
127
128     log_add_verbose(2, "context_init() finished\n");
129
130     return 0;
131 }
132
133 void context_free(void) {
134     log_add_verbose(2, "context_free()... ");
135     free(identities);
136     identities_size = 0;
137
138     for(int i = 0; i < features_size; i++) {
139         free(features[i].name);
140     }
141     free(features);
142     log_add(2, "done\n");
143 }
144
145 int context_get_identity_leafs_of_type(const struct lys_ident *ident, struct lys_ident ***found) {
146
147     *found = (struct lys_ident **)malloc(sizeof(struct lys_ident *) * identities_size);
148     if(!*found) {
149         log_error("bad malloc\n");
150     }
151
152     int count = 0;
153     for(int i = 0; i < identities_size; i++) {
154         if(check_identity_of_type(identities[i].ident, ident)) {
155             if(identities[i].children == 0) {
156                 (*found)[count] = identities[i].ident;
157                 count++;
158             }
159         }
160     }
161
162     if(count == 0) {
163         log_error("no identities found\n");
164     }
165     else {
166         *found = (struct lys_ident **)realloc(*found, sizeof(struct lys_ident *) * count);
167     }
168
169     return count;
170 }
171
172 int context_get_features(char ***found_features) {
173     char **ftrs = (char **)malloc(sizeof(char *) * features_size);
174     if(!ftrs) {
175         log_error("could not alloc\n");
176         return 0;
177     }
178
179     for(int i = 0; i < features_size; i++) {
180         ftrs[i] = (char *)malloc(sizeof(char) * (strlen(features[i].name) + 1));
181         if(!ftrs) {
182             log_error("could not alloc\n");
183             return 0;
184         }
185
186         strcpy(ftrs[i], features[i].name);
187     }
188
189     *found_features = ftrs;
190     return features_size;
191 }
192
193 bool context_get_feature_enabled(const char *feature) {
194     for(int i = 0; i < features_size; i++) {
195         if(strcmp(feature, features[i].name) == 0) {
196             return features[i].enabled;
197         }
198     }
199     return false;
200 }
201
202 bool context_feature_enable(const char *feature) {
203     assert(feature);
204
205     char mod[96];
206     char feat[96];
207
208     mod[0] = 0;
209     feat[0] = 0;
210
211     int i = 0;
212     int j = 0;
213     while((i < strlen(feature)) && (feature[i] != ':')) {
214         mod[j] = feature[i];
215         j++;
216         i++;
217     }
218     mod[j] = 0;
219
220     i++;
221     j = 0;
222     while(i < strlen(feature)) {
223         feat[j] = feature[i];
224         j++;
225         i++;
226     }
227     feat[j] = 0;
228
229     int rc;
230     if((rc = sr_enable_module_feature(session_connection, mod, feat)) != SR_ERR_OK) {
231         return false;
232     }
233
234     context_apply_changes();
235
236     return true;
237 }
238
239 bool context_module_install(const char *name, const char *path) {
240     assert(name);
241     assert(path);
242
243     char *searchpath = strdup(path);
244     int rc = sr_install_module(session_connection, path, dirname(searchpath), 0, 0);
245     free(searchpath);
246     if(rc != SR_ERR_OK) {
247         /* succeed if the module is already installed */
248         if(rc != SR_ERR_EXISTS) {
249             return false;
250         }
251     }
252
253     char *data_path = str_replace(path, ".yang", ".xml");
254     if(file_exists(data_path)) {
255         rc = sr_install_module_data(session_connection, name, 0, data_path, LYD_XML);
256         if(rc != SR_ERR_OK) {
257             log_add(1, " xml error    ");
258             sr_remove_module(session_connection, name);
259             context_apply_changes();
260             return false;
261         }
262     }
263     free(data_path);
264
265     data_path = str_replace(path, ".yang", ".json");
266     if(file_exists(data_path)) {
267         rc = sr_install_module_data(session_connection, name, 0, data_path, LYD_JSON);
268         if(rc != SR_ERR_OK) {
269             log_add(1, " json error    ");
270             sr_remove_module(session_connection, name);
271             context_apply_changes();
272             return false;
273         }
274     }
275     free(data_path);
276
277     //apply changes
278     if(!context_apply_changes()) {
279         sr_remove_module(session_connection, name);
280         context_apply_changes();
281         return false;
282     }
283
284     return true;
285 }
286
287 bool context_module_set_access(const char *module_name) {
288     assert(module_name);
289
290     if(sr_set_module_access(session_connection, module_name, "root", "root", 0666) != SR_ERR_OK) {
291         return false;
292     }
293
294     return true;
295 }
296
297 bool context_apply_changes(void) {
298     int rc;
299     uint32_t connection_count = 0;
300
301     session_context = 0;
302     sr_disconnect(session_connection);
303     session_connection = 0;
304
305     /* get connection count */
306     if((rc = sr_connection_count(&connection_count)) != SR_ERR_OK) {
307         log_error("sr_connection_count() failed to get connection count\n");
308         return false;
309     }
310
311     if(connection_count) {
312         log_error("cannot apply changes because of existing connections\n");
313         return false;
314     }
315
316     if((rc = sr_connect(SR_CONN_ERR_ON_SCHED_FAIL, &session_connection)) != SR_ERR_OK) {
317         if((rc = sr_connect(0, &session_connection)) != SR_ERR_OK) {
318             log_error("failed to reconnect to sysrepo\n");
319         }
320         return false;
321     }
322
323     /* get context */
324     session_context = (struct ly_ctx *)sr_get_context(session_connection);
325     if(session_context == 0) {
326         log_error("sr_get_context failed\n");
327         return false;
328     }
329
330     return true;
331 }
332
333 bool context_yang_is_module(const char *path) {
334     assert(path);
335
336     bool ret = false;
337     struct ly_ctx *ctx = ly_ctx_new(0, 0);
338     if(!ctx) {
339         log_error("ly_ctx_new failed\n");
340     }
341
342     char *searchpath = strdup(path);
343     ly_ctx_set_searchdir(ctx, dirname(searchpath));
344     const struct lys_module *mod = lys_parse_path(ctx, path, LYS_YANG);
345     if((!mod) && (ly_vecode(ctx) == LYVE_SUBMODULE)) {
346         ret = true;
347     }
348
349     free(searchpath);
350     ly_ctx_destroy(ctx, 0);
351     return ret;
352 }
353
354
355 static bool check_identity_of_type(const struct lys_ident *ident, const struct lys_ident *type) {
356     assert(type);
357
358     if((ident->name == type->name) && (ident->module->name == type->module->name)) {
359         return true;
360     }
361     else if(ident->base_size != 0) {
362         bool result = false;
363         for(int i = 0; i < ident->base_size; i++) {
364             result |= check_identity_of_type(ident->base[i], type);
365         }
366         return result;
367     }
368     else {
369         return false;
370     }
371
372 }
373
374 static int identity_get_id(const struct lys_ident *ident) {
375     assert(ident);
376
377     for(int i = 0; i < identities_size; i++) {
378         if((ident->name == identities[i].ident->name) && (ident->module->name == identities[i].ident->module->name)) {
379             return i;
380         }
381     }
382
383     return -1;
384 }