summaryrefslogtreecommitdiffstats
path: root/tools/lint/main_ni.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lint/main_ni.c')
-rw-r--r--tools/lint/main_ni.c790
1 files changed, 275 insertions, 515 deletions
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 04c2340..c08acc3 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -2,9 +2,10 @@
* @file main_ni.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
+ * @author Adam Piecek <piecek@cesnet.cz>
* @brief libyang's yanglint tool - non-interactive code
*
- * Copyright (c) 2020 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -25,107 +26,13 @@
#include <sys/stat.h>
#include "libyang.h"
-#include "plugins_exts.h"
+#include "cmd.h"
#include "common.h"
#include "out.h"
#include "tools/config.h"
-
-/**
- * @brief Context structure to hold and pass variables in a structured form.
- */
-struct context {
- /* libyang context for the run */
- const char *yang_lib_file;
- uint16_t ctx_options;
- struct ly_ctx *ctx;
-
- /* prepared output (--output option or stdout by default) */
- struct ly_out *out;
-
- char *searchpaths;
-
- /* options flags */
- uint8_t list; /* -l option to print list of schemas */
-
- /* line length for 'tree' format */
- size_t line_length; /* --tree-line-length */
-
- /*
- * schema
- */
- /* set schema modules' features via --features option (struct schema_features *) */
- struct ly_set schema_features;
-
- /* set of loaded schema modules (struct lys_module *) */
- struct ly_set schema_modules;
-
- /* options to parse and print schema modules */
- uint32_t schema_parse_options;
- uint32_t schema_print_options;
-
- /* specification of printing schema node subtree, option --schema-node */
- const char *schema_node_path;
- const struct lysc_node *schema_node;
- const char *submodule;
-
- /* name of file containing explicit context passed to callback
- * for schema-mount extension. This also causes a callback to
- * be registered.
- */
- char *schema_context_filename;
-
- /* value of --format in case of schema format */
- LYS_OUTFORMAT schema_out_format;
- ly_bool feature_param_format;
-
- /*
- * data
- */
- /* various options based on --type option */
- enum lyd_type data_type;
- uint32_t data_parse_options;
- uint32_t data_validate_options;
- uint32_t data_print_options;
-
- /* flag for --merge option */
- uint8_t data_merge;
-
- /* value of --format in case of data format */
- LYD_FORMAT data_out_format;
-
- /* input data files (struct cmdline_file *) */
- struct ly_set data_inputs;
-
- /* storage for --operational */
- struct cmdline_file data_operational;
-
- /* storage for --reply-rpc */
- struct cmdline_file reply_rpc;
-};
-
-static void
-erase_context(struct context *c)
-{
- /* data */
- ly_set_erase(&c->data_inputs, free_cmdline_file);
- ly_in_free(c->data_operational.in, 1);
-
- /* schema */
- ly_set_erase(&c->schema_features, free_features);
- ly_set_erase(&c->schema_modules, NULL);
-
- /* context */
- free(c->searchpaths);
- c->searchpaths = NULL;
-
- ly_out_free(c->out, NULL, 0);
- ly_ctx_destroy(c->ctx);
-
- if (c->schema_context_filename) {
- free(c->schema_context_filename);
- }
-}
+#include "yl_opt.h"
+#include "yl_schema_features.h"
static void
version(void)
@@ -146,7 +53,8 @@ help(int shortout)
" printing them in the specified format.\n\n"
" yanglint -t (nc-)rpc/notif [-O <operational-file>] <schema>... <file>\n"
" Validates the YANG/NETCONF RPC/notification <file> according to the <schema>(s) using\n"
- " <operational-file> with possible references to the operational datastore data.\n\n"
+ " <operational-file> with possible references to the operational datastore data.\n"
+ " To validate nested-notification or action, the <operational-file> is required.\n\n"
" yanglint -t nc-reply -R <rpc-file> [-O <operational-file>] <schema>... <file>\n"
" Validates the NETCONF rpc-reply <file> of RPC <rpc-file> according to the <schema>(s)\n"
" using <operational-file> with possible references to the operational datastore data.\n\n"
@@ -169,10 +77,16 @@ help(int shortout)
" yang, yin, tree, info and feature-param for schemas,\n"
" xml, json, and lyb for data.\n\n");
+ printf(" -I FORMAT, --in-format=FORMAT\n"
+ " Load the data in one of the following formats:\n"
+ " xml, json, lyb\n"
+ " If input format not specified, it is detected from the file extension.\n\n");
+
printf(" -p PATH, --path=PATH\n"
" Search path for schema (YANG/YIN) modules. The option can be\n"
" used multiple times. The current working directory and the\n"
- " path of the module being added is used implicitly.\n\n");
+ " path of the module being added is used implicitly. Subdirectories\n"
+ " are also searched\n\n");
printf(" -D, --disable-searchdir\n"
" Do not implicitly search in current working directory for\n"
@@ -251,6 +165,13 @@ help(int shortout)
" trim - Remove all nodes with a default value.\n"
" implicit-tagged - Add missing nodes and mark them with the attribute.\n\n");
+ printf(" -E XPATH, --data-xpath=XPATH\n"
+ " Evaluate XPATH expression over the data and print the nodes satisfying\n"
+ " the expression. The output format is specific and the option cannot\n"
+ " be combined with the -f and -d options. Also all the data\n"
+ " inputs are merged into a single data tree where the expression\n"
+ " is evaluated, so the -m option is always set implicitly.\n\n");
+
printf(" -l, --list Print info about the loaded schemas.\n"
" (i - imported module, I - implemented module)\n"
" In case the '-f' option with data encoding is specified,\n"
@@ -267,8 +188,8 @@ help(int shortout)
" Provide optional data to extend validation of the '(nc-)rpc',\n"
" '(nc-)reply' or '(nc-)notif' TYPEs. The FILE is supposed to contain\n"
" the operational datastore referenced from the operation.\n"
- " In case of a nested operation, its parent existence is also\n"
- " checked in these operational data.\n\n");
+ " In case of a nested notification or action, its parent existence\n"
+ " is also checked in these operational data.\n\n");
printf(" -R FILE, --reply-rpc=FILE\n"
" Provide source RPC for parsing of the 'nc-reply' TYPE. The FILE\n"
@@ -287,6 +208,9 @@ help(int shortout)
" create an exact YANG schema context. If specified, the '-F'\n"
" parameter (enabled features) is ignored.\n\n");
+ printf(" -X, --extended-leafref\n"
+ " Allow usage of deref() XPath function within leafref\n\n");
+
#ifndef NDEBUG
printf(" -G GROUPS, --debug=GROUPS\n"
" Enable printing of specific debugging message group\n"
@@ -321,11 +245,11 @@ libyang_verbclb(LY_LOG_LEVEL level, const char *msg, const char *path)
}
}
-static struct schema_features *
+static struct yl_schema_features *
get_features_not_applied(const struct ly_set *fset)
{
for (uint32_t u = 0; u < fset->count; ++u) {
- struct schema_features *sf = fset->objs[u];
+ struct yl_schema_features *sf = fset->objs[u];
if (!sf->applied) {
return sf;
@@ -335,190 +259,166 @@ get_features_not_applied(const struct ly_set *fset)
return NULL;
}
-static LY_ERR
-ext_data_clb(const struct lysc_ext_instance *ext, void *user_data, void **ext_data, ly_bool *ext_data_free)
-{
- struct ly_ctx *ctx;
- struct lyd_node *data = NULL;
-
- ctx = ext->module->ctx;
- if (user_data) {
- lyd_parse_data_path(ctx, user_data, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, &data);
- }
-
- *ext_data = data;
- *ext_data_free = 1;
- return LY_SUCCESS;
-}
-
-static LY_ERR
-searchpath_strcat(char **searchpaths, const char *path)
-{
- uint64_t len;
- char *new;
-
- if (!(*searchpaths)) {
- *searchpaths = strdup(path);
- return LY_SUCCESS;
- }
-
- len = strlen(*searchpaths) + strlen(path) + strlen(PATH_SEPARATOR);
- new = realloc(*searchpaths, sizeof(char) * len + 1);
- if (!new) {
- return LY_EMEM;
- }
- strcat(new, PATH_SEPARATOR);
- strcat(new, path);
- *searchpaths = new;
-
- return LY_SUCCESS;
-}
-
+/**
+ * @brief Create the libyang context.
+ *
+ * @param[in] yang_lib_file Context can be defined in yang library file.
+ * @param[in] searchpaths Directories in which modules are searched.
+ * @param[in,out] schema_features Set of features.
+ * @param[in,out] ctx_options Options for libyang context.
+ * @param[out] ctx Context for libyang.
+ * @return 0 on success.
+ */
static int
-fill_context_inputs(int argc, char *argv[], struct context *c)
+create_ly_context(const char *yang_lib_file, const char *searchpaths, struct ly_set *schema_features,
+ uint16_t *ctx_options, struct ly_ctx **ctx)
{
- struct ly_in *in = NULL;
- struct schema_features *sf;
- struct lys_module *mod;
- const char *all_features[] = {"*", NULL};
- char *dir = NULL, *module = NULL;
-
- /* Create libyang context. */
- if (c->yang_lib_file) {
+ if (yang_lib_file) {
/* ignore features */
- ly_set_erase(&c->schema_features, free_features);
+ ly_set_erase(schema_features, yl_schema_features_free);
- if (ly_ctx_new_ylpath(c->searchpaths, c->yang_lib_file, LYD_UNKNOWN, c->ctx_options, &c->ctx)) {
- YLMSG_E("Unable to modify libyang context with yang-library data.\n");
+ if (ly_ctx_new_ylpath(searchpaths, yang_lib_file, LYD_UNKNOWN, *ctx_options, ctx)) {
+ YLMSG_E("Unable to modify libyang context with yang-library data.");
return -1;
}
} else {
/* set imp feature flag if all should be enabled */
- c->ctx_options |= !c->schema_features.count ? LY_CTX_ENABLE_IMP_FEATURES : 0;
+ (*ctx_options) |= !schema_features->count ? LY_CTX_ENABLE_IMP_FEATURES : 0;
- if (ly_ctx_new(c->searchpaths, c->ctx_options, &c->ctx)) {
- YLMSG_E("Unable to create libyang context\n");
+ if (ly_ctx_new(searchpaths, *ctx_options, ctx)) {
+ YLMSG_E("Unable to create libyang context.");
return -1;
}
}
- /* set callback providing run-time extension instance data */
- if (c->schema_context_filename) {
- ly_ctx_set_ext_data_clb(c->ctx, ext_data_clb, c->schema_context_filename);
- }
+ return 0;
+}
- /* process the operational and/or reply RPC content if any */
- if (c->data_operational.path) {
- if (get_input(c->data_operational.path, NULL, &c->data_operational.format, &c->data_operational.in)) {
- return -1;
+/**
+ * @brief Implement module if some feature has not been applied.
+ *
+ * @param[in] schema_features Set of features.
+ * @param[in,out] ctx Context for libyang.
+ * @return 0 on success.
+ */
+static int
+apply_features(struct ly_set *schema_features, struct ly_ctx *ctx)
+{
+ struct yl_schema_features *sf;
+ struct lys_module *mod;
+
+ /* check that all specified features were applied, apply now if possible */
+ while ((sf = get_features_not_applied(schema_features))) {
+ /* try to find implemented or the latest revision of this module */
+ mod = ly_ctx_get_module_implemented(ctx, sf->mod_name);
+ if (!mod) {
+ mod = ly_ctx_get_module_latest(ctx, sf->mod_name);
}
- }
- if (c->reply_rpc.path) {
- if (get_input(c->reply_rpc.path, NULL, &c->reply_rpc.format, &c->reply_rpc.in)) {
- return -1;
+ if (!mod) {
+ YLMSG_E("Specified features not applied, module \"%s\" not loaded.", sf->mod_name);
+ return 1;
}
- }
- for (int i = 0; i < argc - optind; i++) {
- LYS_INFORMAT format_schema = LYS_IN_UNKNOWN;
- LYD_FORMAT format_data = LYD_UNKNOWN;
-
- if (get_input(argv[optind + i], &format_schema, &format_data, &in)) {
- goto error;
+ /* we have the module, implement it if needed and enable the specific features */
+ if (lys_set_implemented(mod, (const char **)sf->features)) {
+ YLMSG_E("Implementing module \"%s\" failed.", mod->name);
+ return 1;
}
+ sf->applied = 1;
+ }
- if (format_schema) {
- LY_ERR ret;
- uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
- const char **features;
+ return 0;
+}
- /* parse the input */
- if (parse_schema_path(argv[optind + i], &dir, &module)) {
- goto error;
- }
+/**
+ * @brief Parse and compile modules, data are only stored for later processing.
+ *
+ * @param[in] argc Number of strings in @p argv.
+ * @param[in] argv Strings from command line.
+ * @param[in] optind Index to the first input file in @p argv.
+ * @param[in] data_in_format Specified input data format.
+ * @param[in,out] ctx Context for libyang.
+ * @param[in,out] yo Options for yanglint.
+ * @return 0 on success.
+ */
+static int
+fill_context_inputs(int argc, char *argv[], int optind, LYD_FORMAT data_in_format, struct ly_ctx *ctx,
+ struct yl_opt *yo)
+{
+ char *filepath = NULL;
+ LYS_INFORMAT format_schema;
+ LYD_FORMAT format_data;
- if (c->yang_lib_file) {
- /* just get the module, it should already be parsed */
- mod = ly_ctx_get_module_implemented(c->ctx, module);
- if (!mod) {
- YLMSG_E("Schema module \"%s\" not implemented in yang-library data.\n", module);
- goto error;
- }
- } else {
- /* add temporarily also the path of the module itself */
- if (ly_ctx_set_searchdir(c->ctx, dir) == LY_EEXIST) {
- path_unset = 0;
- }
+ for (int i = 0; i < argc - optind; i++) {
+ format_schema = LYS_IN_UNKNOWN;
+ format_data = data_in_format;
- /* get features list for this module */
- if (!c->schema_features.count) {
- features = all_features;
- } else {
- get_features(&c->schema_features, module, &features);
- }
+ filepath = argv[optind + i];
- /* parse module */
- ret = lys_parse(c->ctx, in, format_schema, features, &mod);
- ly_ctx_unset_searchdir_last(c->ctx, path_unset);
- if (ret) {
- YLMSG_E("Parsing schema module \"%s\" failed.\n", argv[optind + i]);
- goto error;
- }
- }
+ if (!filepath) {
+ return -1;
+ }
+ if (get_format(filepath, &format_schema, &format_data)) {
+ return -1;
+ }
- /* temporary cleanup */
- free(dir);
- dir = NULL;
- free(module);
- module = NULL;
-
- if (c->schema_out_format || c->feature_param_format) {
- /* module will be printed */
- if (ly_set_add(&c->schema_modules, (void *)mod, 1, NULL)) {
- YLMSG_E("Storing parsed schema module (%s) for print failed.\n", argv[optind + i]);
- goto error;
- }
+ if (format_schema) {
+ if (cmd_add_exec(&ctx, yo, filepath)) {
+ return -1;
}
- } else if (format_data) {
- if (!fill_cmdline_file(&c->data_inputs, in, argv[optind + i], format_data)) {
- goto error;
+ } else {
+ if (cmd_data_store(&ctx, yo, filepath)) {
+ return -1;
}
- in = NULL;
}
+ }
- ly_in_free(in, 1);
- in = NULL;
+ /* Check that all specified features were applied, apply now if possible. */
+ if (apply_features(&yo->schema_features, ctx)) {
+ return -1;
}
- /* check that all specified features were applied, apply now if possible */
- while ((sf = get_features_not_applied(&c->schema_features))) {
- /* try to find implemented or the latest revision of this module */
- mod = ly_ctx_get_module_implemented(c->ctx, sf->mod_name);
- if (!mod) {
- mod = ly_ctx_get_module_latest(c->ctx, sf->mod_name);
- }
- if (!mod) {
- YLMSG_E("Specified features not applied, module \"%s\" not loaded.\n", sf->mod_name);
- goto error;
- }
+ return 0;
+}
- /* we have the module, implement it if needed and enable the specific features */
- if (lys_set_implemented(mod, (const char **)sf->features)) {
- YLMSG_E("Implementing module \"%s\" failed.\n", mod->name);
- goto error;
+#ifndef NDEBUG
+/**
+ * @brief Enable specific debugging messages.
+ *
+ * @param[in] groups String in the form "<group>[,group>]*".
+ * @param[in,out] yo Options for yanglint.
+ * return 0 on success.
+ */
+static int
+set_debug_groups(char *groups, struct yl_opt *yo)
+{
+ int rc;
+ char *str, *end;
+
+ /* Process all debug arguments except the last one. */
+ for (str = groups; (end = strchr(str, ',')); str = end + 1) {
+ /* Temporary modify input string. */
+ *end = '\0';
+ rc = cmd_debug_store(NULL, yo, str);
+ *end = ',';
+ if (rc) {
+ return -1;
}
- sf->applied = 1;
+ }
+ /* Process single/last debug argument. */
+ if (cmd_debug_store(NULL, yo, str)) {
+ return -1;
+ }
+ /* All debug arguments are valid, so they can apply. */
+ if (cmd_debug_setlog(NULL, yo)) {
+ return -1;
}
return 0;
-
-error:
- ly_in_free(in, 1);
- free(dir);
- free(module);
- return -1;
}
+#endif
+
/**
* @brief Process command line options and store the settings into the context.
*
@@ -527,10 +427,8 @@ error:
* return 1 in case of success, but expect to exit.
*/
static int
-fill_context(int argc, char *argv[], struct context *c)
+fill_context(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
{
- int ret;
-
int opt, opt_index;
struct option options[] = {
{"help", no_argument, NULL, 'h'},
@@ -542,6 +440,7 @@ fill_context(int argc, char *argv[], struct context *c)
{"disable-searchdir", no_argument, NULL, 'D'},
{"features", required_argument, NULL, 'F'},
{"make-implemented", no_argument, NULL, 'i'},
+ {"in-format", required_argument, NULL, 'I'},
{"schema-node", required_argument, NULL, 'P'},
{"single-node", no_argument, NULL, 'q'},
{"submodule", required_argument, NULL, 's'},
@@ -550,6 +449,7 @@ fill_context(int argc, char *argv[], struct context *c)
{"present", no_argument, NULL, 'e'},
{"type", required_argument, NULL, 't'},
{"default", required_argument, NULL, 'd'},
+ {"data-xpath", required_argument, NULL, 'E'},
{"list", no_argument, NULL, 'l'},
{"tree-line-length", required_argument, NULL, 'L'},
{"output", required_argument, NULL, 'o'},
@@ -558,6 +458,7 @@ fill_context(int argc, char *argv[], struct context *c)
{"merge", no_argument, NULL, 'm'},
{"yang-library", no_argument, NULL, 'y'},
{"yang-library-file", required_argument, NULL, 'Y'},
+ {"extended-leafref", no_argument, NULL, 'X'},
#ifndef NDEBUG
{"debug", required_argument, NULL, 'G'},
#endif
@@ -565,15 +466,16 @@ fill_context(int argc, char *argv[], struct context *c)
};
uint8_t data_type_set = 0;
- c->ctx_options = YL_DEFAULT_CTX_OPTIONS;
- c->data_parse_options = YL_DEFAULT_DATA_PARSE_OPTIONS;
- c->line_length = 0;
+ yo->ctx_options = YL_DEFAULT_CTX_OPTIONS;
+ yo->data_parse_options = YL_DEFAULT_DATA_PARSE_OPTIONS;
+ yo->data_validate_options = YL_DEFAULT_DATA_VALIDATE_OPTIONS;
+ yo->line_length = 0;
opterr = 0;
#ifndef NDEBUG
- while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:R:myY:x:G:", options, &opt_index)) != -1)
+ while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:Xx:G:", options, &opt_index)) != -1)
#else
- while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:O:R:myY:x:", options, &opt_index)) != -1)
+ while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:Xx:", options, &opt_index)) != -1)
#endif
{
switch (opt) {
@@ -609,138 +511,77 @@ fill_context(int argc, char *argv[], struct context *c)
} /* case 'Q' */
case 'f': /* --format */
- if (!strcasecmp(optarg, "yang")) {
- c->schema_out_format = LYS_OUT_YANG;
- c->data_out_format = 0;
- } else if (!strcasecmp(optarg, "yin")) {
- c->schema_out_format = LYS_OUT_YIN;
- c->data_out_format = 0;
- } else if (!strcasecmp(optarg, "info")) {
- c->schema_out_format = LYS_OUT_YANG_COMPILED;
- c->data_out_format = 0;
- } else if (!strcasecmp(optarg, "tree")) {
- c->schema_out_format = LYS_OUT_TREE;
- c->data_out_format = 0;
- } else if (!strcasecmp(optarg, "xml")) {
- c->schema_out_format = 0;
- c->data_out_format = LYD_XML;
- } else if (!strcasecmp(optarg, "json")) {
- c->schema_out_format = 0;
- c->data_out_format = LYD_JSON;
- } else if (!strcasecmp(optarg, "lyb")) {
- c->schema_out_format = 0;
- c->data_out_format = LYD_LYB;
- } else if (!strcasecmp(optarg, "feature-param")) {
- c->feature_param_format = 1;
- } else {
- YLMSG_E("Unknown output format %s\n", optarg);
+ if (yl_opt_update_out_format(optarg, yo)) {
help(1);
return -1;
}
break;
- case 'p': { /* --path */
- struct stat st;
-
- if (stat(optarg, &st) == -1) {
- YLMSG_E("Unable to use search path (%s) - %s.\n", optarg, strerror(errno));
- return -1;
- }
- if (!S_ISDIR(st.st_mode)) {
- YLMSG_E("Provided search path is not a directory.\n");
+ case 'I': /* --in-format */
+ if (yo_opt_update_data_in_format(optarg, yo)) {
+ YLMSG_E("Unknown input format %s.", optarg);
+ help(1);
return -1;
}
+ break;
- if (searchpath_strcat(&c->searchpaths, optarg)) {
- YLMSG_E("Storing searchpath failed.\n");
+ case 'p': /* --path */
+ if (searchpath_strcat(&yo->searchpaths, optarg)) {
+ YLMSG_E("Storing searchpath failed.");
return -1;
}
-
break;
- } /* case 'p' */
+ /* case 'p' */
- case 'D': /* --disable-search */
- if (c->ctx_options & LY_CTX_DISABLE_SEARCHDIRS) {
- YLMSG_W("The -D option specified too many times.\n");
- }
- if (c->ctx_options & LY_CTX_DISABLE_SEARCHDIR_CWD) {
- c->ctx_options &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
- c->ctx_options |= LY_CTX_DISABLE_SEARCHDIRS;
- } else {
- c->ctx_options |= LY_CTX_DISABLE_SEARCHDIR_CWD;
+ case 'D': /* --disable-searchdir */
+ if (yo->ctx_options & LY_CTX_DISABLE_SEARCHDIRS) {
+ YLMSG_W("The -D option specified too many times.");
}
+ yo_opt_update_disable_searchdir(yo);
break;
case 'F': /* --features */
- if (parse_features(optarg, &c->schema_features)) {
+ if (parse_features(optarg, &yo->schema_features)) {
return -1;
}
break;
case 'i': /* --make-implemented */
- if (c->ctx_options & LY_CTX_REF_IMPLEMENTED) {
- c->ctx_options &= ~LY_CTX_REF_IMPLEMENTED;
- c->ctx_options |= LY_CTX_ALL_IMPLEMENTED;
- } else {
- c->ctx_options |= LY_CTX_REF_IMPLEMENTED;
- }
+ yo_opt_update_make_implemented(yo);
break;
case 'P': /* --schema-node */
- c->schema_node_path = optarg;
+ yo->schema_node_path = optarg;
break;
case 'q': /* --single-node */
- c->schema_print_options |= LYS_PRINT_NO_SUBSTMT;
+ yo->schema_print_options |= LYS_PRINT_NO_SUBSTMT;
break;
case 's': /* --submodule */
- c->submodule = optarg;
+ yo->submodule = optarg;
break;
case 'x': /* --ext-data */
- c->schema_context_filename = strdup(optarg);
+ yo->schema_context_filename = optarg;
break;
case 'n': /* --not-strict */
- c->data_parse_options &= ~LYD_PARSE_STRICT;
+ yo->data_parse_options &= ~LYD_PARSE_STRICT;
break;
case 'e': /* --present */
- c->data_validate_options |= LYD_VALIDATE_PRESENT;
+ yo->data_validate_options |= LYD_VALIDATE_PRESENT;
break;
case 't': /* --type */
if (data_type_set) {
- YLMSG_E("The data type (-t) cannot be set multiple times.\n");
+ YLMSG_E("The data type (-t) cannot be set multiple times.");
return -1;
}
- if (!strcasecmp(optarg, "config")) {
- c->data_parse_options |= LYD_PARSE_NO_STATE;
- c->data_validate_options |= LYD_VALIDATE_NO_STATE;
- } else if (!strcasecmp(optarg, "get")) {
- c->data_parse_options |= LYD_PARSE_ONLY;
- } else if (!strcasecmp(optarg, "getconfig") || !strcasecmp(optarg, "get-config")) {
- c->data_parse_options |= LYD_PARSE_ONLY | LYD_PARSE_NO_STATE;
- } else if (!strcasecmp(optarg, "edit")) {
- c->data_parse_options |= LYD_PARSE_ONLY;
- } else if (!strcasecmp(optarg, "rpc")) {
- c->data_type = LYD_TYPE_RPC_YANG;
- } else if (!strcasecmp(optarg, "nc-rpc")) {
- c->data_type = LYD_TYPE_RPC_NETCONF;
- } else if (!strcasecmp(optarg, "reply")) {
- c->data_type = LYD_TYPE_REPLY_YANG;
- } else if (!strcasecmp(optarg, "nc-reply")) {
- c->data_type = LYD_TYPE_REPLY_NETCONF;
- } else if (!strcasecmp(optarg, "notif")) {
- c->data_type = LYD_TYPE_NOTIF_YANG;
- } else if (!strcasecmp(optarg, "nc-notif")) {
- c->data_type = LYD_TYPE_NOTIF_NETCONF;
- } else if (!strcasecmp(optarg, "data")) {
- /* default option */
- } else {
- YLMSG_E("Unknown data tree type %s\n", optarg);
+ if (yl_opt_update_data_type(optarg, yo)) {
+ YLMSG_E("Unknown data tree type %s.", optarg);
help(1);
return -1;
}
@@ -749,184 +590,128 @@ fill_context(int argc, char *argv[], struct context *c)
break;
case 'd': /* --default */
- if (!strcasecmp(optarg, "all")) {
- c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL;
- } else if (!strcasecmp(optarg, "all-tagged")) {
- c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL_TAG;
- } else if (!strcasecmp(optarg, "trim")) {
- c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_TRIM;
- } else if (!strcasecmp(optarg, "implicit-tagged")) {
- c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_IMPL_TAG;
- } else {
- YLMSG_E("Unknown default mode %s\n", optarg);
+ if (yo_opt_update_data_default(optarg, yo)) {
+ YLMSG_E("Unknown default mode %s.", optarg);
help(1);
return -1;
}
break;
+ case 'E': /* --data-xpath */
+ if (ly_set_add(&yo->data_xpath, optarg, 0, NULL)) {
+ YLMSG_E("Storing XPath \"%s\" failed.", optarg);
+ return -1;
+ }
+ break;
+
case 'l': /* --list */
- c->list = 1;
+ yo->list = 1;
break;
case 'L': /* --tree-line-length */
- c->line_length = atoi(optarg);
+ yo->line_length = atoi(optarg);
break;
case 'o': /* --output */
- if (c->out) {
- YLMSG_E("Only a single output can be specified.\n");
+ if (yo->out) {
+ YLMSG_E("Only a single output can be specified.");
return -1;
} else {
- if (ly_out_new_filepath(optarg, &c->out)) {
- YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
+ if (ly_out_new_filepath(optarg, &yo->out)) {
+ YLMSG_E("Unable open output file %s (%s).", optarg, strerror(errno));
return -1;
}
}
break;
case 'O': /* --operational */
- if (c->data_operational.path) {
- YLMSG_E("The operational datastore (-O) cannot be set multiple times.\n");
+ if (yo->data_operational.path) {
+ YLMSG_E("The operational datastore (-O) cannot be set multiple times.");
return -1;
}
- c->data_operational.path = optarg;
+ yo->data_operational.path = optarg;
break;
case 'R': /* --reply-rpc */
- if (c->reply_rpc.path) {
- YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.\n");
+ if (yo->reply_rpc.path) {
+ YLMSG_E("The PRC of the reply (-R) cannot be set multiple times.");
return -1;
}
- c->reply_rpc.path = optarg;
+ yo->reply_rpc.path = optarg;
break;
case 'm': /* --merge */
- c->data_merge = 1;
+ yo->data_merge = 1;
break;
case 'y': /* --yang-library */
- c->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
+ yo->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
break;
case 'Y': /* --yang-library-file */
- c->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
- c->yang_lib_file = optarg;
+ yo->ctx_options &= ~LY_CTX_NO_YANGLIBRARY;
+ yo->yang_lib_file = optarg;
break;
-#ifndef NDEBUG
- case 'G': { /* --debug */
- uint32_t dbg_groups = 0;
- const char *ptr = optarg;
-
- while (ptr[0]) {
- if (!strncasecmp(ptr, "dict", sizeof "dict" - 1)) {
- dbg_groups |= LY_LDGDICT;
- ptr += sizeof "dict" - 1;
- } else if (!strncasecmp(ptr, "xpath", sizeof "xpath" - 1)) {
- dbg_groups |= LY_LDGXPATH;
- ptr += sizeof "xpath" - 1;
- } else if (!strncasecmp(ptr, "dep-sets", sizeof "dep-sets" - 1)) {
- dbg_groups |= LY_LDGDEPSETS;
- ptr += sizeof "dep-sets" - 1;
- }
+ case 'X': /* --extended-leafref */
+ yo->ctx_options |= LY_CTX_LEAFREF_EXTENDED;
+ break;
- if (ptr[0]) {
- if (ptr[0] != ',') {
- YLMSG_E("Unknown debug group string \"%s\"\n", optarg);
- return -1;
- }
- ++ptr;
- }
+#ifndef NDEBUG
+ case 'G': /* --debug */
+ if (set_debug_groups(optarg, yo)) {
+ return -1;
}
- ly_log_dbg_groups(dbg_groups);
break;
- } /* case 'G' */
+ /* case 'G' */
#endif
default:
- YLMSG_E("Invalid option or missing argument: -%c\n", optopt);
+ YLMSG_E("Invalid option or missing argument: -%c.", optopt);
return -1;
} /* switch */
}
/* additional checks for the options combinations */
- if (!c->list && (optind >= argc)) {
+ if (!yo->list && (optind >= argc)) {
help(1);
- YLMSG_E("Missing <schema> to process.\n");
+ YLMSG_E("Missing <schema> to process.");
return 1;
}
- if (c->data_merge) {
- if (c->data_type || (c->data_parse_options & LYD_PARSE_ONLY)) {
- /* switch off the option, incompatible input data type */
- c->data_merge = 0;
- } else {
- /* postpone validation after the merge of all the input data */
- c->data_parse_options |= LYD_PARSE_ONLY;
- }
- }
-
- if (c->data_operational.path && !c->data_type) {
- YLMSG_E("Operational datastore takes effect only with RPCs/Actions/Replies/Notification input data types.\n");
- c->data_operational.path = NULL;
- }
-
- if (c->reply_rpc.path && (c->data_type != LYD_TYPE_REPLY_NETCONF)) {
- YLMSG_E("Source RPC is needed only for NETCONF Reply input data type.\n");
- c->data_operational.path = NULL;
- } else if (!c->reply_rpc.path && (c->data_type == LYD_TYPE_REPLY_NETCONF)) {
- YLMSG_E("Missing source RPC (-R) for NETCONF Reply input data type.\n");
+ if (cmd_data_dep(yo, 0)) {
return -1;
}
-
- if ((c->schema_out_format != LYS_OUT_TREE) && c->line_length) {
- YLMSG_E("--tree-line-length take effect only in case of the tree output format.\n");
+ if (cmd_print_dep(yo, 0)) {
+ return -1;
}
- /* default output stream */
- if (!c->out) {
- if (ly_out_new_file(stdout, &c->out)) {
- YLMSG_E("Unable to set stdout as output.\n");
- return -1;
- }
+ /* Create the libyang context. */
+ if (create_ly_context(yo->yang_lib_file, yo->searchpaths, &yo->schema_features, &yo->ctx_options, ctx)) {
+ return -1;
}
- if (c->schema_out_format == LYS_OUT_TREE) {
- /* print tree from lysc_nodes */
- c->ctx_options |= LY_CTX_SET_PRIV_PARSED;
+ /* Set callback providing run-time extension instance data. */
+ if (yo->schema_context_filename) {
+ ly_ctx_set_ext_data_clb(*ctx, ext_data_clb, yo->schema_context_filename);
}
- /* process input files provided as standalone command line arguments,
- * schema modules are parsed and inserted into the context,
- * data files are just checked and prepared into internal structures for further processing */
- ret = fill_context_inputs(argc, argv, c);
- if (ret) {
- return ret;
+ /* Schema modules and data files are just checked and prepared into internal structures for further processing. */
+ if (fill_context_inputs(argc, argv, optind, yo->data_in_format, *ctx, yo)) {
+ return -1;
}
/* the second batch of checks */
- if (c->schema_print_options && !c->schema_out_format) {
- YLMSG_W("Schema printer options specified, but the schema output format is missing.\n");
+ if (yo->schema_print_options && !yo->schema_out_format) {
+ YLMSG_W("Schema printer options specified, but the schema output format is missing.");
}
- if (c->schema_parse_options && !c->schema_modules.count) {
- YLMSG_W("Schema parser options specified, but no schema input file provided.\n");
+ if (yo->schema_parse_options && !yo->schema_modules.count) {
+ YLMSG_W("Schema parser options specified, but no schema input file provided.");
}
- if (c->data_print_options && !c->data_out_format) {
- YLMSG_W("data printer options specified, but the data output format is missing.\n");
+ if (yo->data_print_options && !yo->data_out_format) {
+ YLMSG_W("data printer options specified, but the data output format is missing.");
}
- if (((c->data_parse_options != YL_DEFAULT_DATA_PARSE_OPTIONS) || c->data_type) && !c->data_inputs.count) {
- YLMSG_W("Data parser options specified, but no data input file provided.\n");
- }
-
- if (c->schema_node_path) {
- c->schema_node = lys_find_path(c->ctx, NULL, c->schema_node_path, 0);
- if (!c->schema_node) {
- c->schema_node = lys_find_path(c->ctx, NULL, c->schema_node_path, 1);
-
- if (!c->schema_node) {
- YLMSG_E("Invalid schema path.\n");
- return -1;
- }
- }
+ if (((yo->data_parse_options != YL_DEFAULT_DATA_PARSE_OPTIONS) || yo->data_type) && !yo->data_inputs.count) {
+ YLMSG_W("Data parser options specified, but no data input file provided.");
}
return 0;
@@ -936,7 +721,8 @@ int
main_ni(int argc, char *argv[])
{
int ret = EXIT_SUCCESS, r;
- struct context c = {0};
+ struct yl_opt yo = {0};
+ struct ly_ctx *ctx = NULL;
char *features_output = NULL;
struct ly_set set = {0};
uint32_t u;
@@ -944,7 +730,7 @@ main_ni(int argc, char *argv[])
/* set callback for printing libyang messages */
ly_set_log_clb(libyang_verbclb, 1);
- r = fill_context(argc, argv, &c);
+ r = fill_context(argc, argv, &yo, &ctx);
if (r < 0) {
ret = EXIT_FAILURE;
}
@@ -954,72 +740,46 @@ main_ni(int argc, char *argv[])
/* do the required job - parse, validate, print */
- if (c.list) {
+ if (yo.list) {
/* print the list of schemas */
- print_list(c.out, c.ctx, c.data_out_format);
- } else {
- if (c.feature_param_format) {
- for (u = 0; u < c.schema_modules.count; u++) {
- if (collect_features(c.schema_modules.objs[u], &set)) {
- YLMSG_E("Unable to read features from a module.\n");
- goto cleanup;
- }
- if (generate_features_output(c.schema_modules.objs[u], &set, &features_output)) {
- YLMSG_E("Unable to generate feature command output.\n");
- goto cleanup;
- }
- ly_set_erase(&set, NULL);
- }
- ly_print(c.out, "%s\n", features_output);
- } else if (c.schema_out_format) {
- if (c.schema_node) {
- ret = lys_print_node(c.out, c.schema_node, c.schema_out_format, 0, c.schema_print_options);
- if (ret) {
- YLMSG_E("Unable to print schema node %s.\n", c.schema_node_path);
- goto cleanup;
- }
- } else if (c.submodule) {
- const struct lysp_submodule *submod = ly_ctx_get_submodule_latest(c.ctx, c.submodule);
-
- if (!submod) {
- YLMSG_E("Unable to find submodule %s.\n", c.submodule);
- goto cleanup;
- }
-
- ret = lys_print_submodule(c.out, submod, c.schema_out_format, c.line_length, c.schema_print_options);
- if (ret) {
- YLMSG_E("Unable to print submodule %s.\n", submod->name);
- goto cleanup;
- }
- } else {
- for (u = 0; u < c.schema_modules.count; ++u) {
- ret = lys_print_module(c.out, (struct lys_module *)c.schema_modules.objs[u], c.schema_out_format,
- c.line_length, c.schema_print_options);
- /* for YANG Tree Diagrams printing it's more readable to print a blank line between modules. */
- if ((c.schema_out_format == LYS_OUT_TREE) && (u + 1 < c.schema_modules.count)) {
- ly_print(c.out, "\n");
- }
- if (ret) {
- YLMSG_E("Unable to print module %s.\n", ((struct lys_module *)c.schema_modules.objs[u])->name);
- goto cleanup;
- }
- }
+ ret = cmd_list_exec(&ctx, &yo, NULL);
+ goto cleanup;
+ }
+ if (yo.feature_param_format) {
+ for (u = 0; u < yo.schema_modules.count; u++) {
+ if ((ret = cmd_feature_exec(&ctx, &yo, ((struct lys_module *)yo.schema_modules.objs[u])->name))) {
+ goto cleanup;
}
}
-
- /* do the data validation despite the schema was printed */
- if (c.data_inputs.size) {
- ret = process_data(c.ctx, c.data_type, c.data_merge, c.data_out_format, c.out, c.data_parse_options,
- c.data_validate_options, c.data_print_options, &c.data_operational, &c.reply_rpc, &c.data_inputs, NULL);
- if (ret) {
+ cmd_feature_fin(ctx, &yo);
+ } else if (yo.schema_out_format && yo.schema_node_path) {
+ if ((ret = cmd_print_exec(&ctx, &yo, NULL))) {
+ goto cleanup;
+ }
+ } else if (yo.schema_out_format && yo.submodule) {
+ if ((ret = cmd_print_exec(&ctx, &yo, yo.submodule))) {
+ goto cleanup;
+ }
+ } else if (yo.schema_out_format) {
+ for (u = 0; u < yo.schema_modules.count; ++u) {
+ yo.last_one = (u + 1) == yo.schema_modules.count;
+ if ((ret = cmd_print_exec(&ctx, &yo, ((struct lys_module *)yo.schema_modules.objs[u])->name))) {
goto cleanup;
}
}
}
+ /* do the data validation despite the schema was printed */
+ if (yo.data_inputs.size) {
+ if ((ret = cmd_data_process(ctx, &yo))) {
+ goto cleanup;
+ }
+ }
+
cleanup:
/* cleanup */
- erase_context(&c);
+ yl_opt_erase(&yo);
+ ly_ctx_destroy(ctx);
free(features_output);
ly_set_erase(&set, NULL);