801966244e2f7c1d0c2968e933469d42a6a6e077
[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_message(2, "context_init() begin\n");
51
52     identities = 0;
53     identities_size = 0;
54
55     features = 0;
56     features_size = 0;
57
58     log_message(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_message(2, "MODULE %s\n", module->name);
63         log_message(2, "  prefix: %s\n", module->prefix);
64         log_message(2, "  namespace: %s\n", module->ns);
65         log_message(2, "  imports [%d]", module->imp_size);
66         if(module->imp_size) {
67             log_message(2, ": ");
68             for(int i = 0; i < module->imp_size; i++) {
69                 log_message(2, "%s(%s), ", module->imp[i].module->name, module->imp[i].module->prefix);
70             }
71         }
72         log_message(2, "\n");
73         log_message(2, "  implemented: %d\n", module->implemented);
74         
75         if(module->implemented) {
76             log_message(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");
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_message(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_message(2, "  IDENT[%d]  %s as base\n", i, module->ident[i].name);
99                     }
100                 }
101             }
102
103
104             log_message(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");
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_message(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_message(2, "Module not implemented, skipping...\n");
123         }
124
125         log_message(2, " ----\n");
126     }
127
128     log_message(2, "context_init() finished\n");
129
130     return 0;
131 }
132
133 void context_free(void) {
134     log_message(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_message(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");
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");
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");
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");
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     return true;
235 }
236
237 bool context_module_install(const char *name, const char *path) {
238     assert(name);
239     assert(path);
240
241     char *searchpath = strdup(path);
242     int rc = sr_install_module(session_connection, path, dirname(searchpath), 0, 0);
243     free(searchpath);
244     if(rc != SR_ERR_OK) {
245         /* succeed if the module is already installed */
246         if(rc != SR_ERR_EXISTS) {
247             return false;
248         }
249     }
250
251     char *data_path = str_replace(path, ".yang", ".xml");
252     if(file_exists(data_path)) {
253         rc = sr_install_module_data(session_connection, name, 0, data_path, LYD_XML);
254         if(rc != SR_ERR_OK) {
255             log_message(1, " xml error    ");
256             sr_remove_module(session_connection, name);
257             context_apply_changes();
258             return false;
259         }
260     }
261     free(data_path);
262
263     data_path = str_replace(path, ".yang", ".json");
264     if(file_exists(data_path)) {
265         rc = sr_install_module_data(session_connection, name, 0, data_path, LYD_JSON);
266         if(rc != SR_ERR_OK) {
267             log_message(1, " json error    ");
268             sr_remove_module(session_connection, name);
269             context_apply_changes();
270             return false;
271         }
272     }
273     free(data_path);
274
275     //apply changes
276     if(!context_apply_changes()) {
277         sr_remove_module(session_connection, name);
278         context_apply_changes();
279         return false;
280     }
281
282     return true;
283 }
284
285 bool context_module_set_access(const char *module_name) {
286     assert(module_name);
287
288     if(sr_set_module_access(session_connection, module_name, "root", "root", 0666) != SR_ERR_OK) {
289         return false;
290     }
291
292     return true;
293 }
294
295 bool context_apply_changes(void) {
296     int rc;
297     uint32_t connection_count = 0;
298
299     session_context = 0;
300     sr_disconnect(session_connection);
301     session_connection = 0;
302
303     /* get connection count */
304     if((rc = sr_connection_count(&connection_count)) != SR_ERR_OK) {
305         log_error("sr_connection_count() failed to get connection count");
306         return false;
307     }
308
309     if(connection_count) {
310         log_error("cannot apply changes because of existing connections");
311         return false;
312     }
313
314     if((rc = sr_connect(SR_CONN_ERR_ON_SCHED_FAIL, &session_connection)) != SR_ERR_OK) {
315         if((rc = sr_connect(0, &session_connection)) != SR_ERR_OK) {
316             log_error("failed to reconnect to sysrepo");
317         }
318         return false;
319     }
320
321     /* get context */
322     session_context = (struct ly_ctx *)sr_get_context(session_connection);
323     if(session_context == 0) {
324         log_error("sr_get_context failed");
325         return false;
326     }
327
328     return true;
329 }
330
331 bool context_yang_is_module(const char *path) {
332     assert(path);
333
334     bool ret = false;
335     struct ly_ctx *ctx = ly_ctx_new(0, 0);
336     if(!ctx) {
337         log_error("ly_ctx_new failed");
338     }
339
340     char *searchpath = strdup(path);
341     ly_ctx_set_searchdir(ctx, dirname(searchpath));
342     const struct lys_module *mod = lys_parse_path(ctx, path, LYS_YANG);
343     if((!mod) && (ly_vecode(ctx) == LYVE_SUBMODULE)) {
344         ret = true;
345     }
346
347     free(searchpath);
348     ly_ctx_destroy(ctx, 0);
349     return ret;
350 }
351
352
353 static bool check_identity_of_type(const struct lys_ident *ident, const struct lys_ident *type) {
354     assert(type);
355
356     if((ident->name == type->name) && (ident->module->name == type->module->name)) {
357         return true;
358     }
359     else if(ident->base_size != 0) {
360         bool result = false;
361         for(int i = 0; i < ident->base_size; i++) {
362             result |= check_identity_of_type(ident->base[i], type);
363         }
364         return result;
365     }
366     else {
367         return false;
368     }
369
370 }
371
372 static int identity_get_id(const struct lys_ident *ident) {
373     assert(ident);
374
375     for(int i = 0; i < identities_size; i++) {
376         if((ident->name == identities[i].ident->name) && (ident->module->name == identities[i].ident->module->name)) {
377             return i;
378         }
379     }
380
381     return -1;
382 }