blob: d651291d4530ea9b87a9379c74745b6053d1b7fa [file] [log] [blame]
Radek Krejcie9f13b12020-11-09 17:42:04 +01001/**
2 * @file common.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief libyang's yanglint tool - common functions for both interactive and non-interactive mode.
5 *
6 * Copyright (c) 2020 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
Radek Krejcie9f13b12020-11-09 17:42:04 +010017
18#include "common.h"
19
20#include <assert.h>
21#include <errno.h>
22#include <getopt.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/stat.h>
27
28#include "compat.h"
29#include "libyang.h"
30
31int
32parse_schema_path(const char *path, char **dir, char **module)
33{
34 char *p;
35
36 assert(dir);
37 assert(module);
38
39 /* split the path to dirname and basename for further work */
40 *dir = strdup(path);
41 *module = strrchr(*dir, '/');
42 if (!(*module)) {
43 *module = *dir;
44 *dir = strdup("./");
45 } else {
46 *module[0] = '\0'; /* break the dir */
47 *module = strdup((*module) + 1);
48 }
49 /* get the pure module name without suffix or revision part of the filename */
50 if ((p = strchr(*module, '@'))) {
51 /* revision */
52 *p = '\0';
53 } else if ((p = strrchr(*module, '.'))) {
54 /* fileformat suffix */
55 *p = '\0';
56 }
57
58 return 0;
59}
60
61int
62get_input(const char *filepath, LYS_INFORMAT *format_schema, LYD_FORMAT *format_data, struct ly_in **in)
63{
64 struct stat st;
65
66 /* check that the filepath exists and is a regular file */
67 if (stat(filepath, &st) == -1) {
68 YLMSG_E("Unable to use input filepath (%s) - %s.\n", filepath, strerror(errno));
69 return -1;
70 }
71 if (!S_ISREG(st.st_mode)) {
72 YLMSG_E("Provided input file (%s) is not a regular file.\n", filepath);
73 return -1;
74 }
75
Michal Vaskod3b10542021-02-03 11:31:16 +010076 if ((format_schema && !*format_schema) || (format_data && !*format_data)) {
77 /* get the file format */
78 if (get_format(filepath, format_schema, format_data)) {
79 return -1;
80 }
Radek Krejcie9f13b12020-11-09 17:42:04 +010081 }
82
83 if (ly_in_new_filepath(filepath, 0, in)) {
84 YLMSG_E("Unable to process input file.\n");
85 return -1;
86 }
87
88 return 0;
89}
90
91void
92free_features(void *flist)
93{
94 struct schema_features *rec = (struct schema_features *)flist;
95
96 if (rec) {
Michal Vaskoa9a98612021-11-22 10:00:27 +010097 free(rec->mod_name);
Radek Krejcie9f13b12020-11-09 17:42:04 +010098 if (rec->features) {
99 for (uint32_t u = 0; rec->features[u]; ++u) {
100 free(rec->features[u]);
101 }
102 free(rec->features);
103 }
104 free(rec);
105 }
106}
107
108void
109get_features(struct ly_set *fset, const char *module, const char ***features)
110{
111 /* get features list for this module */
112 for (uint32_t u = 0; u < fset->count; ++u) {
113 struct schema_features *sf = (struct schema_features *)fset->objs[u];
Michal Vaskoa9a98612021-11-22 10:00:27 +0100114 if (!strcmp(module, sf->mod_name)) {
Radek Krejci8143bb42021-04-07 11:43:50 +0200115 /* matched module - explicitly set features */
Radek Krejcie9f13b12020-11-09 17:42:04 +0100116 *features = (const char **)sf->features;
Michal Vasko686d8fc2021-11-22 10:03:23 +0100117 sf->applied = 1;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100118 return;
119 }
120 }
Radek Krejci8143bb42021-04-07 11:43:50 +0200121
Michal Vasko59740872021-11-22 10:01:34 +0100122 /* features not set so disable all */
123 *features = NULL;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100124}
125
126int
127parse_features(const char *fstring, struct ly_set *fset)
128{
129 struct schema_features *rec;
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200130 uint32_t count;
131 char *p, **fp;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100132
133 rec = calloc(1, sizeof *rec);
134 if (!rec) {
135 YLMSG_E("Unable to allocate features information record (%s).\n", strerror(errno));
136 return -1;
137 }
138 if (ly_set_add(fset, rec, 1, NULL)) {
139 YLMSG_E("Unable to store features information (%s).\n", strerror(errno));
140 free(rec);
141 return -1;
142 }
143
144 /* fill the record */
145 p = strchr(fstring, ':');
146 if (!p) {
Michal Vasko9a5f3dd2021-11-23 08:59:53 +0100147 YLMSG_E("Invalid format of the features specification (%s).\n", fstring);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100148 return -1;
149 }
Michal Vaskoa9a98612021-11-22 10:00:27 +0100150 rec->mod_name = strndup(fstring, p - fstring);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100151
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200152 count = 0;
153 while (p) {
Radek Krejcie9f13b12020-11-09 17:42:04 +0100154 size_t len = 0;
155 char *token = p + 1;
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200156
Radek Krejcie9f13b12020-11-09 17:42:04 +0100157 p = strchr(token, ',');
158 if (!p) {
159 /* the last item, if any */
160 len = strlen(token);
161 } else {
162 len = p - token;
163 }
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200164
Radek Krejcie9f13b12020-11-09 17:42:04 +0100165 if (len) {
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200166 fp = realloc(rec->features, (count + 1) * sizeof *rec->features);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100167 if (!fp) {
168 YLMSG_E("Unable to store features list information (%s).\n", strerror(errno));
169 return -1;
170 }
171 rec->features = fp;
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200172 fp = &rec->features[count++]; /* array item to set */
Radek Krejcie9f13b12020-11-09 17:42:04 +0100173 (*fp) = strndup(token, len);
174 }
175 }
176
Michal Vaskoe699f7b2022-05-09 10:49:57 +0200177 /* terminating NULL */
178 fp = realloc(rec->features, (count + 1) * sizeof *rec->features);
179 if (!fp) {
180 YLMSG_E("Unable to store features list information (%s).\n", strerror(errno));
181 return -1;
182 }
183 rec->features = fp;
184 rec->features[count++] = NULL;
185
Radek Krejcie9f13b12020-11-09 17:42:04 +0100186 return 0;
187}
188
189struct cmdline_file *
190fill_cmdline_file(struct ly_set *set, struct ly_in *in, const char *path, LYD_FORMAT format)
191{
192 struct cmdline_file *rec;
193
194 rec = malloc(sizeof *rec);
195 if (!rec) {
196 YLMSG_E("Allocating memory for data file information failed.\n");
197 return NULL;
198 }
199 if (set && ly_set_add(set, rec, 1, NULL)) {
200 free(rec);
Michal Vasko7edebb42021-01-25 14:18:46 +0100201 YLMSG_E("Storing data file information failed.\n");
Radek Krejcie9f13b12020-11-09 17:42:04 +0100202 return NULL;
203 }
204 rec->in = in;
205 rec->path = path;
206 rec->format = format;
207
208 return rec;
209}
210
211void
212free_cmdline_file(void *cmdline_file)
213{
214 struct cmdline_file *rec = (struct cmdline_file *)cmdline_file;
215
216 if (rec) {
217 ly_in_free(rec->in, 1);
218 free(rec);
219 }
220}
221
222void
223free_cmdline(char *argv[])
224{
225 if (argv) {
226 free(argv[0]);
227 free(argv);
228 }
229}
230
231int
232parse_cmdline(const char *cmdline, int *argc_p, char **argv_p[])
233{
234 int count;
235 char **vector;
236 char *ptr;
237 char qmark = 0;
238
239 assert(cmdline);
240 assert(argc_p);
241 assert(argv_p);
242
243 /* init */
244 optind = 0; /* reinitialize getopt() */
245 count = 1;
246 vector = malloc((count + 1) * sizeof *vector);
247 vector[0] = strdup(cmdline);
248
249 /* command name */
250 strtok(vector[0], " ");
251
252 /* arguments */
253 while ((ptr = strtok(NULL, " "))) {
254 size_t len;
255 void *r;
256
257 len = strlen(ptr);
258
259 if (qmark) {
260 /* still in quotated text */
261 /* remove NULL termination of the previous token since it is not a token,
262 * but a part of the quotation string */
263 ptr[-1] = ' ';
264
265 if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) {
266 /* end of quotation */
267 qmark = 0;
268 /* shorten the argument by the terminating quotation mark */
269 ptr[len - 1] = '\0';
270 }
271 continue;
272 }
273
274 /* another token in cmdline */
275 ++count;
276 r = realloc(vector, (count + 1) * sizeof *vector);
277 if (!r) {
Michal Vasko9a5f3dd2021-11-23 08:59:53 +0100278 YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno));
Radek Krejcie9f13b12020-11-09 17:42:04 +0100279 free(vector);
280 return -1;
281 }
282 vector = r;
283 vector[count - 1] = ptr;
284
285 if ((ptr[0] == '"') || (ptr[0] == '\'')) {
286 /* remember the quotation mark to identify end of quotation */
287 qmark = ptr[0];
288
289 /* move the remembered argument after the quotation mark */
290 ++vector[count - 1];
291
292 /* check if the quotation is terminated within this token */
293 if ((ptr[len - 1] == qmark) && (ptr[len - 2] != '\\')) {
294 /* end of quotation */
295 qmark = 0;
296 /* shorten the argument by the terminating quotation mark */
297 ptr[len - 1] = '\0';
298 }
299 }
300 }
301 vector[count] = NULL;
302
303 *argc_p = count;
304 *argv_p = vector;
305
306 return 0;
307}
308
309int
310get_format(const char *filename, LYS_INFORMAT *schema, LYD_FORMAT *data)
311{
312 char *ptr;
313 LYS_INFORMAT informat_s;
314 LYD_FORMAT informat_d;
315
316 /* get the file format */
317 if ((ptr = strrchr(filename, '.')) != NULL) {
318 ++ptr;
319 if (!strcmp(ptr, "yang")) {
320 informat_s = LYS_IN_YANG;
321 informat_d = 0;
322 } else if (!strcmp(ptr, "yin")) {
323 informat_s = LYS_IN_YIN;
324 informat_d = 0;
325 } else if (!strcmp(ptr, "xml")) {
326 informat_s = 0;
327 informat_d = LYD_XML;
328 } else if (!strcmp(ptr, "json")) {
329 informat_s = 0;
330 informat_d = LYD_JSON;
Michal Vaskod3b10542021-02-03 11:31:16 +0100331 } else if (!strcmp(ptr, "lyb")) {
332 informat_s = 0;
333 informat_d = LYD_LYB;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100334 } else {
335 YLMSG_E("Input file \"%s\" in an unknown format \"%s\".\n", filename, ptr);
336 return 0;
337 }
338 } else {
339 YLMSG_E("Input file \"%s\" without file extension - unknown format.\n", filename);
340 return 1;
341 }
342
343 if (informat_d) {
344 if (!data) {
345 YLMSG_E("Input file \"%s\" not expected to contain data instances (unexpected format).\n", filename);
346 return 2;
347 }
348 (*data) = informat_d;
349 } else if (informat_s) {
350 if (!schema) {
351 YLMSG_E("Input file \"%s\" not expected to contain schema definition (unexpected format).\n", filename);
352 return 3;
353 }
354 (*schema) = informat_s;
355 }
356
357 return 0;
358}
359
360int
361print_list(struct ly_out *out, struct ly_ctx *ctx, LYD_FORMAT outformat)
362{
363 struct lyd_node *ylib;
364 uint32_t idx = 0, has_modules = 0;
365 const struct lys_module *mod;
366
367 if (outformat != LYD_UNKNOWN) {
Michal Vasko794ab4b2021-03-31 09:42:19 +0200368 if (ly_ctx_get_yanglib_data(ctx, &ylib, "%u", ly_ctx_get_change_count(ctx))) {
Michal Vaskoc431a0a2021-01-25 14:31:58 +0100369 YLMSG_E("Getting context info (ietf-yang-library data) failed. If the YANG module is missing or not implemented, use an option to add it internally.\n");
Radek Krejcie9f13b12020-11-09 17:42:04 +0100370 return 1;
371 }
372
373 lyd_print_all(out, ylib, outformat, 0);
374 lyd_free_all(ylib);
375 return 0;
376 }
377
378 /* iterate schemas in context and provide just the basic info */
379 ly_print(out, "List of the loaded models:\n");
380 while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
381 has_modules++;
382
383 /* conformance print */
384 if (mod->implemented) {
385 ly_print(out, " I");
386 } else {
387 ly_print(out, " i");
388 }
389
390 /* module print */
391 ly_print(out, " %s", mod->name);
392 if (mod->revision) {
393 ly_print(out, "@%s", mod->revision);
394 }
395
396 /* submodules print */
397 if (mod->parsed && mod->parsed->includes) {
398 uint64_t u = 0;
399 ly_print(out, " (");
400 LY_ARRAY_FOR(mod->parsed->includes, u) {
401 ly_print(out, "%s%s", !u ? "" : ",", mod->parsed->includes[u].name);
402 if (mod->parsed->includes[u].rev[0]) {
403 ly_print(out, "@%s", mod->parsed->includes[u].rev);
404 }
405 }
406 ly_print(out, ")");
407 }
408
409 /* finish the line */
410 ly_print(out, "\n");
411 }
412
413 if (!has_modules) {
414 ly_print(out, "\t(none)\n");
415 }
416
417 ly_print_flush(out);
418 return 0;
419}
420
421int
Radek Krejcie9f13b12020-11-09 17:42:04 +0100422evaluate_xpath(const struct lyd_node *tree, const char *xpath)
423{
Radek Krejci89757c12020-11-26 12:07:47 +0100424 struct ly_set *set = NULL;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100425
426 if (lyd_find_xpath(tree, xpath, &set)) {
427 return -1;
428 }
429
430 /* print result */
431 printf("XPath \"%s\" evaluation result:\n", xpath);
432 if (!set->count) {
433 printf("\tEmpty\n");
434 } else {
435 for (uint32_t u = 0; u < set->count; ++u) {
436 struct lyd_node *node = (struct lyd_node *)set->objs[u];
437 printf(" %s \"%s\"", lys_nodetype2str(node->schema->nodetype), node->schema->name);
438 if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200439 printf(" (value: \"%s\")\n", lyd_get_value(node));
Radek Krejcie9f13b12020-11-09 17:42:04 +0100440 } else if (node->schema->nodetype == LYS_LIST) {
441 printf(" (");
442 for (struct lyd_node *key = ((struct lyd_node_inner *)node)->child; key && lysc_is_key(key->schema); key = key->next) {
443 printf("%s\"%s\": \"%s\";", (key != ((struct lyd_node_inner *)node)->child) ? " " : "",
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200444 key->schema->name, lyd_get_value(key));
Radek Krejcie9f13b12020-11-09 17:42:04 +0100445 }
446 printf(")\n");
447 }
448 }
449 }
450
451 ly_set_free(set, NULL);
452 return 0;
453}
454
455LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100456process_data(struct ly_ctx *ctx, enum lyd_type data_type, uint8_t merge, LYD_FORMAT format, struct ly_out *out,
Michal Vasko3f08fb92022-04-21 09:52:35 +0200457 uint32_t options_parse, uint32_t options_validate, uint32_t options_print, struct cmdline_file *operational_f,
458 struct cmdline_file *rpc_f, struct ly_set *inputs, struct ly_set *xpaths)
Radek Krejcie9f13b12020-11-09 17:42:04 +0100459{
Radek Krejci89757c12020-11-26 12:07:47 +0100460 LY_ERR ret = LY_SUCCESS;
Michal Vaskoff141b02022-05-02 09:22:36 +0200461 struct lyd_node *tree = NULL, *op = NULL, *envp = NULL, *merged_tree = NULL, *oper_tree = NULL;
Michal Vasko9e81ce52022-04-29 10:16:21 +0200462 char *path = NULL;
463 struct ly_set *set = NULL;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100464
465 /* additional operational datastore */
466 if (operational_f && operational_f->in) {
Michal Vasko3f08fb92022-04-21 09:52:35 +0200467 ret = lyd_parse_data(ctx, NULL, operational_f->in, operational_f->format, LYD_PARSE_ONLY, 0, &oper_tree);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100468 if (ret) {
469 YLMSG_E("Failed to parse operational datastore file \"%s\".\n", operational_f->path);
470 goto cleanup;
471 }
472 }
473
474 for (uint32_t u = 0; u < inputs->count; ++u) {
475 struct cmdline_file *input_f = (struct cmdline_file *)inputs->objs[u];
Radek Krejcie9f13b12020-11-09 17:42:04 +0100476 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +0100477 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +0100478 ret = lyd_parse_data(ctx, NULL, input_f->in, input_f->format, options_parse, options_validate, &tree);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100479 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +0100480 case LYD_TYPE_RPC_YANG:
481 case LYD_TYPE_REPLY_YANG:
482 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoff141b02022-05-02 09:22:36 +0200483 ret = lyd_parse_op(ctx, NULL, input_f->in, input_f->format, data_type, &tree, &op);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100484 break;
Michal Vasko3f08fb92022-04-21 09:52:35 +0200485 case LYD_TYPE_RPC_NETCONF:
486 case LYD_TYPE_NOTIF_NETCONF:
Michal Vaskoff141b02022-05-02 09:22:36 +0200487 ret = lyd_parse_op(ctx, NULL, input_f->in, input_f->format, data_type, &envp, &op);
488
489 /* adjust pointers */
490 for (tree = op; lyd_parent(tree); tree = lyd_parent(tree)) {}
Michal Vasko3f08fb92022-04-21 09:52:35 +0200491 break;
492 case LYD_TYPE_REPLY_NETCONF:
493 /* parse source RPC operation */
494 assert(rpc_f && rpc_f->in);
Michal Vaskoff141b02022-05-02 09:22:36 +0200495 ret = lyd_parse_op(ctx, NULL, rpc_f->in, rpc_f->format, LYD_TYPE_RPC_NETCONF, &envp, &op);
Michal Vasko3f08fb92022-04-21 09:52:35 +0200496 if (ret) {
497 YLMSG_E("Failed to parse source NETCONF RPC operation file \"%s\".\n", rpc_f->path);
498 goto cleanup;
499 }
500
Michal Vaskoff141b02022-05-02 09:22:36 +0200501 /* adjust pointers */
502 for (tree = op; lyd_parent(tree); tree = lyd_parent(tree)) {}
503
Michal Vasko3f08fb92022-04-21 09:52:35 +0200504 /* free input */
Michal Vaskoff141b02022-05-02 09:22:36 +0200505 lyd_free_siblings(lyd_child(op));
Michal Vasko3f08fb92022-04-21 09:52:35 +0200506
507 /* we do not care */
508 lyd_free_all(envp);
509 envp = NULL;
510
Michal Vaskoff141b02022-05-02 09:22:36 +0200511 ret = lyd_parse_op(ctx, op, input_f->in, input_f->format, data_type, &envp, NULL);
Michal Vasko3f08fb92022-04-21 09:52:35 +0200512 break;
Radek Krejci89757c12020-11-26 12:07:47 +0100513 default:
514 YLMSG_E("Internal error (%s:%d).\n", __FILE__, __LINE__);
515 goto cleanup;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100516 }
517
518 if (ret) {
519 YLMSG_E("Failed to parse input data file \"%s\".\n", input_f->path);
520 goto cleanup;
521 }
522
523 if (merge) {
524 /* merge the data so far parsed for later validation and print */
525 if (!merged_tree) {
526 merged_tree = tree;
527 } else {
528 ret = lyd_merge_siblings(&merged_tree, tree, LYD_MERGE_DESTRUCT);
529 if (ret) {
530 YLMSG_E("Merging %s with previous data failed.\n", input_f->path);
531 goto cleanup;
532 }
533 }
534 tree = NULL;
535 } else if (format) {
Michal Vasko3f08fb92022-04-21 09:52:35 +0200536 /* print */
537 switch (data_type) {
538 case LYD_TYPE_DATA_YANG:
539 lyd_print_all(out, tree, format, options_print);
540 break;
541 case LYD_TYPE_RPC_YANG:
542 case LYD_TYPE_REPLY_YANG:
543 case LYD_TYPE_NOTIF_YANG:
544 case LYD_TYPE_RPC_NETCONF:
545 case LYD_TYPE_NOTIF_NETCONF:
546 lyd_print_tree(out, tree, format, options_print);
547 break;
548 case LYD_TYPE_REPLY_NETCONF:
549 /* just the output */
550 lyd_print_tree(out, lyd_child(tree), format, options_print);
551 break;
552 default:
553 assert(0);
554 }
Michal Vasko0bec3222022-04-22 07:46:00 +0200555 } else {
556 /* validation of the RPC/Action/reply/Notification with the operational datastore, if any */
557 switch (data_type) {
558 case LYD_TYPE_DATA_YANG:
559 /* already validated */
560 break;
561 case LYD_TYPE_RPC_YANG:
562 case LYD_TYPE_RPC_NETCONF:
563 ret = lyd_validate_op(tree, oper_tree, LYD_TYPE_RPC_YANG, NULL);
564 break;
565 case LYD_TYPE_REPLY_YANG:
566 case LYD_TYPE_REPLY_NETCONF:
567 ret = lyd_validate_op(tree, oper_tree, LYD_TYPE_REPLY_YANG, NULL);
568 break;
569 case LYD_TYPE_NOTIF_YANG:
570 case LYD_TYPE_NOTIF_NETCONF:
571 ret = lyd_validate_op(tree, oper_tree, LYD_TYPE_NOTIF_YANG, NULL);
572 break;
573 default:
574 assert(0);
575 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100576 if (ret) {
Michal Vasko0bec3222022-04-22 07:46:00 +0200577 if (operational_f->path) {
578 YLMSG_E("Failed to validate input data file \"%s\" with operational datastore \"%s\".\n",
579 input_f->path, operational_f->path);
580 } else {
581 YLMSG_E("Failed to validate input data file \"%s\".\n", input_f->path);
582 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100583 goto cleanup;
584 }
Michal Vasko9e81ce52022-04-29 10:16:21 +0200585
Michal Vaskoff141b02022-05-02 09:22:36 +0200586 if (op && oper_tree && lyd_parent(op)) {
Michal Vasko9e81ce52022-04-29 10:16:21 +0200587 /* check operation parent existence */
Michal Vaskoff141b02022-05-02 09:22:36 +0200588 path = lyd_path(lyd_parent(op), LYD_PATH_STD, NULL, 0);
Michal Vasko9e81ce52022-04-29 10:16:21 +0200589 if (!path) {
590 ret = LY_EMEM;
591 goto cleanup;
592 }
593 if ((ret = lyd_find_xpath(oper_tree, path, &set))) {
594 goto cleanup;
595 }
596 if (!set->count) {
Michal Vaskoff141b02022-05-02 09:22:36 +0200597 YLMSG_E("Operation \"%s\" parent \"%s\" not found in the operational data.\n", LYD_NAME(op), path);
Michal Vasko9e81ce52022-04-29 10:16:21 +0200598 ret = LY_EVALID;
599 goto cleanup;
600 }
601 }
Radek Krejcie9f13b12020-11-09 17:42:04 +0100602 }
Michal Vasko3f08fb92022-04-21 09:52:35 +0200603
604 /* next iter */
Radek Krejcie9f13b12020-11-09 17:42:04 +0100605 lyd_free_all(tree);
606 tree = NULL;
Michal Vasko3f08fb92022-04-21 09:52:35 +0200607 lyd_free_all(envp);
608 envp = NULL;
Radek Krejcie9f13b12020-11-09 17:42:04 +0100609 }
610
611 if (merge) {
612 /* validate the merged result */
613 ret = lyd_validate_all(&merged_tree, ctx, LYD_VALIDATE_PRESENT, NULL);
614 if (ret) {
615 YLMSG_E("Merged data are not valid.\n");
616 goto cleanup;
617 }
618
619 if (format) {
620 /* and print it */
621 lyd_print_all(out, merged_tree, format, options_print);
622 }
623
Michal Vaskof8e71f72022-03-29 12:12:58 +0200624 for (uint32_t u = 0; xpaths && (u < xpaths->count); ++u) {
Radek Krejcie9f13b12020-11-09 17:42:04 +0100625 if (evaluate_xpath(merged_tree, (const char *)xpaths->objs[u])) {
626 goto cleanup;
627 }
628 }
629 }
630
631cleanup:
Radek Krejcie9f13b12020-11-09 17:42:04 +0100632 lyd_free_all(tree);
Michal Vasko3f08fb92022-04-21 09:52:35 +0200633 lyd_free_all(envp);
Michal Vaskoe1f495b2022-04-20 08:32:41 +0200634 lyd_free_all(merged_tree);
Michal Vasko3f08fb92022-04-21 09:52:35 +0200635 lyd_free_all(oper_tree);
Michal Vasko9e81ce52022-04-29 10:16:21 +0200636 free(path);
637 ly_set_free(set, NULL);
Radek Krejcie9f13b12020-11-09 17:42:04 +0100638 return ret;
639}