yanglint FEATURE initial version of yanglint(1)
Source codes are mostly taken from libyang 1.0 and slightly modified for
libyang 2.0. A lot of functionality is still missing since it is not yet
provided by libyang 2.0
diff --git a/tools/lint/commands.c b/tools/lint/commands.c
new file mode 100644
index 0000000..0e7913a
--- /dev/null
+++ b/tools/lint/commands.c
@@ -0,0 +1,1551 @@
+/**
+ * @file commands.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool commands
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <libgen.h>
+
+#include "commands.h"
+#include "libyang.h"
+
+COMMAND commands[];
+extern int done;
+extern struct ly_ctx *ctx;
+
+void
+cmd_add_help(void)
+{
+ printf("add [-i] <path-to-model> [<paths-to-other-models> ...]\n");
+ printf("\t-i - make all the imported modules implemented\n");
+}
+
+void
+cmd_load_help(void)
+{
+ printf("load [-i] <model-name> [<other-model-names> ...]\n");
+ printf("\t-i - make all the imported modules implemented\n");
+}
+
+void
+cmd_clear_help(void)
+{
+ printf("clear [<yang-library> | -e]\n");
+ printf("\t Replace the current context with an empty one, searchpaths are not kept.\n");
+ printf("\t If <yang-library> path specified, load the modules according to the yang library data.\n");
+ printf("\t Option '-e' causes ietf-yang-library will not be loaded.\n");
+}
+
+void
+cmd_print_help(void)
+{
+ printf("print [-f (yang | yin | tree [<tree-options>] | info [-P <info-path>] | jsons)] [-o <output-file>]"
+ " <model-name>[@<revision>]\n");
+ printf("\n");
+ printf("\ttree-options:\t--tree-print-groupings\t(print top-level groupings in a separate section)\n");
+ printf("\t \t--tree-print-uses\t(print uses nodes instead the resolved grouping nodes)\n");
+ printf("\t \t--tree-no-leafref-target\t(do not print the target nodes of leafrefs)\n");
+ printf("\t \t--tree-path <schema-path>\t(print only the specified subtree)\n");
+ printf("\t \t--tree-line-length <line-length>\t(wrap lines if longer than line-length,\n");
+ printf("\t \t\tnot a strict limit, longer lines can often appear)\n");
+ printf("\n");
+ printf("\tinfo-path:\t<schema-path> | typedef[<schema-path>]/<typedef-name> |\n");
+ printf("\t \t| identity/<identity-name> | feature/<feature-name> |\n");
+ printf("\t \t| grouping[<schema-path>]/<grouping-name> |\n");
+ printf("\t \t| type/<schema-path-leaf-or-leaflist>\n");
+ printf("\n");
+ printf("\tschema-path:\t( /<module-name>:<node-identifier> )+\n");
+}
+
+void
+cmd_data_help(void)
+{
+ printf("data [-(-s)trict] [-t TYPE] [-d DEFAULTS] [-o <output-file>] [-f (xml | json | lyb)] [-r <running-file-name>]\n");
+ printf(" <data-file-name> [<RPC/action-data-file-name> | <yang-data name>]\n\n");
+ printf("Accepted TYPEs:\n");
+ printf("\tauto - resolve data type (one of the following) automatically (as pyang does),\n");
+ printf("\t this option is applicable only in case of XML input data.\n");
+ printf("\tdata - LYD_OPT_DATA (default value) - complete datastore including status data.\n");
+ printf("\tconfig - LYD_OPT_CONFIG - complete configuration datastore.\n");
+ printf("\tget - LYD_OPT_GET - <get> operation result.\n");
+ printf("\tgetconfig - LYD_OPT_GETCONFIG - <get-config> operation result.\n");
+ printf("\tedit - LYD_OPT_EDIT - <edit-config>'s data (content of its <config> element).\n");
+ printf("\trpc - LYD_OPT_RPC - NETCONF RPC message.\n");
+ printf("\trpcreply - LYD_OPT_RPCREPLY (last parameter mandatory in this case)\n");
+ printf("\tnotif - LYD_OPT_NOTIF - NETCONF Notification message.\n");
+ printf("\tyangdata - LYD_OPT_DATA_TEMPLATE - yang-data extension (last parameter mandatory in this case)\n\n");
+ printf("Accepted DEFAULTS:\n");
+ printf("\tall - add missing default nodes\n");
+ printf("\tall-tagged - add missing default nodes and mark all the default nodes with the attribute.\n");
+ printf("\ttrim - remove all nodes with a default value\n");
+ printf("\timplicit-tagged - add missing nodes and mark them with the attribute\n\n");
+ printf("Option -r:\n");
+ printf("\tOptional parameter for 'rpc', 'rpcreply' and 'notif' TYPEs, the file contains running\n");
+ printf("\tconfiguration datastore data referenced from the RPC/Notification. Note that the file is\n");
+ printf("\tvalidated as 'data' TYPE. Special value '!' can be used as argument to ignore the\n");
+ printf("\texternal references.\n\n");
+ printf("\tIf an XPath expression (when/must) needs access to configuration data, you can provide\n");
+ printf("\tthem in a file, which will be parsed as 'data' TYPE.\n\n");
+}
+
+void
+cmd_xpath_help(void)
+{
+ printf("xpath [-t TYPE] [-x <additional-tree-file-name>] -e <XPath-expression>\n"
+ " <XML-data-file-name> [<JSON-rpc/action-schema-nodeid>]\n");
+ printf("Accepted TYPEs:\n");
+ printf("\tauto - resolve data type (one of the following) automatically (as pyang does),\n");
+ printf("\t this option is applicable only in case of XML input data.\n");
+ printf("\tconfig - LYD_OPT_CONFIG\n");
+ printf("\tget - LYD_OPT_GET\n");
+ printf("\tgetconfig - LYD_OPT_GETCONFIG\n");
+ printf("\tedit - LYD_OPT_EDIT\n");
+ printf("\trpc - LYD_OPT_RPC\n");
+ printf("\trpcreply - LYD_OPT_RPCREPLY (last parameter mandatory in this case)\n");
+ printf("\tnotif - LYD_OPT_NOTIF\n\n");
+ printf("Option -x:\n");
+ printf("\tIf RPC/action/notification/RPC reply (for TYPEs 'rpc', 'rpcreply', and 'notif') includes\n");
+ printf("\tan XPath expression (when/must) that needs access to the configuration data, you can provide\n");
+ printf("\tthem in a file, which will be parsed as 'config'.\n");
+}
+
+void
+cmd_list_help(void)
+{
+ printf("list [-f (xml | json)]\n\n");
+ printf("\tBasic list output (no -f): i - imported module, I - implemented module\n");
+}
+
+void
+cmd_feature_help(void)
+{
+ printf("feature [ -(-e)nable | -(-d)isable (* | <feature-name>[,<feature-name> ...]) ] <model-name>[@<revision>]\n");
+}
+
+void
+cmd_searchpath_help(void)
+{
+ printf("searchpath [<model-dir-path> | --clear]\n\n");
+ printf("\tThey are used to search for imports and includes of a model.\n");
+ printf("\tThe \"load\" command uses these directories to find models directly.\n");
+}
+
+void
+cmd_verb_help(void)
+{
+ printf("verb (error/0 | warning/1 | verbose/2 | debug/3)\n");
+}
+
+#ifndef NDEBUG
+
+void
+cmd_debug_help(void)
+{
+ printf("debug (dict | yang | yin | xpath | diff)+\n");
+}
+
+#endif
+
+LYS_INFORMAT
+get_schema_format(const char *path)
+{
+ char *ptr;
+
+ if ((ptr = strrchr(path, '.')) != NULL) {
+ ++ptr;
+ if (!strcmp(ptr, "yang")) {
+ return LYS_IN_YANG;
+ /* TODO YIN parser not yet implemented
+ } else if (!strcmp(ptr, "yin")) {
+ return LYS_IN_YIN;
+ */
+ } else {
+ fprintf(stderr, "Input file in an unknown format \"%s\".\n", ptr);
+ return LYS_IN_UNKNOWN;
+ }
+ } else {
+ fprintf(stdout, "Input file \"%s\" without extension - unknown format.\n", path);
+ return LYS_IN_UNKNOWN;
+ }
+}
+
+int
+cmd_add(const char *arg)
+{
+ int path_len, ret = 1, index = 0;
+ char *path, *dir, *s, *arg_ptr;
+ const char * const *searchpaths;
+ const struct lys_module *model;
+ LYS_INFORMAT format = LYS_IN_UNKNOWN;
+
+ if (strlen(arg) < 5) {
+ cmd_add_help();
+ return 1;
+ }
+
+ arg_ptr = strdup(arg + 3 /* ignore "add" */);
+
+ for (s = strstr(arg_ptr, "-i"); s ; s = strstr(s + 2, "-i")) {
+ if (s[2] == '\0' || s[2] == ' ') {
+ ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
+ s[0] = s[1] = ' ';
+ }
+ }
+ s = arg_ptr;
+
+ while (arg_ptr[0] == ' ') {
+ ++arg_ptr;
+ }
+ if (strchr(arg_ptr, ' ')) {
+ path_len = strchr(arg_ptr, ' ') - arg_ptr;
+ } else {
+ path_len = strlen(arg_ptr);
+ }
+ path = strndup(arg_ptr, path_len);
+
+ searchpaths = ly_ctx_get_searchdirs(ctx);
+ if (searchpaths) {
+ for (index = 0; searchpaths[index]; index++);
+ }
+
+ while (path) {
+ format = get_schema_format(path);
+ if (format == LYS_IN_UNKNOWN) {
+ free(path);
+ goto cleanup;
+ }
+
+ dir = strdup(path);
+ ly_ctx_set_searchdir(ctx, dirname(dir));
+ model = lys_parse_path(ctx, path, format);
+ ly_ctx_unset_searchdir(ctx, index);
+ free(path);
+ free(dir);
+
+ if (!model) {
+ /* libyang printed the error messages */
+ goto cleanup;
+ }
+
+ /* next model */
+ arg_ptr += path_len;
+ while (arg_ptr[0] == ' ') {
+ ++arg_ptr;
+ }
+ if (strchr(arg_ptr, ' ')) {
+ path_len = strchr(arg_ptr, ' ') - arg_ptr;
+ } else {
+ path_len = strlen(arg_ptr);
+ }
+
+ if (path_len) {
+ path = strndup(arg_ptr, path_len);
+ } else {
+ path = NULL;
+ }
+ }
+ if (format == LYS_IN_UNKNOWN) {
+ /* no schema on input */
+ cmd_add_help();
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ free(s);
+ ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
+
+ return ret;
+}
+
+int
+cmd_load(const char *arg)
+{
+ int name_len, ret = 1;
+ char *name, *s, *arg_ptr;
+ const struct lys_module *model;
+
+ if (strlen(arg) < 6) {
+ cmd_load_help();
+ return 1;
+ }
+
+ arg_ptr = strdup(arg + 4 /* ignore "load" */);
+
+ for (s = strstr(arg_ptr, "-i"); s ; s = strstr(s + 2, "-i")) {
+ if (s[2] == '\0' || s[2] == ' ') {
+ ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
+ s[0] = s[1] = ' ';
+ }
+ }
+ s = arg_ptr;
+
+ while (arg_ptr[0] == ' ') {
+ ++arg_ptr;
+ }
+ if (strchr(arg_ptr, ' ')) {
+ name_len = strchr(arg_ptr, ' ') - arg_ptr;
+ } else {
+ name_len = strlen(arg_ptr);
+ }
+ name = strndup(arg_ptr, name_len);
+
+ while (name) {
+ model = ly_ctx_load_module(ctx, name, NULL);
+ free(name);
+ if (!model) {
+ /* libyang printed the error messages */
+ goto cleanup;
+ }
+
+ /* next model */
+ arg_ptr += name_len;
+ while (arg_ptr[0] == ' ') {
+ ++arg_ptr;
+ }
+ if (strchr(arg_ptr, ' ')) {
+ name_len = strchr(arg_ptr, ' ') - arg_ptr;
+ } else {
+ name_len = strlen(arg_ptr);
+ }
+
+ if (name_len) {
+ name = strndup(arg_ptr, name_len);
+ } else {
+ name = NULL;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ free(s);
+ ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
+
+ return ret;
+}
+
+int
+cmd_print(const char *arg)
+{
+ int c, argc, option_index, ret = 1, tree_ll = 0, tree_opts = 0;
+ char **argv = NULL, *ptr, *model_name, *revision;
+ const char *out_path = NULL;
+ const struct lys_module *module;
+ LYS_OUTFORMAT format = LYS_OUT_TREE;
+ FILE *output = stdout;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {"output", required_argument, 0, 'o'},
+#if 0
+ {"tree-print-groupings", no_argument, 0, 'g'},
+ {"tree-print-uses", no_argument, 0, 'u'},
+ {"tree-no-leafref-target", no_argument, 0, 'n'},
+ {"tree-path", required_argument, 0, 'P'},
+ {"info-path", required_argument, 0, 'P'},
+ {"tree-line-length", required_argument, 0, 'L'},
+#endif
+ {NULL, 0, 0, 0}
+ };
+ void *rlcd;
+
+ argc = 1;
+ argv = malloc(2*sizeof *argv);
+ *argv = strdup(arg);
+ ptr = strtok(*argv, " ");
+ while ((ptr = strtok(NULL, " "))) {
+ rlcd = realloc(argv, (argc+2)*sizeof *argv);
+ if (!rlcd) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto cleanup;
+ }
+ argv = rlcd;
+ argv[argc++] = ptr;
+ }
+ argv[argc] = NULL;
+
+ optind = 0;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "hf:go:guP:L:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ cmd_print_help();
+ ret = 0;
+ goto cleanup;
+ case 'f':
+ if (!strcmp(optarg, "yang")) {
+ format = LYS_OUT_YANG;
+#if 0
+ } else if (!strcmp(optarg, "yin")) {
+ format = LYS_OUT_YIN;
+ } else if (!strcmp(optarg, "tree")) {
+ format = LYS_OUT_TREE;
+ } else if (!strcmp(optarg, "tree-rfc")) {
+ format = LYS_OUT_TREE;
+ tree_opts |= LYS_OUTOPT_TREE_RFC;
+ } else if (!strcmp(optarg, "info")) {
+ format = LYS_OUT_INFO;
+ } else if (!strcmp(optarg, "jsons")) {
+ format = LYS_OUT_JSON;
+#endif
+ } else {
+ fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+ goto cleanup;
+ }
+ break;
+ case 'o':
+ if (out_path) {
+ fprintf(stderr, "Output specified twice.\n");
+ goto cleanup;
+ }
+ out_path = optarg;
+ break;
+#if 0
+ case 'g':
+ tree_opts |= LYS_OUTOPT_TREE_GROUPING;
+ break;
+ case 'u':
+ tree_opts |= LYS_OUTOPT_TREE_USES;
+ break;
+ case 'n':
+ tree_opts |= LYS_OUTOPT_TREE_NO_LEAFREF;
+ break;
+ case 'P':
+ target_path = optarg;
+ break;
+ case 'L':
+ tree_ll = atoi(optarg);
+ break;
+#endif
+ case '?':
+ fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+ goto cleanup;
+ }
+ }
+
+ /* file name */
+ if (optind == argc) {
+ fprintf(stderr, "Missing the module name.\n");
+ goto cleanup;
+ }
+
+ /* tree fromat with or without gropings */
+ if ((tree_opts || tree_ll) && format != LYS_OUT_TREE) {
+ fprintf(stderr, "--tree options take effect only in case of the tree output format.\n");
+ }
+
+ /* module, revision */
+ model_name = argv[optind];
+ revision = NULL;
+ if (strchr(model_name, '@')) {
+ revision = strchr(model_name, '@');
+ revision[0] = '\0';
+ ++revision;
+ }
+
+ if (revision) {
+ module = ly_ctx_get_module(ctx, model_name, revision);
+ } else {
+ module = ly_ctx_get_module_latest(ctx, model_name);
+ }
+#if 0
+ if (!module) {
+ /* not a module, try to find it as a submodule */
+ module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
+ }
+#endif
+
+ if (!module) {
+ if (revision) {
+ fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
+ } else {
+ fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
+ }
+ goto cleanup;
+ }
+
+ if (out_path) {
+ output = fopen(out_path, "w");
+ if (!output) {
+ fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
+ goto cleanup;
+ }
+ }
+
+ ret = lys_print_file(output, module, format, tree_ll, tree_opts);
+ if (format == LYS_OUT_JSON) {
+ fputs("\n", output);
+ }
+
+cleanup:
+ free(*argv);
+ free(argv);
+
+ if (output && (output != stdout)) {
+ fclose(output);
+ }
+
+ return ret;
+}
+#if 0
+static LYD_FORMAT
+detect_data_format(char *filepath)
+{
+ size_t len;
+
+ /* detect input format according to file suffix */
+ len = strlen(filepath);
+ for (; isspace(filepath[len - 1]); len--, filepath[len] = '\0'); /* remove trailing whitespaces */
+ if (len >= 5 && !strcmp(&filepath[len - 4], ".xml")) {
+ return LYD_XML;
+ } else if (len >= 6 && !strcmp(&filepath[len - 5], ".json")) {
+ return LYD_JSON;
+ } else if (len >= 5 && !strcmp(&filepath[len - 4], ".lyb")) {
+ return LYD_LYB;
+ } else {
+ return LYD_UNKNOWN;
+ }
+}
+
+static int
+parse_data(char *filepath, int *options, struct lyd_node *val_tree, const char *rpc_act_file,
+ struct lyd_node **result)
+{
+ LYD_FORMAT informat = LYD_UNKNOWN;
+ struct lyxml_elem *xml = NULL;
+ struct lyd_node *data = NULL, *rpc_act = NULL;
+ int opts = *options;
+
+ /* detect input format according to file suffix */
+ informat = detect_data_format(filepath);
+ if (informat == LYD_UNKNOWN) {
+ fprintf(stderr, "Unable to resolve format of the input file, please add \".xml\", \".json\", or \".lyb\" suffix.\n");
+ return EXIT_FAILURE;
+ }
+
+ ly_errno = LY_SUCCESS;
+
+ if ((opts & LYD_OPT_TYPEMASK) == LYD_OPT_TYPEMASK) {
+ /* automatically detect data type from the data top level */
+ if (informat != LYD_XML) {
+ fprintf(stderr, "Only XML data can be automatically explored.\n");
+ return EXIT_FAILURE;
+ }
+
+ xml = lyxml_parse_path(ctx, filepath, 0);
+ if (!xml) {
+ fprintf(stderr, "Failed to parse XML data for automatic type detection.\n");
+ return EXIT_FAILURE;
+ }
+
+ /* NOTE: namespace is ignored to simplify usage of this feature */
+
+ if (!strcmp(xml->name, "data")) {
+ fprintf(stdout, "Parsing %s as complete datastore.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_ADD_YANGLIB;
+ } else if (!strcmp(xml->name, "config")) {
+ fprintf(stdout, "Parsing %s as config data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+ } else if (!strcmp(xml->name, "get-reply")) {
+ fprintf(stdout, "Parsing %s as <get> reply data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+ } else if (!strcmp(xml->name, "get-config-reply")) {
+ fprintf(stdout, "Parsing %s as <get-config> reply data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+ } else if (!strcmp(xml->name, "edit-config")) {
+ fprintf(stdout, "Parsing %s as <edit-config> data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+ } else if (!strcmp(xml->name, "rpc")) {
+ fprintf(stdout, "Parsing %s as <rpc> data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+ } else if (!strcmp(xml->name, "rpc-reply")) {
+ if (!rpc_act_file) {
+ fprintf(stderr, "RPC/action reply data require additional argument (file with the RPC/action).\n");
+ lyxml_free(ctx, xml);
+ return EXIT_FAILURE;
+ }
+ fprintf(stdout, "Parsing %s as <rpc-reply> data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+ rpc_act = lyd_parse_path(ctx, rpc_act_file, informat, LYD_OPT_RPC, val_tree);
+ if (!rpc_act) {
+ fprintf(stderr, "Failed to parse RPC/action.\n");
+ lyxml_free(ctx, xml);
+ return EXIT_FAILURE;
+ }
+ } else if (!strcmp(xml->name, "notification")) {
+ fprintf(stdout, "Parsing %s as <notification> data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+ } else if (!strcmp(xml->name, "yang-data")) {
+ fprintf(stdout, "Parsing %s as <yang-data> data.\n", filepath);
+ opts = (opts & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+ if (!rpc_act_file) {
+ fprintf(stderr, "YANG-DATA require additional argument (name instance of yang-data extension).\n");
+ lyxml_free(ctx, xml);
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "Invalid top-level element for automatic data type recognition.\n");
+ lyxml_free(ctx, xml);
+ return EXIT_FAILURE;
+ }
+
+ if (opts & LYD_OPT_RPCREPLY) {
+ data = lyd_parse_xml(ctx, &xml->child, opts, rpc_act, val_tree);
+ } else if (opts & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
+ data = lyd_parse_xml(ctx, &xml->child, opts, val_tree);
+ } else if (opts & LYD_OPT_DATA_TEMPLATE) {
+ data = lyd_parse_xml(ctx, &xml->child, opts, rpc_act_file);
+ } else {
+ data = lyd_parse_xml(ctx, &xml->child, opts);
+ }
+ lyxml_free(ctx, xml);
+ } else {
+ if (opts & LYD_OPT_RPCREPLY) {
+ if (!rpc_act_file) {
+ fprintf(stderr, "RPC/action reply data require additional argument (file with the RPC/action).\n");
+ return EXIT_FAILURE;
+ }
+ rpc_act = lyd_parse_path(ctx, rpc_act_file, informat, LYD_OPT_RPC, val_tree);
+ if (!rpc_act) {
+ fprintf(stderr, "Failed to parse RPC/action.\n");
+ return EXIT_FAILURE;
+ }
+ data = lyd_parse_path(ctx, filepath, informat, opts, rpc_act, val_tree);
+ } else if (opts & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
+ data = lyd_parse_path(ctx, filepath, informat, opts, val_tree);
+ } else if (opts & LYD_OPT_DATA_TEMPLATE) {
+ if (!rpc_act_file) {
+ fprintf(stderr, "YANG-DATA require additional argument (name instance of yang-data extension).\n");
+ return EXIT_FAILURE;
+ }
+ data = lyd_parse_path(ctx, filepath, informat, opts, rpc_act_file);
+ } else {
+ if (!(opts & LYD_OPT_TYPEMASK)) {
+ /* automatically add yang-library data */
+ opts |= LYD_OPT_DATA_ADD_YANGLIB;
+ }
+ data = lyd_parse_path(ctx, filepath, informat, opts);
+ }
+ }
+ lyd_free_withsiblings(rpc_act);
+
+ if (ly_errno) {
+ fprintf(stderr, "Failed to parse data.\n");
+ lyd_free_withsiblings(data);
+ return EXIT_FAILURE;
+ }
+
+ *result = data;
+ *options = opts;
+ return EXIT_SUCCESS;
+}
+
+int
+cmd_data(const char *arg)
+{
+ int c, argc, option_index, ret = 1;
+ int options = 0, printopt = 0;
+ char **argv = NULL, *ptr;
+ const char *out_path = NULL;
+ struct lyd_node *data = NULL, *val_tree = NULL;
+ LYD_FORMAT outformat = LYD_UNKNOWN;
+ FILE *output = stdout;
+ static struct option long_options[] = {
+ {"defaults", required_argument, 0, 'd'},
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {"option", required_argument, 0, 't'},
+ {"output", required_argument, 0, 'o'},
+ {"running", required_argument, 0, 'r'},
+ {"strict", no_argument, 0, 's'},
+ {NULL, 0, 0, 0}
+ };
+ void *rlcd;
+
+ argc = 1;
+ argv = malloc(2*sizeof *argv);
+ *argv = strdup(arg);
+ ptr = strtok(*argv, " ");
+ while ((ptr = strtok(NULL, " "))) {
+ rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+ if (!rlcd) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto cleanup;
+ }
+ argv = rlcd;
+ argv[argc++] = ptr;
+ }
+ argv[argc] = NULL;
+
+ optind = 0;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "d:hf:o:st:r:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'd':
+ if (!strcmp(optarg, "all")) {
+ printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL;
+ } else if (!strcmp(optarg, "all-tagged")) {
+ printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_ALL_TAG;
+ } else if (!strcmp(optarg, "trim")) {
+ printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_TRIM;
+ } else if (!strcmp(optarg, "implicit-tagged")) {
+ printopt = (printopt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
+ }
+ break;
+ case 'h':
+ cmd_data_help();
+ ret = 0;
+ goto cleanup;
+ case 'f':
+ if (!strcmp(optarg, "xml")) {
+ outformat = LYD_XML;
+ } else if (!strcmp(optarg, "json")) {
+ outformat = LYD_JSON;
+ } else if (!strcmp(optarg, "lyb")) {
+ outformat = LYD_LYB;
+ } else {
+ fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+ goto cleanup;
+ }
+ break;
+ case 'o':
+ if (out_path) {
+ fprintf(stderr, "Output specified twice.\n");
+ goto cleanup;
+ }
+ out_path = optarg;
+ break;
+ case 'r':
+ if (val_tree || (options & LYD_OPT_NOEXTDEPS)) {
+ fprintf(stderr, "The running datastore (-r) cannot be set multiple times.\n");
+ goto cleanup;
+ }
+ if (optarg[0] == '!') {
+ /* ignore extenral dependencies to the running datastore */
+ options |= LYD_OPT_NOEXTDEPS;
+ } else {
+ /* external file with the running datastore */
+ val_tree = lyd_parse_path(ctx, optarg, LYD_XML, LYD_OPT_DATA_NO_YANGLIB);
+ if (!val_tree) {
+ fprintf(stderr, "Failed to parse the additional data tree for validation.\n");
+ goto cleanup;
+ }
+ }
+ break;
+ case 's':
+ options |= LYD_OPT_STRICT;
+ options |= LYD_OPT_OBSOLETE;
+ break;
+ case 't':
+ if (!strcmp(optarg, "auto")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_TYPEMASK;
+ } else if (!strcmp(optarg, "data")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA;
+ } else if (!strcmp(optarg, "config")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+ } else if (!strcmp(optarg, "get")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+ } else if (!strcmp(optarg, "getconfig")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+ } else if (!strcmp(optarg, "edit")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+ } else if (!strcmp(optarg, "rpc")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+ } else if (!strcmp(optarg, "rpcreply")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+ } else if (!strcmp(optarg, "notif")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+ } else if (!strcmp(optarg, "yangdata")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+ } else {
+ fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
+ cmd_data_help();
+ goto cleanup;
+ }
+ break;
+ case '?':
+ fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+ goto cleanup;
+ }
+ }
+
+ /* file name */
+ if (optind == argc) {
+ fprintf(stderr, "Missing the data file name.\n");
+ goto cleanup;
+ }
+
+ if (parse_data(argv[optind], &options, val_tree, argv[optind + 1], &data)) {
+ goto cleanup;
+ }
+
+ if (out_path) {
+ output = fopen(out_path, "w");
+ if (!output) {
+ fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
+ goto cleanup;
+ }
+ }
+
+ if (outformat != LYD_UNKNOWN) {
+ if (options & LYD_OPT_RPCREPLY) {
+ lyd_print_file(output, data->child, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+ } else {
+ lyd_print_file(output, data, outformat, LYP_WITHSIBLINGS | LYP_FORMAT | printopt);
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ free(*argv);
+ free(argv);
+
+ if (output && (output != stdout)) {
+ fclose(output);
+ }
+
+ lyd_free_withsiblings(val_tree);
+ lyd_free_withsiblings(data);
+
+ return ret;
+}
+
+int
+cmd_xpath(const char *arg)
+{
+ int c, argc, option_index, ret = 1, long_str;
+ char **argv = NULL, *ptr, *expr = NULL;
+ unsigned int i, j;
+ int options = 0;
+ struct lyd_node *data = NULL, *node, *val_tree = NULL;
+ struct lyd_node_leaf_list *key;
+ struct ly_set *set;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"expr", required_argument, 0, 'e'},
+ {NULL, 0, 0, 0}
+ };
+ void *rlcd;
+
+ long_str = 0;
+ argc = 1;
+ argv = malloc(2 * sizeof *argv);
+ *argv = strdup(arg);
+ ptr = strtok(*argv, " ");
+ while ((ptr = strtok(NULL, " "))) {
+ if (long_str) {
+ ptr[-1] = ' ';
+ if (ptr[strlen(ptr) - 1] == long_str) {
+ long_str = 0;
+ ptr[strlen(ptr) - 1] = '\0';
+ }
+ } else {
+ rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+ if (!rlcd) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto cleanup;
+ }
+ argv = rlcd;
+ argv[argc] = ptr;
+ if (ptr[0] == '"') {
+ long_str = '"';
+ ++argv[argc];
+ }
+ if (ptr[0] == '\'') {
+ long_str = '\'';
+ ++argv[argc];
+ }
+ if (ptr[strlen(ptr) - 1] == long_str) {
+ long_str = 0;
+ ptr[strlen(ptr) - 1] = '\0';
+ }
+ ++argc;
+ }
+ }
+ argv[argc] = NULL;
+
+ optind = 0;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "he:t:x:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ cmd_xpath_help();
+ ret = 0;
+ goto cleanup;
+ case 'e':
+ expr = optarg;
+ break;
+ case 't':
+ if (!strcmp(optarg, "auto")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_TYPEMASK;
+ } else if (!strcmp(optarg, "config")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+ } else if (!strcmp(optarg, "get")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+ } else if (!strcmp(optarg, "getconfig")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+ } else if (!strcmp(optarg, "edit")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+ } else if (!strcmp(optarg, "rpc")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+ } else if (!strcmp(optarg, "rpcreply")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+ } else if (!strcmp(optarg, "notif")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+ } else if (!strcmp(optarg, "yangdata")) {
+ options = (options & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_TEMPLATE;
+ } else {
+ fprintf(stderr, "Invalid parser option \"%s\".\n", optarg);
+ cmd_data_help();
+ goto cleanup;
+ }
+ break;
+ case 'x':
+ val_tree = lyd_parse_path(ctx, optarg, LYD_XML, LYD_OPT_CONFIG);
+ if (!val_tree) {
+ fprintf(stderr, "Failed to parse the additional data tree for validation.\n");
+ goto cleanup;
+ }
+ break;
+ case '?':
+ fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+ goto cleanup;
+ }
+ }
+
+ if (optind == argc) {
+ fprintf(stderr, "Missing the file with data.\n");
+ goto cleanup;
+ }
+
+ if (!expr) {
+ fprintf(stderr, "Missing the XPath expression.\n");
+ goto cleanup;
+ }
+
+ if (parse_data(argv[optind], &options, val_tree, argv[optind + 1], &data)) {
+ goto cleanup;
+ }
+
+ if (!(set = lyd_find_path(data, expr))) {
+ goto cleanup;
+ }
+
+ /* print result */
+ printf("Result:\n");
+ if (!set->number) {
+ printf("\tEmpty\n");
+ } else {
+ for (i = 0; i < set->number; ++i) {
+ node = set->set.d[i];
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ printf("\tContainer ");
+ break;
+ case LYS_LEAF:
+ printf("\tLeaf ");
+ break;
+ case LYS_LEAFLIST:
+ printf("\tLeaflist ");
+ break;
+ case LYS_LIST:
+ printf("\tList ");
+ break;
+ case LYS_ANYXML:
+ printf("\tAnyxml ");
+ break;
+ case LYS_ANYDATA:
+ printf("\tAnydata ");
+ break;
+ default:
+ printf("\tUnknown ");
+ break;
+ }
+ printf("\"%s\"", node->schema->name);
+ if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+ printf(" (val: %s)", ((struct lyd_node_leaf_list *)node)->value_str);
+ } else if (node->schema->nodetype == LYS_LIST) {
+ key = (struct lyd_node_leaf_list *)node->child;
+ printf(" (");
+ for (j = 0; j < ((struct lys_node_list *)node->schema)->keys_size; ++j) {
+ if (j) {
+ printf(" ");
+ }
+ printf("\"%s\": %s", key->schema->name, key->value_str);
+ key = (struct lyd_node_leaf_list *)key->next;
+ }
+ printf(")");
+ }
+ printf("\n");
+ }
+ }
+ printf("\n");
+
+ ly_set_free(set);
+ ret = 0;
+
+cleanup:
+ free(*argv);
+ free(argv);
+
+ lyd_free_withsiblings(data);
+
+ return ret;
+}
+
+int
+print_list(FILE *out, struct ly_ctx *ctx, LYD_FORMAT outformat)
+{
+ struct lyd_node *ylib;
+ uint32_t idx = 0, has_modules = 0;
+ uint8_t u;
+ const struct lys_module *mod;
+
+ if (outformat != LYD_UNKNOWN) {
+ ylib = ly_ctx_info(ctx);
+ if (!ylib) {
+ fprintf(stderr, "Getting context info (ietf-yang-library data) failed.\n");
+ return 1;
+ }
+
+ lyd_print_file(out, ylib, outformat, LYP_WITHSIBLINGS | LYP_FORMAT);
+ lyd_free_withsiblings(ylib);
+ return 0;
+ }
+
+ /* iterate schemas in context and provide just the basic info */
+ fprintf(out, "List of the loaded models:\n");
+ while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
+ has_modules++;
+
+ /* conformance print */
+ if (mod->implemented) {
+ fprintf(out, "\tI");
+ } else {
+ fprintf(out, "\ti");
+ }
+
+ /* module print */
+ fprintf(out, " %s", mod->name);
+ if (mod->rev_size) {
+ fprintf(out, "@%s", mod->rev[0].date);
+ }
+
+ /* submodules print */
+ if (mod->inc_size) {
+ fprintf(out, " (");
+ for (u = 0; u < mod->inc_size; u++) {
+ fprintf(out, "%s%s", !u ? "" : ",", mod->inc[u].submodule->name);
+ if (mod->inc[u].submodule->rev_size) {
+ fprintf(out, "@%s", mod->inc[u].submodule->rev[0].date);
+ }
+ }
+ fprintf(out, ")");
+ }
+
+ /* finish the line */
+ fprintf(out, "\n");
+ }
+
+ if (!has_modules) {
+ fprintf(out, "\t(none)\n");
+ }
+
+ return 0;
+}
+
+int
+cmd_list(const char *arg)
+{
+ char **argv = NULL, *ptr;
+ int c, argc, option_index;
+ LYD_FORMAT outformat = LYD_UNKNOWN;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"format", required_argument, 0, 'f'},
+ {NULL, 0, 0, 0}
+ };
+ void *rlcd;
+
+ argc = 1;
+ argv = malloc(2*sizeof *argv);
+ *argv = strdup(arg);
+ ptr = strtok(*argv, " ");
+ while ((ptr = strtok(NULL, " "))) {
+ rlcd = realloc(argv, (argc+2)*sizeof *argv);
+ if (!rlcd) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto error;
+ }
+ argv = rlcd;
+ argv[argc++] = ptr;
+ }
+ argv[argc] = NULL;
+
+ optind = 0;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "hf:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ cmd_data_help();
+ free(*argv);
+ free(argv);
+ return 0;
+ case 'f':
+ if (!strcmp(optarg, "xml")) {
+ outformat = LYD_XML;
+ } else if (!strcmp(optarg, "json")) {
+ outformat = LYD_JSON;
+ } else {
+ fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
+ goto error;
+ }
+ break;
+ case '?':
+ /* getopt_long() prints message */
+ goto error;
+ }
+ }
+ if (optind != argc) {
+ fprintf(stderr, "Unknown parameter \"%s\"\n", argv[optind]);
+error:
+ free(*argv);
+ free(argv);
+ return 1;
+ }
+ free(*argv);
+ free(argv);
+
+ return print_list(stdout, ctx, outformat);
+}
+#endif
+int
+cmd_feature(const char *arg)
+{
+ int c, argc, option_index, ret = 1, task = 0;
+ char **argv = NULL, *ptr, *model_name, *revision, *feat_names = NULL;
+ const struct lys_module *module;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"enable", required_argument, 0, 'e'},
+ {"disable", required_argument, 0, 'd'},
+ {NULL, 0, 0, 0}
+ };
+ void *rlcd;
+
+ argc = 1;
+ argv = malloc(2*sizeof *argv);
+ *argv = strdup(arg);
+ ptr = strtok(*argv, " ");
+ while ((ptr = strtok(NULL, " "))) {
+ rlcd = realloc(argv, (argc + 2) * sizeof *argv);
+ if (!rlcd) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto cleanup;
+ }
+ argv = rlcd;
+ argv[argc++] = ptr;
+ }
+ argv[argc] = NULL;
+
+ optind = 0;
+ while (1) {
+ option_index = 0;
+ c = getopt_long(argc, argv, "he:d:", long_options, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ cmd_feature_help();
+ ret = 0;
+ goto cleanup;
+ case 'e':
+ if (task) {
+ fprintf(stderr, "Only one of enable or disable can be specified.\n");
+ goto cleanup;
+ }
+ task = 1;
+ feat_names = optarg;
+ break;
+ case 'd':
+ if (task) {
+ fprintf(stderr, "Only one of enable, or disable can be specified.\n");
+ goto cleanup;
+ }
+ task = 2;
+ feat_names = optarg;
+ break;
+ case '?':
+ fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
+ goto cleanup;
+ }
+ }
+
+ /* module name */
+ if (optind == argc) {
+ fprintf(stderr, "Missing the module name.\n");
+ goto cleanup;
+ }
+
+ revision = NULL;
+ model_name = argv[optind];
+ if (strchr(model_name, '@')) {
+ revision = strchr(model_name, '@');
+ revision[0] = '\0';
+ ++revision;
+ }
+
+ module = ly_ctx_get_module(ctx, model_name, revision);
+#if 0
+ if (!module) {
+ /* not a module, try to find it as a submodule */
+ module = (const struct lys_module *)ly_ctx_get_submodule(ctx, NULL, NULL, model_name, revision);
+ }
+#endif
+
+ if (module == NULL) {
+ if (revision) {
+ fprintf(stderr, "No (sub)module \"%s\" in revision %s found.\n", model_name, revision);
+ } else {
+ fprintf(stderr, "No (sub)module \"%s\" found.\n", model_name);
+ }
+ goto cleanup;
+ }
+
+ if (!task) {
+ unsigned int len, max_len = 0;
+ unsigned int u;
+ struct lysc_feature *features;
+
+ printf("%s features:\n", module->name);
+
+ if (module->compiled) {
+ features = module->compiled->features;
+ } else {
+ features = module->off_features;
+ }
+
+ /* get the max len */
+ LY_ARRAY_FOR(features, u) {
+ len = strlen(features[u].name);
+ if (len > max_len) {
+ max_len = len;
+ }
+ }
+
+ LY_ARRAY_FOR(features, u) {
+ printf("\t%-*s (%s)\n", max_len, features[u].name, (features[u].flags & LYS_FENABLED) ? "on" : "off");
+ }
+ if (!u) {
+ printf("\t(none)\n");
+ }
+ } else {
+ feat_names = strtok(feat_names, ",");
+ while (feat_names) {
+ if (((task == 1) && lys_feature_enable(module, feat_names))
+ || ((task == 2) && lys_feature_disable(module, feat_names))) {
+ fprintf(stderr, "Feature \"%s\" not found.\n", feat_names);
+ ret = 1;
+ }
+ feat_names = strtok(NULL, ",");
+ }
+ }
+
+cleanup:
+ free(*argv);
+ free(argv);
+
+ return ret;
+}
+
+int
+cmd_searchpath(const char *arg)
+{
+ const char *path;
+ const char * const *searchpaths;
+ int index;
+ struct stat st;
+
+ for (path = strchr(arg, ' '); path && (path[0] == ' '); ++path);
+ if (!path || (path[0] == '\0')) {
+ searchpaths = ly_ctx_get_searchdirs(ctx);
+ if (searchpaths) {
+ for (index = 0; searchpaths[index]; index++) {
+ fprintf(stdout, "%s\n", searchpaths[index]);
+ }
+ }
+ return 0;
+ }
+
+ if ((!strncmp(path, "-h", 2) && (path[2] == '\0' || path[2] == ' ')) ||
+ (!strncmp(path, "--help", 6) && (path[6] == '\0' || path[6] == ' '))) {
+ cmd_searchpath_help();
+ return 0;
+ } else if (!strncmp(path, "--clear", 7) && (path[7] == '\0' || path[7] == ' ')) {
+ ly_ctx_unset_searchdirs(ctx, NULL);
+ return 0;
+ }
+
+ if (stat(path, &st) == -1) {
+ fprintf(stderr, "Failed to stat the search path (%s).\n", strerror(errno));
+ return 1;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "\"%s\" is not a directory.\n", path);
+ return 1;
+ }
+
+ ly_ctx_set_searchdir(ctx, path);
+
+ return 0;
+}
+
+int
+cmd_clear(const char *arg)
+{
+ struct ly_ctx *ctx_new;
+ int options = 0;
+#if 0
+ int i;
+ char *ylpath;
+ const char * const *searchpaths;
+ LYD_FORMAT format;
+
+ /* get optional yang library file name */
+ for (i = 5; arg[i] && isspace(arg[i]); i++);
+ if (arg[i]) {
+ if (arg[i] == '-' && arg[i + 1] == 'e') {
+ options = LY_CTX_NOYANGLIBRARY;
+ goto create_empty;
+ } else {
+ ylpath = strdup(&arg[i]);
+ format = detect_data_format(ylpath);
+ if (format == LYD_UNKNOWN) {
+ free(ylpath);
+ fprintf(stderr, "Unable to resolve format of the yang library file, please add \".xml\" or \".json\" suffix.\n");
+ goto create_empty;
+ }
+ searchpaths = ly_ctx_get_searchdirs(ctx);
+ ctx_new = ly_ctx_new_ylpath(searchpaths ? searchpaths[0] : NULL, ylpath, format, 0);
+ free(ylpath);
+ }
+ } else {
+create_empty:
+#else
+ (void) arg; /* TODO unused */
+ {
+#endif
+ ly_ctx_new(NULL, options, &ctx_new);
+ }
+
+ if (!ctx_new) {
+ fprintf(stderr, "Failed to create context.\n");
+ return 1;
+ }
+
+ /* final switch */
+ ly_ctx_destroy(ctx, NULL);
+ ctx = ctx_new;
+
+ return 0;
+}
+
+int
+cmd_verb(const char *arg)
+{
+ const char *verb;
+ if (strlen(arg) < 5) {
+ cmd_verb_help();
+ return 1;
+ }
+
+ verb = arg + 5;
+ if (!strcmp(verb, "error") || !strcmp(verb, "0")) {
+ ly_verb(LY_LLERR);
+#ifndef NDEBUG
+ ly_verb_dbg(0);
+#endif
+ } else if (!strcmp(verb, "warning") || !strcmp(verb, "1")) {
+ ly_verb(LY_LLWRN);
+#ifndef NDEBUG
+ ly_verb_dbg(0);
+#endif
+ } else if (!strcmp(verb, "verbose") || !strcmp(verb, "2")) {
+ ly_verb(LY_LLVRB);
+#ifndef NDEBUG
+ ly_verb_dbg(0);
+#endif
+ } else if (!strcmp(verb, "debug") || !strcmp(verb, "3")) {
+ ly_verb(LY_LLDBG);
+#ifndef NDEBUG
+ ly_verb_dbg(LY_LDGDICT | LY_LDGYANG | LY_LDGYIN | LY_LDGXPATH | LY_LDGDIFF);
+#endif
+ } else {
+ fprintf(stderr, "Unknown verbosity \"%s\"\n", verb);
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifndef NDEBUG
+
+int
+cmd_debug(const char *arg)
+{
+ const char *beg, *end;
+ int grps = 0;
+ if (strlen(arg) < 6) {
+ cmd_debug_help();
+ return 1;
+ }
+
+ end = arg + 6;
+ while (end[0]) {
+ for (beg = end; isspace(beg[0]); ++beg);
+ if (!beg[0]) {
+ break;
+ }
+
+ for (end = beg; (end[0] && !isspace(end[0])); ++end);
+
+ if (!strncmp(beg, "dict", end - beg)) {
+ grps |= LY_LDGDICT;
+ } else if (!strncmp(beg, "yang", end - beg)) {
+ grps |= LY_LDGYANG;
+ } else if (!strncmp(beg, "yin", end - beg)) {
+ grps |= LY_LDGYIN;
+ } else if (!strncmp(beg, "xpath", end - beg)) {
+ grps |= LY_LDGXPATH;
+ } else if (!strncmp(beg, "diff", end - beg)) {
+ grps |= LY_LDGDIFF;
+ } else {
+ fprintf(stderr, "Unknown debug group \"%.*s\"\n", (int)(end - beg), beg);
+ return 1;
+ }
+ }
+ ly_verb_dbg(grps);
+
+ return 0;
+}
+
+#endif
+
+int
+cmd_quit(const char *UNUSED(arg))
+{
+ done = 1;
+ return 0;
+}
+
+int
+cmd_help(const char *arg)
+{
+ int i;
+ char *args = strdup(arg);
+ char *cmd = NULL;
+
+ strtok(args, " ");
+ if ((cmd = strtok(NULL, " ")) == NULL) {
+
+generic_help:
+ fprintf(stdout, "Available commands:\n");
+
+ for (i = 0; commands[i].name; i++) {
+ if (commands[i].helpstring != NULL) {
+ fprintf(stdout, " %-15s %s\n", commands[i].name, commands[i].helpstring);
+ }
+ }
+ } else {
+ /* print specific help for the selected command */
+
+ /* get the command of the specified name */
+ for (i = 0; commands[i].name; i++) {
+ if (strcmp(cmd, commands[i].name) == 0) {
+ break;
+ }
+ }
+
+ /* execute the command's help if any valid command specified */
+ if (commands[i].name) {
+ if (commands[i].help_func != NULL) {
+ commands[i].help_func();
+ } else {
+ printf("%s\n", commands[i].helpstring);
+ }
+ } else {
+ /* if unknown command specified, print the list of commands */
+ printf("Unknown command \'%s\'\n", cmd);
+ goto generic_help;
+ }
+ }
+
+ free(args);
+ return 0;
+}
+
+COMMAND commands[] = {
+ {"help", cmd_help, NULL, "Display commands description"},
+ {"add", cmd_add, cmd_add_help, "Add a new model from a specific file"},
+ {"load", cmd_load, cmd_load_help, "Load a new model from the searchdirs"},
+ {"print", cmd_print, cmd_print_help, "Print a model"},
+#if 0
+ {"data", cmd_data, cmd_data_help, "Load, validate and optionally print instance data"},
+ {"xpath", cmd_xpath, cmd_xpath_help, "Get data nodes satisfying an XPath expression"},
+ {"list", cmd_list, cmd_list_help, "List all the loaded models"},
+#endif
+ {"feature", cmd_feature, cmd_feature_help, "Print/enable/disable all/specific features of models"},
+ {"searchpath", cmd_searchpath, cmd_searchpath_help, "Print/set the search path(s) for models"},
+ {"clear", cmd_clear, cmd_clear_help, "Clear the context - remove all the loaded models"},
+ {"verb", cmd_verb, cmd_verb_help, "Change verbosity"},
+#ifndef NDEBUG
+ {"debug", cmd_debug, cmd_debug_help, "Display specific debug message groups"},
+#endif
+ {"quit", cmd_quit, NULL, "Quit the program"},
+ /* synonyms for previous commands */
+ {"?", cmd_help, NULL, "Display commands description"},
+ {"exit", cmd_quit, NULL, "Quit the program"},
+ {NULL, NULL, NULL, NULL}
+};
diff --git a/tools/lint/commands.h b/tools/lint/commands.h
new file mode 100644
index 0000000..18d7fdc
--- /dev/null
+++ b/tools/lint/commands.h
@@ -0,0 +1,46 @@
+/**
+ * @file main.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool commands header
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef COMMANDS_H_
+#define COMMANDS_H_
+
+#ifdef __GNUC__
+# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+# define UNUSED(x) UNUSED_ ## x
+#endif
+
+#include <stdlib.h>
+
+#include "libyang.h"
+
+#define PROMPT "> "
+
+struct model_hint {
+ char* hint;
+ struct model_hint* next;
+};
+
+typedef struct {
+ char *name; /* User printable name of the function. */
+ int (*func)(const char*); /* Function to call to do the command. */
+ void (*help_func)(void); /* Display command help. */
+ char *helpstring; /* Documentation for this function. */
+} COMMAND;
+
+LYS_INFORMAT get_schema_format(const char *path);
+
+extern COMMAND commands[];
+
+#endif /* COMMANDS_H_ */
diff --git a/tools/lint/completion.c b/tools/lint/completion.c
new file mode 100644
index 0000000..f2e8461
--- /dev/null
+++ b/tools/lint/completion.c
@@ -0,0 +1,140 @@
+/**
+ * @file completion.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool auto completion
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+
+#include "commands.h"
+#include "./linenoise/linenoise.h"
+#include "libyang.h"
+
+extern struct ly_ctx *ctx;
+
+static void
+get_cmd_completion(const char *hint, char ***matches, unsigned int *match_count)
+{
+ int i;
+ void *p;
+
+ *match_count = 0;
+ *matches = NULL;
+
+ for (i = 0; commands[i].name; i++) {
+ if (!strncmp(hint, commands[i].name, strlen(hint))) {
+ ++(*match_count);
+ p = realloc(*matches, *match_count * sizeof **matches);
+ if (!p) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ return;
+ }
+ *matches = p;
+ (*matches)[*match_count-1] = strdup(commands[i].name);
+ }
+ }
+}
+
+static int
+last_is_opt(const char *hint)
+{
+ const char *ptr;
+
+ /* last is option */
+ if (hint[0] == '-') {
+ return 1;
+ }
+
+ do {
+ --hint;
+ } while (hint[0] == ' ');
+
+ /* last is option argument */
+ ptr = strrchr(hint, ' ');
+ if (ptr) {
+ ++ptr;
+ if (ptr[0] == '-') {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+get_model_completion(const char *hint, char ***matches, unsigned int *match_count)
+{
+ unsigned int u;
+ uint32_t idx = 0;
+ const struct lys_module *module;
+ void *p;
+
+ *match_count = 0;
+ *matches = NULL;
+
+ while ((module = ly_ctx_get_module_iter(ctx, &idx))) {
+ if (!strncmp(hint, module->name, strlen(hint))) {
+ ++(*match_count);
+ p = realloc(*matches, *match_count * sizeof **matches);
+ if (!p) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ return;
+ }
+ *matches = p;
+ (*matches)[*match_count-1] = strdup(module->name);
+ }
+
+ LY_ARRAY_FOR(module->parsed->includes, u) {
+ if (!strncmp(hint, module->parsed->includes[u].submodule->name, strlen(hint))) {
+ ++(*match_count);
+ p = realloc(*matches, *match_count * sizeof **matches);
+ if (!p) {
+ fprintf(stderr, "Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ return;
+ }
+ *matches = p;
+ (*matches)[*match_count-1] = strdup(module->parsed->includes[u].submodule->name);
+ }
+ }
+ }
+}
+
+void
+complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc)
+{
+ char **matches = NULL;
+ unsigned int match_count = 0, i;
+
+ if (!strncmp(buf, "add ", 4)) {
+ linenoisePathCompletion(buf, hint, lc);
+ } else if ((!strncmp(buf, "searchpath ", 11) || !strncmp(buf, "data ", 5)
+ || !strncmp(buf, "config ", 7) || !strncmp(buf, "filter ", 7)
+ || !strncmp(buf, "xpath ", 6) || !strncmp(buf, "clear ", 6)) && !last_is_opt(hint)) {
+ linenoisePathCompletion(buf, hint, lc);
+ } else if ((!strncmp(buf, "print ", 6) || !strncmp(buf, "feature ", 8)) && !last_is_opt(hint)) {
+ get_model_completion(hint, &matches, &match_count);
+ } else if (!strchr(buf, ' ') && hint[0]) {
+ get_cmd_completion(hint, &matches, &match_count);
+ }
+
+ for (i = 0; i < match_count; ++i) {
+ linenoiseAddCompletion(lc, matches[i]);
+ free(matches[i]);
+ }
+ free(matches);
+}
diff --git a/tools/lint/completion.h b/tools/lint/completion.h
new file mode 100644
index 0000000..953add2
--- /dev/null
+++ b/tools/lint/completion.h
@@ -0,0 +1,22 @@
+/**
+ * @file main.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang's yanglint tool auto completion header
+ *
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef COMPLETION_H_
+#define COMPLETION_H_
+
+#include "./linenoise/linenoise.h"
+
+void complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc);
+
+#endif /* COMPLETION_H_ */
diff --git a/tools/lint/configuration.c b/tools/lint/configuration.c
new file mode 100644
index 0000000..095d2d0
--- /dev/null
+++ b/tools/lint/configuration.c
@@ -0,0 +1,121 @@
+/**
+ * @file configuration.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief yanglint configuration
+ *
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include "configuration.h"
+#include "./linenoise/linenoise.h"
+
+/* Yanglint home (appended to ~/) */
+#define YL_DIR ".yanglint"
+
+char *
+get_yanglint_dir(void)
+{
+ int ret;
+ struct passwd *pw;
+ char *user_home, *yl_dir;
+
+ if (!(pw = getpwuid(getuid()))) {
+ fprintf(stderr, "Determining home directory failed (%s).\n", strerror(errno));
+ return NULL;
+ }
+ user_home = pw->pw_dir;
+
+ yl_dir = malloc(strlen(user_home) + 1 + strlen(YL_DIR) + 1);
+ if (!yl_dir) {
+ fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+ return NULL;
+ }
+ sprintf(yl_dir, "%s/%s", user_home, YL_DIR);
+
+ ret = access(yl_dir, R_OK | X_OK);
+ if (ret == -1) {
+ if (errno == ENOENT) {
+ /* directory does not exist */
+ fprintf(stdout, "Configuration directory \"%s\" does not exist, creating it.\n", yl_dir);
+ if (mkdir(yl_dir, 00700)) {
+ fprintf(stderr, "Configuration directory \"%s\" cannot be created (%s).\n", yl_dir, strerror(errno));
+ free(yl_dir);
+ return NULL;
+ }
+ } else {
+ fprintf(stderr, "Configuration directory \"%s\" exists but cannot be accessed (%s).\n", yl_dir, strerror(errno));
+ free(yl_dir);
+ return NULL;
+ }
+ }
+
+ return yl_dir;
+}
+
+void
+load_config(void)
+{
+ char *yl_dir, *history_file;
+ if ((yl_dir = get_yanglint_dir()) == NULL) {
+ return;
+ }
+
+ history_file = malloc(strlen(yl_dir) + 9);
+ if (!history_file) {
+ fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+ free(yl_dir);
+ return;
+ }
+
+ sprintf(history_file, "%s/history", yl_dir);
+ if (access(history_file, F_OK) && (errno == ENOENT)) {
+ fprintf(stdout, "No saved history.\n");
+ } else if (linenoiseHistoryLoad(history_file)) {
+ fprintf(stderr, "Failed to load history.\n");
+ }
+
+ free(history_file);
+ free(yl_dir);
+}
+
+void
+store_config(void)
+{
+ char *yl_dir, *history_file;
+
+ if ((yl_dir = get_yanglint_dir()) == NULL) {
+ return;
+ }
+
+ history_file = malloc(strlen(yl_dir) + 9);
+ if (!history_file) {
+ fprintf(stderr, "Memory allocation failed (%s).\n", strerror(errno));
+ free(yl_dir);
+ return;
+ }
+
+ sprintf(history_file, "%s/history", yl_dir);
+ if (linenoiseHistorySave(history_file)) {
+ fprintf(stderr, "Failed to save history.\n");
+ }
+
+ free(history_file);
+ free(yl_dir);
+}
diff --git a/tools/lint/configuration.h b/tools/lint/configuration.h
new file mode 100644
index 0000000..a299407
--- /dev/null
+++ b/tools/lint/configuration.h
@@ -0,0 +1,37 @@
+/**
+ * @file configuration.h
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief yanglint configuration header
+ *
+ * Copyright (c) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef CONFIGURATION_H_
+#define CONFIGURATION_H_
+
+
+/**
+ * @brief Finds the current user's yanglint dir
+ * @return NULL on failure, dynamically allocated yanglint dir path
+ * otherwise
+ */
+char *get_yanglint_dir(void);
+
+/**
+ * @brief Checks all the relevant files and directories creating any
+ * that are missing, sets the saved configuration (currently only history)
+ */
+void load_config(void);
+
+/**
+ * @brief Saves the current configuration (currently only history)
+ */
+void store_config(void);
+
+#endif /* CONFIGURATION_H_ */
diff --git a/tools/lint/examples/README.md b/tools/lint/examples/README.md
new file mode 100644
index 0000000..4b1d972
--- /dev/null
+++ b/tools/lint/examples/README.md
@@ -0,0 +1,572 @@
+YANGLINT IS NOT YET PREPARED FOR USE, EXAMPLES MAY NOT WORK YET!!!
+
+# YANGLINT - Interactive Mode Examples
+
+This text provides several use-case of the `yanglint(1)` interactive
+mode. For basic information about the `yanglint(1)` usage, please see
+the man page.
+
+The examples are supposed to be went through one by one. Some of the examples
+suppose the specific schemas loaded in some of the previous example is still
+loaded. If an addition work is need, the *preparation* part in the example
+provides information what to do.
+
+To show all available command of the `yanglint(1)`, use the `help` command:
+```
+> help
+Available commands:
+ help Display commands description
+ add Add a new model
+ print Print model
+ data Load, validate and optionally print instance data
+ xpath Get data nodes satisfying an XPath expression
+ list List all the loaded models
+ feature Print/enable/disable all/specific features of models
+ searchpath Set the search path for models
+ clear Clear the context - remove all the loaded models
+ verb Change verbosity
+ quit Quit the program
+ ? Display commands description
+ exit Quit the program
+```
+To show the information about the specific command, use the `help` command in
+combination with the command name you are interested in:
+```
+> help searchpath
+searchpath <model-dir-path>
+```
+
+The input files referred in this document are available together with this
+document.
+
+## Duplicit Data Model
+
+Let's have two data models [module1.yang](./module1.yang)
+and [module1b.yang](./module1b.yang).
+They differ in the module name but their namespaces are the same.
+
+Preparation:
+
+```
+> clear
+> add module1.yang
+> list
+```
+
+Output:
+
+```
+List of the loaded models (mod-set-id 5):
+ ietf-inet-types@2013-07-15
+ ietf-yang-types@2013-07-15
+ ietf-yang-library@2015-07-03
+ module1
+```
+
+Command and its output:
+
+```
+> add module1b.yang
+libyang[0]: Two different modules ("module1" and "module1b") have the same namespace "urn:yanglint:module".
+libyang[0]: Module "module1b" parsing failed.
+```
+
+## Yang Data Model Validation
+
+**YANG/YIN syntax**
+
+`module2.yin` contains a syntax error.
+There is a bad syntax of the `type` statement in YIN file.
+
+```
+<type value="string"/>
+```
+
+instead of
+
+```
+<type name="string"/>
+```
+
+Preparation:
+
+```
+> clear
+```
+
+Command and its output:
+
+```
+> add module2.yin
+libyang[0]: Missing argument "name" to keyword "type".
+libyang[0]: Module "module1" parsing failed.
+```
+
+Similarly, there is a typo in `module2.yang`.
+
+**XPath errors**
+
+`libyang` and `yanglint(1)` is able to detect also errors in XPath expressions.
+In `module3.yang` the `must` expression refers to the node which does not exists.
+
+Preparation:
+
+```
+> clear
+```
+
+Command and its output:
+
+```
+> add module3.yang
+libyang[0]: Schema node "a" not found (../c/a).
+libyang[0]: Path is related to the previous error message. (path: /module3:m)
+libyang[0]: Module "module3" parsing failed.
+```
+
+Note that libyang does not provide line numbers of the error. Instead it tries to
+print the path to the related node. in some cases (as this one) it is not able
+to print the path immediately so the path (to the node `m` which refers node which
+does not exist) is printed in the second message.
+
+## Data Validation
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Unknown data**
+
+By default, yanglint ignores unknown data and no error is printed (you can
+compare real content of the `datastore.xml` file and what yanglint prints
+in the following command if you add `-f xml` option).
+
+Command and its output:
+
+```
+> data -t config datastore.xml
+```
+
+We use option `-t` to specify type of the data in `datastore.xml`. By the
+`config` value we declare that the input file contains all the configuration
+data (with at least all the mandatory nodes as required by the loaded schemas),
+but without the status data. More examples of different data types will follow.
+
+To handle unknown data as error, use strict mode (`-s` option).
+
+Command and its output:
+
+```
+> data -t config -s datastore.xml
+libyang[0]: Unknown element "interfaces". (path: /)
+Failed to parse data.
+```
+
+Note that in case of working with complete datastore including the status data
+(no `-t` option is specified), `yanglint(1)` has to add status data from its
+internal `ietf-yang-library` module. Using the `-s` option in this case forces
+validation in time of parsing the input file so it is expected to include also
+the mandatory status data from the `ietf-yang-library` module.
+
+**RPC and RPC-reply**
+
+It is possible to validate RPCs and their replies as well.
+
+Peparation:
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t rpc rpc.xml
+```
+
+Reply to this RPC can be validated too, but it must be specified, to which
+RPC it is a reply to, because it is not included in the reply itself.
+
+Command and its output:
+
+```
+> data -t rpcreply rpc-reply.xml rpc.xml
+```
+
+**action and action-reply**
+
+Actions are validated the same way as RPCs except you need to be careful
+about the input file structure.
+
+Preparation
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t rpc action.xml
+```
+
+Command and its output:
+
+```
+> data -t rpc action-reply.xml action.xml
+```
+
+**notification**
+
+Both top-level and nested notification can be validated.
+
+Preparation
+
+```
+> clear
+> add module4.yang
+```
+
+Command and its output:
+
+```
+> data -t notif notification.xml
+```
+
+Command and its output:
+
+```
+> data -t notif nested-notification.xml
+```
+
+
+**Multiple top-level elements in a single document**
+
+As a feature and in conflict with the XML definition, `yanglint(1)` (and libyang)
+is able to read XML files with multiple top-level elements. Such documents
+are not well-formed according to the XML spec, but it fits to how the YANG
+interconnects data trees (defined as top-level elements of a single schema
+or by multiple schemas).
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+> add ietf-interfaces.yang
+> add ietf-ip.yang
+> add iana-if-type.yang
+```
+
+Command and its output:
+
+```
+> data -t config -s datastore.xml
+```
+
+**Different data content types**
+
+Since NETCONF requires the data described by YANG to be used in different
+situations (e.g. as <edit-config data>, result of the <get> with status data
+included or as a result of the <get-config> without the status data and
+possibly filtered, so without specified subtrees), it must be possible to
+specify which kind of data is going to be parsed. In `yanglint(1)`, this is done
+via `-t` option. The list of supported modes can be displayed by the `-h`
+option given to the `data` command. In general, the `auto` value lets the
+`yanglint(1)` to recognize the data type automatically by the additional top-level
+elements added to the parsed data. This is the same way as `pyang(1)` uses. Note,
+that the automatic data type recognition is available only for the XML input.
+
+**Malformed XML data**
+
+Command and its output:
+
+```
+> data -t edit config-missing-key.xml
+libyang[0]: Invalid (mixed names) opening (nam) and closing (name) element tags. (path: /nacm/groups/group/nam)
+Failed to parse data.
+```
+
+**State information in edit-config XML**
+
+Command and its output:
+
+```
+> data -t edit config-unknown-element.xml
+libyang[0]: Unknown element "denied-operations". (path: /ietf-netconf-acm:nacm/denied-operations)
+Failed to parse data.
+```
+
+**Missing required element in NETCONF data**
+
+Command and its output:
+
+```
+> data data-missing-key.xml
+libyang[0]: Missing required element "name" in "rule". (path: /ietf-netconf-acm:nacm/rule-list[name='almighty']/rule)
+Failed to parse data.
+```
+
+**Malformed XML**
+
+Command and its output:
+
+```
+> data data-malformed-xml.xml
+libyang[0]: Invalid (mixed names) opening (nam) and closing (rule) element tags. (path: /nacm/rule-list/rule/nam)
+Failed to parse data.
+```
+
+Command and its output:
+
+```
+> data data-malformed-xml2.xml
+libyang[0]: Invalid (mixed names) opening (module-name) and closing (name) element tags. (path: /nacm/rule-list/rule/name/module-name)
+Failed to parse data.
+```
+
+**Bad value**
+
+Command and its output:
+
+```
+> data data-out-of-range-value.xml
+libyang[0]: Invalid value "-1" in "denied-operations" element. (path: /ietf-netconf-acm:nacm/denied-operations)
+Failed to parse data.
+```
+
+## Validation of "when" Statement in Data
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm-when.yang
+```
+
+**`When` condition is not satisfied since `denied-operation = 0`**
+
+Command and its output:
+
+```
+> data data-acm.xml
+```
+
+The command succeeds. It is because `yanglint(1)` (via `libyang`) performs
+autodeletion - the not satisfied `when` condition in `denied-data-writes`
+causes its automatic (silent) deletion.
+
+## Printing a Data Model
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Print a `pyang`-style tree**
+
+Command and its output:
+
+```
+> print ietf-netconf-acm
+module: ietf-netconf-acm
+ +--rw nacm
+ +--rw enable-nacm? boolean <true>
+ +--rw read-default? action-type <permit>
+ +--rw write-default? action-type <deny>
+ +--rw exec-default? action-type <permit>
+ +--rw enable-external-groups? boolean <true>
+ +--ro denied-operations ietf-yang-types:zero-based-counter32
+ +--ro denied-data-writes ietf-yang-types:zero-based-counter32
+ +--ro denied-notifications ietf-yang-types:zero-based-counter32
+ +--rw groups
+ | +--rw group* [name]
+ | +--rw name group-name-type
+ | +--rw user-name* user-name-type
+ +--rw rule-list* [name]
+ +--rw name string
+ +--rw group* union
+ +--rw rule* [name]
+ +--rw name string
+ +--rw module-name? union <*>
+ +--rw (rule-type)?
+ | +--:(protocol-operation)
+ | | +--rw rpc-name? union
+ | +--:(notification)
+ | | +--rw notification-name? union
+ | +--:(data-node)
+ | +--rw path node-instance-identifier
+ +--rw access-operations? union <*>
+ +--rw action action-type
+ +--rw comment? string
+>
+```
+
+**Obtain information about model**
+
+Command and its output:
+
+```
+> print -f info ietf-netconf-acm
+Module: ietf-netconf-acm
+Namespace: urn:ietf:params:xml:ns:yang:ietf-netconf-acm
+Prefix: nacm
+Desc: NETCONF Access Control Model.
+
+ Copyright (c) 2012 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD
+ License set forth in Section 4.c of the IETF Trust's
+ Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6536; see
+ the RFC itself for full legal notices.
+Reference:
+Org: IETF NETCONF (Network Configuration) Working Group
+Contact: WG Web: <http://tools.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+
+ WG Chair: Bert Wijnen
+ <mailto:bertietf@bwijnen.net>
+
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>
+YANG ver: 1.0
+Deviated: no
+Implement: yes
+URI:
+Revisions: 2012-02-22
+Includes:
+Imports: yang:ietf-yang-types
+Typedefs: user-name-type
+ matchall-string-type
+ access-operations-type
+ group-name-type
+ action-type
+ node-instance-identifier
+Idents:
+Features:
+Augments:
+Deviation:
+Data: container "nacm"
+```
+
+**Print information about specific model part**
+
+Command and its output:
+
+```
+> print -f info -t /ietf-netconf-acm:nacm/ietf-netconf-acm:enable-nacm ietf-netconf-ac
+Leaf: enable-nacm
+Module: ietf-netconf-acm
+Desc: Enables or disables all NETCONF access control
+ enforcement. If 'true', then enforcement
+ is enabled. If 'false', then enforcement
+ is disabled.
+Reference:
+Config: read-write
+Status: current
+Mandatory: no
+Type: boolean
+Units:
+Default: true
+If-feats:
+When:
+Must:
+NACM: default-deny-all
+```
+
+## Query using NETCONF data
+
+Preparation:
+
+```
+> clear
+> add ietf-netconf-acm.yang
+```
+
+**Print all `user-name` elements that occure in data**
+
+Command and its output:
+
+```
+> xpath -e //ietf-netconf-acm:user-name data-acm.xml
+Result:
+ Leaflist "user-name" (val: smith)
+ Leaflist "user-name" (val: smith)
+ Leaflist "user-name" (val: doe)
+
+```
+
+**Print all data that satisfies condition**
+
+Command and its output:
+
+```
+> xpath -e //ietf-netconf-acm:user-name[text()="smith"] data-acm.xml
+Result:
+ Leaflist "user-name" (val: smith)
+ Leaflist "user-name" (val: smith)
+
+```
+
+## Usage of `feature` in Yang
+
+Preparation:
+
+```
+> clear
+> add ietf-interfaces.yang
+> add ietf-ip.yang
+> add iana-if-type.yang
+```
+
+Note: This example also shows `JSON` output of the command.
+
+Command and its output:
+```
+> feature -e * ietf-ip
+> data -f json -t config data-ip.xml
+{
+ "ietf-interfaces:interfaces": {
+ "interface": [
+ {
+ "name": "eth0",
+ "description": "Wire Connection",
+ "type": "iana-if-type:ethernetCsmacd",
+ "enabled": true,
+ "ietf-ip:ipv4": {
+ "address": [
+ {
+ "ip": "192.168.1.15",
+ "netmask": "255.255.255.0"
+ },
+ {
+ "ip": "192.168.1.10",
+ "netmask": "255.255.255.0"
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
+```
+
diff --git a/tools/lint/examples/action-reply.xml b/tools/lint/examples/action-reply.xml
new file mode 100644
index 0000000..5a4788e
--- /dev/null
+++ b/tools/lint/examples/action-reply.xml
@@ -0,0 +1 @@
+<leaf3 xmlns="urn:module4">some_output</leaf3>
diff --git a/tools/lint/examples/action.xml b/tools/lint/examples/action.xml
new file mode 100644
index 0000000..b0bd411
--- /dev/null
+++ b/tools/lint/examples/action.xml
@@ -0,0 +1,10 @@
+<action xmlns="urn:ietf:params:xml:ns:yang:1">
+ <cont1 xmlns="urn:module4">
+ <list>
+ <leaf1>key_val</leaf1>
+ <act>
+ <leaf2>some_input</leaf2>
+ </act>
+ </list>
+ </cont1>
+</action>
diff --git a/tools/lint/examples/config-acm.xml b/tools/lint/examples/config-acm.xml
new file mode 100644
index 0000000..8c99419
--- /dev/null
+++ b/tools/lint/examples/config-acm.xml
@@ -0,0 +1,24 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+</nacm>
diff --git a/tools/lint/examples/config-missing-key.xml b/tools/lint/examples/config-missing-key.xml
new file mode 100644
index 0000000..16854d5
--- /dev/null
+++ b/tools/lint/examples/config-missing-key.xml
@@ -0,0 +1,24 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <nam>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+</nacm>
diff --git a/tools/lint/examples/config-unknown-element.xml b/tools/lint/examples/config-unknown-element.xml
new file mode 100644
index 0000000..87c79ee
--- /dev/null
+++ b/tools/lint/examples/config-unknown-element.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>0</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-acm.xml b/tools/lint/examples/data-acm.xml
new file mode 100644
index 0000000..87c79ee
--- /dev/null
+++ b/tools/lint/examples/data-acm.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>0</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-ip.xml b/tools/lint/examples/data-ip.xml
new file mode 100644
index 0000000..1894f6d
--- /dev/null
+++ b/tools/lint/examples/data-ip.xml
@@ -0,0 +1,12 @@
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+ <interface>
+ <name>eth0</name>
+ <description>Wire Connection</description>
+ <type xmlns:ift="urn:ietf:params:xml:ns:yang:iana-if-type">ift:ethernetCsmacd</type>
+ <enabled>true</enabled>
+ <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
+ <address><ip>192.168.1.15</ip><netmask>255.255.255.0</netmask></address>
+ <address><ip>192.168.1.10</ip><netmask>255.255.255.0</netmask></address>
+ </ipv4>
+ </interface>
+</interfaces>
diff --git a/tools/lint/examples/data-malformed-xml.xml b/tools/lint/examples/data-malformed-xml.xml
new file mode 100644
index 0000000..fd800ad
--- /dev/null
+++ b/tools/lint/examples/data-malformed-xml.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <nam>almighty
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>0</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-malformed-xml2.xml b/tools/lint/examples/data-malformed-xml2.xml
new file mode 100644
index 0000000..1837264
--- /dev/null
+++ b/tools/lint/examples/data-malformed-xml2.xml
@@ -0,0 +1,26 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty<module-name></name> *</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>0</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-missing-key.xml b/tools/lint/examples/data-missing-key.xml
new file mode 100644
index 0000000..d3ccd53
--- /dev/null
+++ b/tools/lint/examples/data-missing-key.xml
@@ -0,0 +1,26 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>0</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/data-out-of-range-value.xml b/tools/lint/examples/data-out-of-range-value.xml
new file mode 100644
index 0000000..83a0d65
--- /dev/null
+++ b/tools/lint/examples/data-out-of-range-value.xml
@@ -0,0 +1,27 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <group nc:operation="create">test</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>test</name>
+ <user-name>smith</user-name>
+ </group>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ <user-name>doe</user-name>
+ </group>
+ </groups>
+ <denied-operations>-1</denied-operations>
+ <denied-data-writes>0</denied-data-writes>
+ <denied-notifications>0</denied-notifications>
+</nacm>
diff --git a/tools/lint/examples/datastore.xml b/tools/lint/examples/datastore.xml
new file mode 100644
index 0000000..c6a6fc9
--- /dev/null
+++ b/tools/lint/examples/datastore.xml
@@ -0,0 +1,29 @@
+<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
+ <rule-list>
+ <name>almighty</name>
+ <group>almighty</group>
+ <rule>
+ <name>almighty</name>
+ <module-name>*</module-name>
+ <access-operations>*</access-operations>
+ <action>permit</action>
+ </rule>
+ </rule-list>
+ <groups>
+ <group>
+ <name>almighty</name>
+ <user-name>smith</user-name>
+ </group>
+ </groups>
+</nacm>
+<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
+ <interface>
+ <name>eth0</name>
+ <description>Wire Connection</description>
+ <type xmlns:ift="urn:ietf:params:xml:ns:yang:iana-if-type">ift:ethernetCsmacd</type>
+ <enabled>true</enabled>
+ <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
+ <address><ip>192.168.1.15</ip><prefix-length>24</prefix-length></address>
+ </ipv4>
+ </interface>
+</interfaces>
diff --git a/tools/lint/examples/iana-if-type.yang b/tools/lint/examples/iana-if-type.yang
new file mode 100644
index 0000000..5dd8219
--- /dev/null
+++ b/tools/lint/examples/iana-if-type.yang
@@ -0,0 +1,1547 @@
+module iana-if-type {
+ namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+ prefix ianaift;
+
+ import ietf-interfaces {
+ prefix if;
+ }
+
+ organization "IANA";
+ contact
+ " Internet Assigned Numbers Authority
+
+ Postal: ICANN
+ 4676 Admiralty Way, Suite 330
+ Marina del Rey, CA 90292
+
+ Tel: +1 310 823 9358
+ <mailto:iana@iana.org>";
+ description
+ "This YANG module defines YANG identities for IANA-registered
+ interface types.
+
+ This YANG module is maintained by IANA and reflects the
+ 'ifType definitions' registry.
+
+ The latest revision of this YANG module can be obtained from
+ the IANA web site.
+
+ Requests for new values should be made to IANA via
+ email (iana@iana.org).
+
+ Copyright (c) 2014 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ The initial version of this YANG module is part of RFC 7224;
+ see the RFC itself for full legal notices.";
+ reference
+ "IANA 'ifType definitions' registry.
+ <http://www.iana.org/assignments/smi-numbers>";
+
+ revision 2014-05-08 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7224: IANA Interface Type YANG Module";
+ }
+
+ identity iana-interface-type {
+ base if:interface-type;
+ description
+ "This identity is used as a base for all interface types
+ defined in the 'ifType definitions' registry.";
+ }
+
+
+
+
+
+
+ identity other {
+ base iana-interface-type;
+ }
+ identity regular1822 {
+ base iana-interface-type;
+ }
+ identity hdh1822 {
+ base iana-interface-type;
+ }
+ identity ddnX25 {
+ base iana-interface-type;
+ }
+ identity rfc877x25 {
+ base iana-interface-type;
+ reference
+ "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+ }
+ identity ethernetCsmacd {
+ base iana-interface-type;
+ description
+ "For all Ethernet-like interfaces, regardless of speed,
+ as per RFC 3635.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity iso88023Csmacd {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "Deprecated via RFC 3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity iso88024TokenBus {
+ base iana-interface-type;
+ }
+ identity iso88025TokenRing {
+ base iana-interface-type;
+ }
+ identity iso88026Man {
+ base iana-interface-type;
+ }
+ identity starLan {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "Deprecated via RFC 3635.
+ Use ethernetCsmacd(6) instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity proteon10Mbit {
+ base iana-interface-type;
+ }
+ identity proteon80Mbit {
+ base iana-interface-type;
+ }
+ identity hyperchannel {
+ base iana-interface-type;
+ }
+ identity fddi {
+ base iana-interface-type;
+ reference
+ "RFC 1512 - FDDI Management Information Base";
+ }
+ identity lapb {
+ base iana-interface-type;
+ reference
+ "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+ }
+ identity sdlc {
+ base iana-interface-type;
+ }
+ identity ds1 {
+ base iana-interface-type;
+ description
+ "DS1-MIB.";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+ identity e1 {
+ base iana-interface-type;
+ status obsolete;
+ description
+ "Obsolete; see DS1-MIB.";
+ reference
+ "RFC 4805 - Definitions of Managed Objects for the
+ DS1, J1, E1, DS2, and E2 Interface Types";
+ }
+
+
+ identity basicISDN {
+ base iana-interface-type;
+ description
+ "No longer used. See also RFC 2127.";
+ }
+ identity primaryISDN {
+ base iana-interface-type;
+ description
+ "No longer used. See also RFC 2127.";
+ }
+ identity propPointToPointSerial {
+ base iana-interface-type;
+ description
+ "Proprietary serial.";
+ }
+ identity ppp {
+ base iana-interface-type;
+ }
+ identity softwareLoopback {
+ base iana-interface-type;
+ }
+ identity eon {
+ base iana-interface-type;
+ description
+ "CLNP over IP.";
+ }
+ identity ethernet3Mbit {
+ base iana-interface-type;
+ }
+ identity nsip {
+ base iana-interface-type;
+ description
+ "XNS over IP.";
+ }
+ identity slip {
+ base iana-interface-type;
+ description
+ "Generic SLIP.";
+ }
+ identity ultra {
+ base iana-interface-type;
+ description
+ "Ultra Technologies.";
+ }
+ identity ds3 {
+ base iana-interface-type;
+ description
+ "DS3-MIB.";
+ reference
+ "RFC 3896 - Definitions of Managed Objects for the
+ DS3/E3 Interface Type";
+ }
+ identity sip {
+ base iana-interface-type;
+ description
+ "SMDS, coffee.";
+ reference
+ "RFC 1694 - Definitions of Managed Objects for SMDS
+ Interfaces using SMIv2";
+ }
+ identity frameRelay {
+ base iana-interface-type;
+ description
+ "DTE only.";
+ reference
+ "RFC 2115 - Management Information Base for Frame Relay
+ DTEs Using SMIv2";
+ }
+ identity rs232 {
+ base iana-interface-type;
+ reference
+ "RFC 1659 - Definitions of Managed Objects for RS-232-like
+ Hardware Devices using SMIv2";
+ }
+ identity para {
+ base iana-interface-type;
+ description
+ "Parallel-port.";
+ reference
+ "RFC 1660 - Definitions of Managed Objects for
+ Parallel-printer-like Hardware Devices using
+ SMIv2";
+ }
+ identity arcnet {
+ base iana-interface-type;
+ description
+ "ARCnet.";
+ }
+ identity arcnetPlus {
+ base iana-interface-type;
+ description
+ "ARCnet Plus.";
+ }
+
+
+
+ identity atm {
+ base iana-interface-type;
+ description
+ "ATM cells.";
+ }
+ identity miox25 {
+ base iana-interface-type;
+ reference
+ "RFC 1461 - SNMP MIB extension for Multiprotocol
+ Interconnect over X.25";
+ }
+ identity sonet {
+ base iana-interface-type;
+ description
+ "SONET or SDH.";
+ }
+ identity x25ple {
+ base iana-interface-type;
+ reference
+ "RFC 2127 - ISDN Management Information Base using SMIv2";
+ }
+ identity iso88022llc {
+ base iana-interface-type;
+ }
+ identity localTalk {
+ base iana-interface-type;
+ }
+ identity smdsDxi {
+ base iana-interface-type;
+ }
+ identity frameRelayService {
+ base iana-interface-type;
+ description
+ "FRNETSERV-MIB.";
+ reference
+ "RFC 2954 - Definitions of Managed Objects for Frame
+ Relay Service";
+ }
+ identity v35 {
+ base iana-interface-type;
+ }
+ identity hssi {
+ base iana-interface-type;
+ }
+ identity hippi {
+ base iana-interface-type;
+ }
+
+ identity modem {
+ base iana-interface-type;
+ description
+ "Generic modem.";
+ }
+ identity aal5 {
+ base iana-interface-type;
+ description
+ "AAL5 over ATM.";
+ }
+ identity sonetPath {
+ base iana-interface-type;
+ }
+ identity sonetVT {
+ base iana-interface-type;
+ }
+ identity smdsIcip {
+ base iana-interface-type;
+ description
+ "SMDS InterCarrier Interface.";
+ }
+ identity propVirtual {
+ base iana-interface-type;
+ description
+ "Proprietary virtual/internal.";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ identity propMultiplexor {
+ base iana-interface-type;
+ description
+ "Proprietary multiplexing.";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+ identity ieee80212 {
+ base iana-interface-type;
+ description
+ "100BaseVG.";
+ }
+ identity fibreChannel {
+ base iana-interface-type;
+ description
+ "Fibre Channel.";
+ }
+
+
+
+ identity hippiInterface {
+ base iana-interface-type;
+ description
+ "HIPPI interfaces.";
+ }
+ identity frameRelayInterconnect {
+ base iana-interface-type;
+ status obsolete;
+ description
+ "Obsolete; use either
+ frameRelay(32) or frameRelayService(44).";
+ }
+ identity aflane8023 {
+ base iana-interface-type;
+ description
+ "ATM Emulated LAN for 802.3.";
+ }
+ identity aflane8025 {
+ base iana-interface-type;
+ description
+ "ATM Emulated LAN for 802.5.";
+ }
+ identity cctEmul {
+ base iana-interface-type;
+ description
+ "ATM Emulated circuit.";
+ }
+ identity fastEther {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "Obsoleted via RFC 3635.
+ ethernetCsmacd(6) should be used instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity isdn {
+ base iana-interface-type;
+ description
+ "ISDN and X.25.";
+ reference
+ "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+ in the Packet Mode";
+ }
+
+
+
+ identity v11 {
+ base iana-interface-type;
+ description
+ "CCITT V.11/X.21.";
+ }
+ identity v36 {
+ base iana-interface-type;
+ description
+ "CCITT V.36.";
+ }
+ identity g703at64k {
+ base iana-interface-type;
+ description
+ "CCITT G703 at 64Kbps.";
+ }
+ identity g703at2mb {
+ base iana-interface-type;
+ status obsolete;
+ description
+ "Obsolete; see DS1-MIB.";
+ }
+ identity qllc {
+ base iana-interface-type;
+ description
+ "SNA QLLC.";
+ }
+ identity fastEtherFX {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "Obsoleted via RFC 3635.
+ ethernetCsmacd(6) should be used instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity channel {
+ base iana-interface-type;
+ description
+ "Channel.";
+ }
+ identity ieee80211 {
+ base iana-interface-type;
+ description
+ "Radio spread spectrum.";
+ }
+ identity ibm370parChan {
+ base iana-interface-type;
+ description
+ "IBM System 360/370 OEMI Channel.";
+ }
+ identity escon {
+ base iana-interface-type;
+ description
+ "IBM Enterprise Systems Connection.";
+ }
+ identity dlsw {
+ base iana-interface-type;
+ description
+ "Data Link Switching.";
+ }
+ identity isdns {
+ base iana-interface-type;
+ description
+ "ISDN S/T interface.";
+ }
+ identity isdnu {
+ base iana-interface-type;
+ description
+ "ISDN U interface.";
+ }
+ identity lapd {
+ base iana-interface-type;
+ description
+ "Link Access Protocol D.";
+ }
+ identity ipSwitch {
+ base iana-interface-type;
+ description
+ "IP Switching Objects.";
+ }
+ identity rsrb {
+ base iana-interface-type;
+ description
+ "Remote Source Route Bridging.";
+ }
+ identity atmLogical {
+ base iana-interface-type;
+ description
+ "ATM Logical Port.";
+ reference
+ "RFC 3606 - Definitions of Supplemental Managed Objects
+ for ATM Interface";
+ }
+ identity ds0 {
+ base iana-interface-type;
+ description
+ "Digital Signal Level 0.";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ identity ds0Bundle {
+ base iana-interface-type;
+ description
+ "Group of ds0s on the same ds1.";
+ reference
+ "RFC 2494 - Definitions of Managed Objects for the DS0
+ and DS0 Bundle Interface Type";
+ }
+ identity bsc {
+ base iana-interface-type;
+ description
+ "Bisynchronous Protocol.";
+ }
+ identity async {
+ base iana-interface-type;
+ description
+ "Asynchronous Protocol.";
+ }
+ identity cnr {
+ base iana-interface-type;
+ description
+ "Combat Net Radio.";
+ }
+ identity iso88025Dtr {
+ base iana-interface-type;
+ description
+ "ISO 802.5r DTR.";
+ }
+ identity eplrs {
+ base iana-interface-type;
+ description
+ "Ext Pos Loc Report Sys.";
+ }
+ identity arap {
+ base iana-interface-type;
+ description
+ "Appletalk Remote Access Protocol.";
+ }
+ identity propCnls {
+ base iana-interface-type;
+ description
+ "Proprietary Connectionless Protocol.";
+ }
+ identity hostPad {
+ base iana-interface-type;
+ description
+ "CCITT-ITU X.29 PAD Protocol.";
+ }
+ identity termPad {
+ base iana-interface-type;
+ description
+ "CCITT-ITU X.3 PAD Facility.";
+ }
+ identity frameRelayMPI {
+ base iana-interface-type;
+ description
+ "Multiproto Interconnect over FR.";
+ }
+ identity x213 {
+ base iana-interface-type;
+ description
+ "CCITT-ITU X213.";
+ }
+ identity adsl {
+ base iana-interface-type;
+ description
+ "Asymmetric Digital Subscriber Loop.";
+ }
+ identity radsl {
+ base iana-interface-type;
+ description
+ "Rate-Adapt. Digital Subscriber Loop.";
+ }
+ identity sdsl {
+ base iana-interface-type;
+ description
+ "Symmetric Digital Subscriber Loop.";
+ }
+ identity vdsl {
+ base iana-interface-type;
+ description
+ "Very H-Speed Digital Subscrib. Loop.";
+ }
+ identity iso88025CRFPInt {
+ base iana-interface-type;
+ description
+ "ISO 802.5 CRFP.";
+ }
+ identity myrinet {
+ base iana-interface-type;
+ description
+ "Myricom Myrinet.";
+ }
+ identity voiceEM {
+ base iana-interface-type;
+ description
+ "Voice recEive and transMit.";
+ }
+ identity voiceFXO {
+ base iana-interface-type;
+ description
+ "Voice Foreign Exchange Office.";
+ }
+ identity voiceFXS {
+ base iana-interface-type;
+ description
+ "Voice Foreign Exchange Station.";
+ }
+ identity voiceEncap {
+ base iana-interface-type;
+ description
+ "Voice encapsulation.";
+ }
+ identity voiceOverIp {
+ base iana-interface-type;
+ description
+ "Voice over IP encapsulation.";
+ }
+ identity atmDxi {
+ base iana-interface-type;
+ description
+ "ATM DXI.";
+ }
+ identity atmFuni {
+ base iana-interface-type;
+ description
+ "ATM FUNI.";
+ }
+ identity atmIma {
+ base iana-interface-type;
+ description
+ "ATM IMA.";
+ }
+ identity pppMultilinkBundle {
+ base iana-interface-type;
+ description
+ "PPP Multilink Bundle.";
+ }
+ identity ipOverCdlc {
+ base iana-interface-type;
+ description
+ "IBM ipOverCdlc.";
+ }
+ identity ipOverClaw {
+ base iana-interface-type;
+ description
+ "IBM Common Link Access to Workstn.";
+ }
+ identity stackToStack {
+ base iana-interface-type;
+ description
+ "IBM stackToStack.";
+ }
+ identity virtualIpAddress {
+ base iana-interface-type;
+ description
+ "IBM VIPA.";
+ }
+ identity mpc {
+ base iana-interface-type;
+ description
+ "IBM multi-protocol channel support.";
+ }
+ identity ipOverAtm {
+ base iana-interface-type;
+ description
+ "IBM ipOverAtm.";
+ reference
+ "RFC 2320 - Definitions of Managed Objects for Classical IP
+ and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+ }
+ identity iso88025Fiber {
+ base iana-interface-type;
+ description
+ "ISO 802.5j Fiber Token Ring.";
+ }
+ identity tdlc {
+ base iana-interface-type;
+ description
+ "IBM twinaxial data link control.";
+ }
+ identity gigabitEthernet {
+ base iana-interface-type;
+ status deprecated;
+
+
+ description
+ "Obsoleted via RFC 3635.
+ ethernetCsmacd(6) should be used instead.";
+ reference
+ "RFC 3635 - Definitions of Managed Objects for the
+ Ethernet-like Interface Types";
+ }
+ identity hdlc {
+ base iana-interface-type;
+ description
+ "HDLC.";
+ }
+ identity lapf {
+ base iana-interface-type;
+ description
+ "LAP F.";
+ }
+ identity v37 {
+ base iana-interface-type;
+ description
+ "V.37.";
+ }
+ identity x25mlp {
+ base iana-interface-type;
+ description
+ "Multi-Link Protocol.";
+ }
+ identity x25huntGroup {
+ base iana-interface-type;
+ description
+ "X25 Hunt Group.";
+ }
+ identity transpHdlc {
+ base iana-interface-type;
+ description
+ "Transp HDLC.";
+ }
+ identity interleave {
+ base iana-interface-type;
+ description
+ "Interleave channel.";
+ }
+ identity fast {
+ base iana-interface-type;
+ description
+ "Fast channel.";
+ }
+
+ identity ip {
+ base iana-interface-type;
+ description
+ "IP (for APPN HPR in IP networks).";
+ }
+ identity docsCableMaclayer {
+ base iana-interface-type;
+ description
+ "CATV Mac Layer.";
+ }
+ identity docsCableDownstream {
+ base iana-interface-type;
+ description
+ "CATV Downstream interface.";
+ }
+ identity docsCableUpstream {
+ base iana-interface-type;
+ description
+ "CATV Upstream interface.";
+ }
+ identity a12MppSwitch {
+ base iana-interface-type;
+ description
+ "Avalon Parallel Processor.";
+ }
+ identity tunnel {
+ base iana-interface-type;
+ description
+ "Encapsulation interface.";
+ }
+ identity coffee {
+ base iana-interface-type;
+ description
+ "Coffee pot.";
+ reference
+ "RFC 2325 - Coffee MIB";
+ }
+ identity ces {
+ base iana-interface-type;
+ description
+ "Circuit Emulation Service.";
+ }
+ identity atmSubInterface {
+ base iana-interface-type;
+ description
+ "ATM Sub Interface.";
+ }
+
+ identity l2vlan {
+ base iana-interface-type;
+ description
+ "Layer 2 Virtual LAN using 802.1Q.";
+ }
+ identity l3ipvlan {
+ base iana-interface-type;
+ description
+ "Layer 3 Virtual LAN using IP.";
+ }
+ identity l3ipxvlan {
+ base iana-interface-type;
+ description
+ "Layer 3 Virtual LAN using IPX.";
+ }
+ identity digitalPowerline {
+ base iana-interface-type;
+ description
+ "IP over Power Lines.";
+ }
+ identity mediaMailOverIp {
+ base iana-interface-type;
+ description
+ "Multimedia Mail over IP.";
+ }
+ identity dtm {
+ base iana-interface-type;
+ description
+ "Dynamic synchronous Transfer Mode.";
+ }
+ identity dcn {
+ base iana-interface-type;
+ description
+ "Data Communications Network.";
+ }
+ identity ipForward {
+ base iana-interface-type;
+ description
+ "IP Forwarding Interface.";
+ }
+ identity msdsl {
+ base iana-interface-type;
+ description
+ "Multi-rate Symmetric DSL.";
+ }
+ identity ieee1394 {
+ base iana-interface-type;
+
+ description
+ "IEEE1394 High Performance Serial Bus.";
+ }
+ identity if-gsn {
+ base iana-interface-type;
+ description
+ "HIPPI-6400.";
+ }
+ identity dvbRccMacLayer {
+ base iana-interface-type;
+ description
+ "DVB-RCC MAC Layer.";
+ }
+ identity dvbRccDownstream {
+ base iana-interface-type;
+ description
+ "DVB-RCC Downstream Channel.";
+ }
+ identity dvbRccUpstream {
+ base iana-interface-type;
+ description
+ "DVB-RCC Upstream Channel.";
+ }
+ identity atmVirtual {
+ base iana-interface-type;
+ description
+ "ATM Virtual Interface.";
+ }
+ identity mplsTunnel {
+ base iana-interface-type;
+ description
+ "MPLS Tunnel Virtual Interface.";
+ }
+ identity srp {
+ base iana-interface-type;
+ description
+ "Spatial Reuse Protocol.";
+ }
+ identity voiceOverAtm {
+ base iana-interface-type;
+ description
+ "Voice over ATM.";
+ }
+ identity voiceOverFrameRelay {
+ base iana-interface-type;
+ description
+ "Voice Over Frame Relay.";
+ }
+ identity idsl {
+ base iana-interface-type;
+ description
+ "Digital Subscriber Loop over ISDN.";
+ }
+ identity compositeLink {
+ base iana-interface-type;
+ description
+ "Avici Composite Link Interface.";
+ }
+ identity ss7SigLink {
+ base iana-interface-type;
+ description
+ "SS7 Signaling Link.";
+ }
+ identity propWirelessP2P {
+ base iana-interface-type;
+ description
+ "Prop. P2P wireless interface.";
+ }
+ identity frForward {
+ base iana-interface-type;
+ description
+ "Frame Forward Interface.";
+ }
+ identity rfc1483 {
+ base iana-interface-type;
+ description
+ "Multiprotocol over ATM AAL5.";
+ reference
+ "RFC 1483 - Multiprotocol Encapsulation over ATM
+ Adaptation Layer 5";
+ }
+ identity usb {
+ base iana-interface-type;
+ description
+ "USB Interface.";
+ }
+ identity ieee8023adLag {
+ base iana-interface-type;
+ description
+ "IEEE 802.3ad Link Aggregate.";
+ }
+ identity bgppolicyaccounting {
+ base iana-interface-type;
+ description
+ "BGP Policy Accounting.";
+ }
+ identity frf16MfrBundle {
+ base iana-interface-type;
+ description
+ "FRF.16 Multilink Frame Relay.";
+ }
+ identity h323Gatekeeper {
+ base iana-interface-type;
+ description
+ "H323 Gatekeeper.";
+ }
+ identity h323Proxy {
+ base iana-interface-type;
+ description
+ "H323 Voice and Video Proxy.";
+ }
+ identity mpls {
+ base iana-interface-type;
+ description
+ "MPLS.";
+ }
+ identity mfSigLink {
+ base iana-interface-type;
+ description
+ "Multi-frequency signaling link.";
+ }
+ identity hdsl2 {
+ base iana-interface-type;
+ description
+ "High Bit-Rate DSL - 2nd generation.";
+ }
+ identity shdsl {
+ base iana-interface-type;
+ description
+ "Multirate HDSL2.";
+ }
+ identity ds1FDL {
+ base iana-interface-type;
+ description
+ "Facility Data Link (4Kbps) on a DS1.";
+ }
+ identity pos {
+ base iana-interface-type;
+ description
+ "Packet over SONET/SDH Interface.";
+ }
+
+
+
+ identity dvbAsiIn {
+ base iana-interface-type;
+ description
+ "DVB-ASI Input.";
+ }
+ identity dvbAsiOut {
+ base iana-interface-type;
+ description
+ "DVB-ASI Output.";
+ }
+ identity plc {
+ base iana-interface-type;
+ description
+ "Power Line Communications.";
+ }
+ identity nfas {
+ base iana-interface-type;
+ description
+ "Non-Facility Associated Signaling.";
+ }
+ identity tr008 {
+ base iana-interface-type;
+ description
+ "TR008.";
+ }
+ identity gr303RDT {
+ base iana-interface-type;
+ description
+ "Remote Digital Terminal.";
+ }
+ identity gr303IDT {
+ base iana-interface-type;
+ description
+ "Integrated Digital Terminal.";
+ }
+ identity isup {
+ base iana-interface-type;
+ description
+ "ISUP.";
+ }
+ identity propDocsWirelessMaclayer {
+ base iana-interface-type;
+ description
+ "Cisco proprietary Maclayer.";
+ }
+
+
+
+ identity propDocsWirelessDownstream {
+ base iana-interface-type;
+ description
+ "Cisco proprietary Downstream.";
+ }
+ identity propDocsWirelessUpstream {
+ base iana-interface-type;
+ description
+ "Cisco proprietary Upstream.";
+ }
+ identity hiperlan2 {
+ base iana-interface-type;
+ description
+ "HIPERLAN Type 2 Radio Interface.";
+ }
+ identity propBWAp2Mp {
+ base iana-interface-type;
+ description
+ "PropBroadbandWirelessAccesspt2Multipt (use of this value
+ for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+ is deprecated, and ieee80216WMAN(237) should be used
+ instead).";
+ }
+ identity sonetOverheadChannel {
+ base iana-interface-type;
+ description
+ "SONET Overhead Channel.";
+ }
+ identity digitalWrapperOverheadChannel {
+ base iana-interface-type;
+ description
+ "Digital Wrapper.";
+ }
+ identity aal2 {
+ base iana-interface-type;
+ description
+ "ATM adaptation layer 2.";
+ }
+ identity radioMAC {
+ base iana-interface-type;
+ description
+ "MAC layer over radio links.";
+ }
+ identity atmRadio {
+ base iana-interface-type;
+ description
+ "ATM over radio links.";
+ }
+ identity imt {
+ base iana-interface-type;
+ description
+ "Inter-Machine Trunks.";
+ }
+ identity mvl {
+ base iana-interface-type;
+ description
+ "Multiple Virtual Lines DSL.";
+ }
+ identity reachDSL {
+ base iana-interface-type;
+ description
+ "Long Reach DSL.";
+ }
+ identity frDlciEndPt {
+ base iana-interface-type;
+ description
+ "Frame Relay DLCI End Point.";
+ }
+ identity atmVciEndPt {
+ base iana-interface-type;
+ description
+ "ATM VCI End Point.";
+ }
+ identity opticalChannel {
+ base iana-interface-type;
+ description
+ "Optical Channel.";
+ }
+ identity opticalTransport {
+ base iana-interface-type;
+ description
+ "Optical Transport.";
+ }
+ identity propAtm {
+ base iana-interface-type;
+ description
+ "Proprietary ATM.";
+ }
+ identity voiceOverCable {
+ base iana-interface-type;
+ description
+ "Voice Over Cable Interface.";
+ }
+
+
+
+ identity infiniband {
+ base iana-interface-type;
+ description
+ "Infiniband.";
+ }
+ identity teLink {
+ base iana-interface-type;
+ description
+ "TE Link.";
+ }
+ identity q2931 {
+ base iana-interface-type;
+ description
+ "Q.2931.";
+ }
+ identity virtualTg {
+ base iana-interface-type;
+ description
+ "Virtual Trunk Group.";
+ }
+ identity sipTg {
+ base iana-interface-type;
+ description
+ "SIP Trunk Group.";
+ }
+ identity sipSig {
+ base iana-interface-type;
+ description
+ "SIP Signaling.";
+ }
+ identity docsCableUpstreamChannel {
+ base iana-interface-type;
+ description
+ "CATV Upstream Channel.";
+ }
+ identity econet {
+ base iana-interface-type;
+ description
+ "Acorn Econet.";
+ }
+ identity pon155 {
+ base iana-interface-type;
+ description
+ "FSAN 155Mb Symetrical PON interface.";
+ }
+
+
+
+ identity pon622 {
+ base iana-interface-type;
+ description
+ "FSAN 622Mb Symetrical PON interface.";
+ }
+ identity bridge {
+ base iana-interface-type;
+ description
+ "Transparent bridge interface.";
+ }
+ identity linegroup {
+ base iana-interface-type;
+ description
+ "Interface common to multiple lines.";
+ }
+ identity voiceEMFGD {
+ base iana-interface-type;
+ description
+ "Voice E&M Feature Group D.";
+ }
+ identity voiceFGDEANA {
+ base iana-interface-type;
+ description
+ "Voice FGD Exchange Access North American.";
+ }
+ identity voiceDID {
+ base iana-interface-type;
+ description
+ "Voice Direct Inward Dialing.";
+ }
+ identity mpegTransport {
+ base iana-interface-type;
+ description
+ "MPEG transport interface.";
+ }
+ identity sixToFour {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "6to4 interface (DEPRECATED).";
+ reference
+ "RFC 4087 - IP Tunnel MIB";
+ }
+ identity gtp {
+ base iana-interface-type;
+ description
+ "GTP (GPRS Tunneling Protocol).";
+ }
+ identity pdnEtherLoop1 {
+ base iana-interface-type;
+ description
+ "Paradyne EtherLoop 1.";
+ }
+ identity pdnEtherLoop2 {
+ base iana-interface-type;
+ description
+ "Paradyne EtherLoop 2.";
+ }
+ identity opticalChannelGroup {
+ base iana-interface-type;
+ description
+ "Optical Channel Group.";
+ }
+ identity homepna {
+ base iana-interface-type;
+ description
+ "HomePNA ITU-T G.989.";
+ }
+ identity gfp {
+ base iana-interface-type;
+ description
+ "Generic Framing Procedure (GFP).";
+ }
+ identity ciscoISLvlan {
+ base iana-interface-type;
+ description
+ "Layer 2 Virtual LAN using Cisco ISL.";
+ }
+ identity actelisMetaLOOP {
+ base iana-interface-type;
+ description
+ "Acteleis proprietary MetaLOOP High Speed Link.";
+ }
+ identity fcipLink {
+ base iana-interface-type;
+ description
+ "FCIP Link.";
+ }
+ identity rpr {
+ base iana-interface-type;
+ description
+ "Resilient Packet Ring Interface Type.";
+ }
+
+
+
+ identity qam {
+ base iana-interface-type;
+ description
+ "RF Qam Interface.";
+ }
+ identity lmp {
+ base iana-interface-type;
+ description
+ "Link Management Protocol.";
+ reference
+ "RFC 4327 - Link Management Protocol (LMP) Management
+ Information Base (MIB)";
+ }
+ identity cblVectaStar {
+ base iana-interface-type;
+ description
+ "Cambridge Broadband Networks Limited VectaStar.";
+ }
+ identity docsCableMCmtsDownstream {
+ base iana-interface-type;
+ description
+ "CATV Modular CMTS Downstream Interface.";
+ }
+ identity adsl2 {
+ base iana-interface-type;
+ status deprecated;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2
+ (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+ instead).";
+ reference
+ "RFC 4706 - Definitions of Managed Objects for Asymmetric
+ Digital Subscriber Line 2 (ADSL2)";
+ }
+ identity macSecControlledIF {
+ base iana-interface-type;
+ description
+ "MACSecControlled.";
+ }
+ identity macSecUncontrolledIF {
+ base iana-interface-type;
+ description
+ "MACSecUncontrolled.";
+ }
+ identity aviciOpticalEther {
+ base iana-interface-type;
+ description
+ "Avici Optical Ethernet Aggregate.";
+ }
+ identity atmbond {
+ base iana-interface-type;
+ description
+ "atmbond.";
+ }
+ identity voiceFGDOS {
+ base iana-interface-type;
+ description
+ "Voice FGD Operator Services.";
+ }
+ identity mocaVersion1 {
+ base iana-interface-type;
+ description
+ "MultiMedia over Coax Alliance (MoCA) Interface
+ as documented in information provided privately to IANA.";
+ }
+ identity ieee80216WMAN {
+ base iana-interface-type;
+ description
+ "IEEE 802.16 WMAN interface.";
+ }
+ identity adsl2plus {
+ base iana-interface-type;
+ description
+ "Asymmetric Digital Subscriber Loop Version 2 -
+ Version 2 Plus and all variants.";
+ }
+ identity dvbRcsMacLayer {
+ base iana-interface-type;
+ description
+ "DVB-RCS MAC Layer.";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ identity dvbTdm {
+ base iana-interface-type;
+ description
+ "DVB Satellite TDM.";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ identity dvbRcsTdma {
+ base iana-interface-type;
+ description
+ "DVB-RCS TDMA.";
+ reference
+ "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+ }
+ identity x86Laps {
+ base iana-interface-type;
+ description
+ "LAPS based on ITU-T X.86/Y.1323.";
+ }
+ identity wwanPP {
+ base iana-interface-type;
+ description
+ "3GPP WWAN.";
+ }
+ identity wwanPP2 {
+ base iana-interface-type;
+ description
+ "3GPP2 WWAN.";
+ }
+ identity voiceEBS {
+ base iana-interface-type;
+ description
+ "Voice P-phone EBS physical interface.";
+ }
+ identity ifPwType {
+ base iana-interface-type;
+ description
+ "Pseudowire interface type.";
+ reference
+ "RFC 5601 - Pseudowire (PW) Management Information Base (MIB)";
+ }
+ identity ilan {
+ base iana-interface-type;
+ description
+ "Internal LAN on a bridge per IEEE 802.1ap.";
+ }
+ identity pip {
+ base iana-interface-type;
+ description
+ "Provider Instance Port on a bridge per IEEE 802.1ah PBB.";
+ }
+ identity aluELP {
+ base iana-interface-type;
+ description
+ "Alcatel-Lucent Ethernet Link Protection.";
+ }
+ identity gpon {
+ base iana-interface-type;
+ description
+ "Gigabit-capable passive optical networks (G-PON) as per
+ ITU-T G.948.";
+ }
+ identity vdsl2 {
+ base iana-interface-type;
+ description
+ "Very high speed digital subscriber line Version 2
+ (as per ITU-T Recommendation G.993.2).";
+ reference
+ "RFC 5650 - Definitions of Managed Objects for Very High
+ Speed Digital Subscriber Line 2 (VDSL2)";
+ }
+ identity capwapDot11Profile {
+ base iana-interface-type;
+ description
+ "WLAN Profile Interface.";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ identity capwapDot11Bss {
+ base iana-interface-type;
+ description
+ "WLAN BSS Interface.";
+ reference
+ "RFC 5834 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Binding MIB for
+ IEEE 802.11";
+ }
+ identity capwapWtpVirtualRadio {
+ base iana-interface-type;
+ description
+ "WTP Virtual Radio Interface.";
+ reference
+ "RFC 5833 - Control and Provisioning of Wireless Access
+ Points (CAPWAP) Protocol Base MIB";
+ }
+ identity bits {
+ base iana-interface-type;
+ description
+ "bitsport.";
+ }
+ identity docsCableUpstreamRfPort {
+ base iana-interface-type;
+ description
+ "DOCSIS CATV Upstream RF Port.";
+ }
+
+
+ identity cableDownstreamRfPort {
+ base iana-interface-type;
+ description
+ "CATV downstream RF Port.";
+ }
+ identity vmwareVirtualNic {
+ base iana-interface-type;
+ description
+ "VMware Virtual Network Interface.";
+ }
+ identity ieee802154 {
+ base iana-interface-type;
+ description
+ "IEEE 802.15.4 WPAN interface.";
+ reference
+ "IEEE 802.15.4-2006";
+ }
+ identity otnOdu {
+ base iana-interface-type;
+ description
+ "OTN Optical Data Unit.";
+ }
+ identity otnOtu {
+ base iana-interface-type;
+ description
+ "OTN Optical channel Transport Unit.";
+ }
+ identity ifVfiType {
+ base iana-interface-type;
+ description
+ "VPLS Forwarding Instance Interface Type.";
+ }
+ identity g9981 {
+ base iana-interface-type;
+ description
+ "G.998.1 bonded interface.";
+ }
+ identity g9982 {
+ base iana-interface-type;
+ description
+ "G.998.2 bonded interface.";
+ }
+ identity g9983 {
+ base iana-interface-type;
+ description
+ "G.998.3 bonded interface.";
+ }
+
+ identity aluEpon {
+ base iana-interface-type;
+ description
+ "Ethernet Passive Optical Networks (E-PON).";
+ }
+ identity aluEponOnu {
+ base iana-interface-type;
+ description
+ "EPON Optical Network Unit.";
+ }
+ identity aluEponPhysicalUni {
+ base iana-interface-type;
+ description
+ "EPON physical User to Network interface.";
+ }
+ identity aluEponLogicalLink {
+ base iana-interface-type;
+ description
+ "The emulation of a point-to-point link over the EPON
+ layer.";
+ }
+ identity aluGponOnu {
+ base iana-interface-type;
+ description
+ "GPON Optical Network Unit.";
+ reference
+ "ITU-T G.984.2";
+ }
+ identity aluGponPhysicalUni {
+ base iana-interface-type;
+ description
+ "GPON physical User to Network interface.";
+ reference
+ "ITU-T G.984.2";
+ }
+ identity vmwareNicTeam {
+ base iana-interface-type;
+ description
+ "VMware NIC Team.";
+ }
+}
diff --git a/tools/lint/examples/ietf-interfaces.yang b/tools/lint/examples/ietf-interfaces.yang
new file mode 100644
index 0000000..ad64425
--- /dev/null
+++ b/tools/lint/examples/ietf-interfaces.yang
@@ -0,0 +1,725 @@
+module ietf-interfaces {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ prefix if;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: Thomas Nadeau
+ <mailto:tnadeau@lucidvision.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "This module contains a collection of YANG definitions for
+ managing network interfaces.
+
+ Copyright (c) 2014 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 7223; see
+ the RFC itself for full legal notices.";
+
+ revision 2014-05-08 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7223: A YANG Data Model for Interface Management";
+ }
+
+ /*
+ * Typedefs
+ */
+
+ typedef interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ configured interfaces.";
+ }
+
+ typedef interface-state-ref {
+ type leafref {
+ path "/if:interfaces-state/if:interface/if:name";
+ }
+ description
+ "This type is used by data models that need to reference
+ the operationally present interfaces.";
+ }
+
+ /*
+ * Identities
+ */
+
+ identity interface-type {
+ description
+ "Base identity from which specific interface types are
+ derived.";
+ }
+
+ /*
+ * Features
+ */
+
+ feature arbitrary-names {
+ description
+ "This feature indicates that the device allows user-controlled
+ interfaces to be named arbitrarily.";
+ }
+ feature pre-provisioning {
+ description
+ "This feature indicates that the device supports
+ pre-provisioning of interface configuration, i.e., it is
+ possible to configure an interface whose physical interface
+ hardware is not present on the device.";
+ }
+
+ feature if-mib {
+ description
+ "This feature indicates that the device implements
+ the IF-MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB";
+ }
+
+ /*
+ * Configuration data nodes
+ */
+
+ container interfaces {
+ description
+ "Interface configuration parameters.";
+
+ list interface {
+ key "name";
+
+ description
+ "The list of configured interfaces on the device.
+
+ The operational state of an interface is available in the
+ /interfaces-state/interface list. If the configuration of a
+ system-controlled interface cannot be used by the system
+ (e.g., the interface hardware present does not match the
+ interface type), then the configuration is not applied to
+ the system-controlled interface shown in the
+ /interfaces-state/interface list. If the configuration
+ of a user-controlled interface cannot be used by the system,
+ the configured interface is not instantiated in the
+ /interfaces-state/interface list.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list /interfaces-state/interface contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ /interfaces-state/interface list, the server MAY reject
+ the request if the implementation does not support
+ pre-provisioning of interfaces or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ If the device supports pre-provisioning of interface
+ configuration, the 'pre-provisioning' feature is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the 'arbitrary-names' feature is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interface-state/interface list.";
+ }
+
+ leaf description {
+ type string;
+ description
+ "A textual description of the interface.
+
+ A server implementation MAY map this leaf to the ifAlias
+ MIB object. Such an implementation needs to use some
+ mechanism to handle the differences in size and characters
+ allowed between this leaf and ifAlias. The definition of
+ such a mechanism is outside the scope of this document.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation to
+
+ decide whether to modify this single leaf in 'startup' or
+ perform an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf type {
+ type identityref {
+ base interface-type;
+ }
+ mandatory true;
+ description
+ "The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf link-up-down-trap-enable {
+ if-feature if-mib;
+ type enumeration {
+ enum enabled {
+ value 1;
+ }
+ enum disabled {
+ value 2;
+ }
+ }
+ description
+ "Controls whether linkUp/linkDown SNMP notifications
+ should be generated for this interface.
+
+ If this node is not configured, the value 'enabled' is
+ operationally used by the server for interfaces that do
+ not operate on top of any other interface (i.e., there are
+ no 'lower-layer-if' entries), and 'disabled' otherwise.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifLinkUpDownTrapEnable";
+ }
+ }
+ }
+
+ /*
+ * Operational state data nodes
+ */
+
+ container interfaces-state {
+ config false;
+ description
+ "Data nodes for the operational state of interfaces.";
+
+ list interface {
+ key "name";
+
+
+
+
+
+ description
+ "The list of interfaces on the device.
+
+ System-controlled interfaces created by the system are
+ always present in this list, whether they are configured or
+ not.";
+
+ leaf name {
+ type string;
+ description
+ "The name of the interface.
+
+ A server implementation MAY map this leaf to the ifName
+ MIB object. Such an implementation needs to use some
+ mechanism to handle the differences in size and characters
+ allowed between this leaf and ifName. The definition of
+ such a mechanism is outside the scope of this document.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifName";
+ }
+
+ leaf type {
+ type identityref {
+ base interface-type;
+ }
+ mandatory true;
+ description
+ "The type of the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf admin-status {
+ if-feature if-mib;
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+
+
+
+ enum testing {
+ value 3;
+ description
+ "In some test mode.";
+ }
+ }
+ mandatory true;
+ description
+ "The desired state of the interface.
+
+ This leaf has the same read semantics as ifAdminStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum up {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum down {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum testing {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum unknown {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum dormant {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum not-present {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum lower-layer-down {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ mandatory true;
+ description
+ "The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:date-and-time;
+ description
+ "The time the interface entered its current operational
+ state. If the current state was entered prior to the
+ last re-initialization of the local network management
+ subsystem, then this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ leaf if-index {
+ if-feature if-mib;
+ type int32 {
+ range "1..2147483647";
+ }
+ mandatory true;
+ description
+ "The ifIndex value for the ifEntry represented by this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifIndex";
+ }
+
+ leaf phys-address {
+ type yang:phys-address;
+ description
+ "The interface's address at its protocol sub-layer. For
+ example, for an 802.x interface, this object normally
+ contains a Media Access Control (MAC) address. The
+ interface's media-specific modules must define the bit
+
+
+ and byte ordering and the format of the value of this
+ object. For interfaces that do not have such an address
+ (e.g., a serial line), this node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+ }
+
+ leaf-list higher-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered on top of this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf-list lower-layer-if {
+ type interface-state-ref;
+ description
+ "A list of references to interfaces layered underneath this
+ interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifStackTable";
+ }
+
+ leaf speed {
+ type yang:gauge64;
+ units "bits/second";
+ description
+ "An estimate of the interface's current bandwidth in bits
+ per second. For interfaces that do not vary in
+ bandwidth or for those where no accurate estimation can
+ be made, this node should contain the nominal bandwidth.
+ For interfaces that have no concept of bandwidth, this
+ node is not present.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifSpeed, ifHighSpeed";
+ }
+
+
+
+
+
+
+
+
+
+ container statistics {
+ description
+ "A collection of interface-related statistics objects.";
+
+ leaf discontinuity-time {
+ type yang:date-and-time;
+ mandatory true;
+ description
+ "The time on the most recent occasion at which any one or
+ more of this interface's counters suffered a
+ discontinuity. If no such discontinuities have occurred
+ since the last re-initialization of the local management
+ subsystem, then this node contains the time the local
+ management subsystem re-initialized itself.";
+ }
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+
+
+
+
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were addressed to a multicast
+ address at this sub-layer. For a MAC-layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+
+ leaf in-discards {
+ type yang:counter32;
+ description
+ "The number of inbound packets that were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+
+
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+
+ leaf in-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of packets
+ received via the interface that were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing, the number of
+ transmission units received via the interface that were
+ discarded because of an unknown or unsupported protocol.
+ For any interface that does not support protocol
+ multiplexing, this counter is not present.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+
+
+
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and that were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and that were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+
+
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "The total number of packets that higher-level protocols
+ requested be transmitted, and that were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC-layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+
+ leaf out-discards {
+ type yang:counter32;
+ description
+ "The number of outbound packets that were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+
+ leaf out-errors {
+ type yang:counter32;
+ description
+ "For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+
+
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+ }
+ }
+ }
+}
diff --git a/tools/lint/examples/ietf-ip.yang b/tools/lint/examples/ietf-ip.yang
new file mode 100644
index 0000000..1499120
--- /dev/null
+++ b/tools/lint/examples/ietf-ip.yang
@@ -0,0 +1,758 @@
+module ietf-ip {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
+ prefix ip;
+
+ import ietf-interfaces {
+ prefix if;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ WG Chair: Thomas Nadeau
+ <mailto:tnadeau@lucidvision.com>
+
+ WG Chair: Juergen Schoenwaelder
+ <mailto:j.schoenwaelder@jacobs-university.de>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+
+
+
+
+
+
+
+
+
+ description
+ "This module contains a collection of YANG definitions for
+ configuring IP implementations.
+
+ Copyright (c) 2014 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 7277; see
+ the RFC itself for full legal notices.";
+
+ revision 2014-06-16 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 7277: A YANG Data Model for IP Management";
+ }
+
+ /*
+
+ * Features
+ */
+
+ feature ipv4-non-contiguous-netmasks {
+ description
+ "Indicates support for configuring non-contiguous
+ subnet masks.";
+ }
+
+ feature ipv6-privacy-autoconf {
+ description
+ "Indicates support for Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6.";
+ reference
+ "RFC 4941: Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6";
+ }
+
+
+
+
+
+ /*
+ * Typedefs
+ */
+
+ typedef ip-address-origin {
+ type enumeration {
+ enum other {
+ description
+ "None of the following.";
+ }
+ enum static {
+ description
+ "Indicates that the address has been statically
+ configured - for example, using NETCONF or a Command Line
+ Interface.";
+ }
+ enum dhcp {
+ description
+ "Indicates an address that has been assigned to this
+ system by a DHCP server.";
+ }
+ enum link-layer {
+ description
+ "Indicates an address created by IPv6 stateless
+ autoconfiguration that embeds a link-layer address in its
+ interface identifier.";
+ }
+ enum random {
+ description
+ "Indicates an address chosen by the system at
+
+ random, e.g., an IPv4 address within 169.254/16, an
+ RFC 4941 temporary address, or an RFC 7217 semantically
+ opaque address.";
+ reference
+ "RFC 4941: Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6
+ RFC 7217: A Method for Generating Semantically Opaque
+ Interface Identifiers with IPv6 Stateless
+ Address Autoconfiguration (SLAAC)";
+ }
+ }
+ description
+ "The origin of an address.";
+ }
+
+
+
+ typedef neighbor-origin {
+ type enumeration {
+ enum other {
+ description
+ "None of the following.";
+ }
+ enum static {
+ description
+ "Indicates that the mapping has been statically
+ configured - for example, using NETCONF or a Command Line
+ Interface.";
+ }
+ enum dynamic {
+ description
+ "Indicates that the mapping has been dynamically resolved
+ using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery
+ protocol.";
+ }
+ }
+ description
+ "The origin of a neighbor entry.";
+ }
+
+ /*
+ * Configuration data nodes
+ */
+
+ augment "/if:interfaces/if:interface" {
+ description
+ "Parameters for configuring IP on interfaces.
+
+ If an interface is not capable of running IP, the server
+ must not allow the client to configure these parameters.";
+
+ container ipv4 {
+ presence
+ "Enables IPv4 unless the 'enabled' leaf
+ (which defaults to 'true') is set to 'false'";
+ description
+ "Parameters for the IPv4 address family.";
+
+
+
+
+
+
+
+
+ leaf enabled {
+ type boolean;
+ default true;
+ description
+ "Controls whether IPv4 is enabled or disabled on this
+ interface. When IPv4 is enabled, this interface is
+ connected to an IPv4 stack, and the interface can send
+ and receive IPv4 packets.";
+ }
+ leaf forwarding {
+ type boolean;
+ default false;
+ description
+ "Controls IPv4 packet forwarding of datagrams received by,
+ but not addressed to, this interface. IPv4 routers
+ forward datagrams. IPv4 hosts do not (except those
+ source-routed via the host).";
+ }
+ leaf mtu {
+ type uint16 {
+ range "68..max";
+ }
+ units octets;
+ description
+ "The size, in octets, of the largest IPv4 packet that the
+ interface will send and receive.
+
+ The server may restrict the allowed values for this leaf,
+ depending on the interface's type.
+
+ If this leaf is not configured, the operationally used MTU
+ depends on the interface's type.";
+ reference
+ "RFC 791: Internet Protocol";
+ }
+ list address {
+ key "ip";
+ description
+ "The list of configured IPv4 addresses on the interface.";
+
+ leaf ip {
+ type inet:ipv4-address-no-zone;
+ description
+ "The IPv4 address on the interface.";
+ }
+
+
+
+ choice subnet {
+ mandatory true;
+ description
+ "The subnet can be specified as a prefix-length, or,
+ if the server supports non-contiguous netmasks, as
+ a netmask.";
+ leaf prefix-length {
+ type uint8 {
+ range "0..32";
+ }
+ description
+ "The length of the subnet prefix.";
+ }
+ leaf netmask {
+ if-feature ipv4-non-contiguous-netmasks;
+ type yang:dotted-quad;
+ description
+ "The subnet specified as a netmask.";
+ }
+ }
+ }
+ list neighbor {
+ key "ip";
+ description
+ "A list of mappings from IPv4 addresses to
+ link-layer addresses.
+
+ Entries in this list are used as static entries in the
+ ARP Cache.";
+ reference
+ "RFC 826: An Ethernet Address Resolution Protocol";
+
+ leaf ip {
+ type inet:ipv4-address-no-zone;
+ description
+ "The IPv4 address of the neighbor node.";
+ }
+ leaf link-layer-address {
+ type yang:phys-address;
+ mandatory true;
+ description
+ "The link-layer address of the neighbor node.";
+ }
+ }
+
+ }
+
+
+ container ipv6 {
+ presence
+ "Enables IPv6 unless the 'enabled' leaf
+ (which defaults to 'true') is set to 'false'";
+ description
+ "Parameters for the IPv6 address family.";
+
+ leaf enabled {
+ type boolean;
+ default true;
+ description
+ "Controls whether IPv6 is enabled or disabled on this
+ interface. When IPv6 is enabled, this interface is
+ connected to an IPv6 stack, and the interface can send
+ and receive IPv6 packets.";
+ }
+ leaf forwarding {
+ type boolean;
+ default false;
+ description
+ "Controls IPv6 packet forwarding of datagrams received by,
+ but not addressed to, this interface. IPv6 routers
+ forward datagrams. IPv6 hosts do not (except those
+ source-routed via the host).";
+ reference
+ "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+ Section 6.2.1, IsRouter";
+ }
+ leaf mtu {
+ type uint32 {
+ range "1280..max";
+ }
+ units octets;
+ description
+ "The size, in octets, of the largest IPv6 packet that the
+ interface will send and receive.
+
+ The server may restrict the allowed values for this leaf,
+ depending on the interface's type.
+
+ If this leaf is not configured, the operationally used MTU
+ depends on the interface's type.";
+ reference
+ "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ Section 5";
+ }
+
+
+ list address {
+ key "ip";
+ description
+ "The list of configured IPv6 addresses on the interface.";
+
+ leaf ip {
+ type inet:ipv6-address-no-zone;
+ description
+ "The IPv6 address on the interface.";
+ }
+ leaf prefix-length {
+ type uint8 {
+ range "0..128";
+ }
+ mandatory true;
+ description
+ "The length of the subnet prefix.";
+ }
+ }
+ list neighbor {
+ key "ip";
+ description
+ "A list of mappings from IPv6 addresses to
+ link-layer addresses.
+
+ Entries in this list are used as static entries in the
+ Neighbor Cache.";
+ reference
+ "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+ leaf ip {
+ type inet:ipv6-address-no-zone;
+ description
+ "The IPv6 address of the neighbor node.";
+ }
+ leaf link-layer-address {
+ type yang:phys-address;
+ mandatory true;
+ description
+ "The link-layer address of the neighbor node.";
+ }
+ }
+
+
+
+
+
+
+ leaf dup-addr-detect-transmits {
+ type uint32;
+ default 1;
+ description
+ "The number of consecutive Neighbor Solicitation messages
+ sent while performing Duplicate Address Detection on a
+ tentative address. A value of zero indicates that
+ Duplicate Address Detection is not performed on
+ tentative addresses. A value of one indicates a single
+ transmission with no follow-up retransmissions.";
+ reference
+ "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+ }
+ container autoconf {
+ description
+ "Parameters to control the autoconfiguration of IPv6
+ addresses, as described in RFC 4862.";
+ reference
+ "RFC 4862: IPv6 Stateless Address Autoconfiguration";
+
+ leaf create-global-addresses {
+ type boolean;
+ default true;
+ description
+ "If enabled, the host creates global addresses as
+ described in RFC 4862.";
+ reference
+ "RFC 4862: IPv6 Stateless Address Autoconfiguration
+ Section 5.5";
+ }
+ leaf create-temporary-addresses {
+ if-feature ipv6-privacy-autoconf;
+ type boolean;
+ default false;
+ description
+ "If enabled, the host creates temporary addresses as
+ described in RFC 4941.";
+ reference
+ "RFC 4941: Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6";
+ }
+
+
+
+
+
+
+
+ leaf temporary-valid-lifetime {
+ if-feature ipv6-privacy-autoconf;
+ type uint32;
+ units "seconds";
+ default 604800;
+ description
+ "The time period during which the temporary address
+ is valid.";
+ reference
+ "RFC 4941: Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6
+ - TEMP_VALID_LIFETIME";
+ }
+ leaf temporary-preferred-lifetime {
+ if-feature ipv6-privacy-autoconf;
+ type uint32;
+ units "seconds";
+ default 86400;
+ description
+ "The time period during which the temporary address is
+ preferred.";
+ reference
+ "RFC 4941: Privacy Extensions for Stateless Address
+ Autoconfiguration in IPv6
+ - TEMP_PREFERRED_LIFETIME";
+ }
+ }
+ }
+ }
+
+ /*
+ * Operational state data nodes
+ */
+
+ augment "/if:interfaces-state/if:interface" {
+ description
+ "Data nodes for the operational state of IP on interfaces.";
+
+ container ipv4 {
+ presence "Present if IPv4 is enabled on this interface";
+ config false;
+ description
+ "Interface-specific parameters for the IPv4 address family.";
+
+
+
+
+
+ leaf forwarding {
+ type boolean;
+ description
+ "Indicates whether IPv4 packet forwarding is enabled or
+ disabled on this interface.";
+ }
+ leaf mtu {
+ type uint16 {
+ range "68..max";
+ }
+ units octets;
+ description
+ "The size, in octets, of the largest IPv4 packet that the
+ interface will send and receive.";
+ reference
+ "RFC 791: Internet Protocol";
+ }
+ list address {
+ key "ip";
+ description
+ "The list of IPv4 addresses on the interface.";
+
+ leaf ip {
+ type inet:ipv4-address-no-zone;
+ description
+ "The IPv4 address on the interface.";
+ }
+ choice subnet {
+ description
+ "The subnet can be specified as a prefix-length, or,
+ if the server supports non-contiguous netmasks, as
+ a netmask.";
+ leaf prefix-length {
+ type uint8 {
+ range "0..32";
+ }
+ description
+ "The length of the subnet prefix.";
+ }
+ leaf netmask {
+ if-feature ipv4-non-contiguous-netmasks;
+ type yang:dotted-quad;
+ description
+ "The subnet specified as a netmask.";
+ }
+ }
+
+
+ leaf origin {
+ type ip-address-origin;
+ description
+ "The origin of this address.";
+ }
+ }
+ list neighbor {
+ key "ip";
+ description
+ "A list of mappings from IPv4 addresses to
+ link-layer addresses.
+
+ This list represents the ARP Cache.";
+ reference
+ "RFC 826: An Ethernet Address Resolution Protocol";
+
+ leaf ip {
+ type inet:ipv4-address-no-zone;
+ description
+ "The IPv4 address of the neighbor node.";
+ }
+ leaf link-layer-address {
+ type yang:phys-address;
+ description
+ "The link-layer address of the neighbor node.";
+ }
+ leaf origin {
+ type neighbor-origin;
+ description
+ "The origin of this neighbor entry.";
+ }
+ }
+
+ }
+
+ container ipv6 {
+ presence "Present if IPv6 is enabled on this interface";
+ config false;
+ description
+ "Parameters for the IPv6 address family.";
+
+
+
+
+
+
+
+
+ leaf forwarding {
+ type boolean;
+ default false;
+ description
+ "Indicates whether IPv6 packet forwarding is enabled or
+ disabled on this interface.";
+ reference
+ "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+ Section 6.2.1, IsRouter";
+ }
+ leaf mtu {
+ type uint32 {
+ range "1280..max";
+ }
+ units octets;
+ description
+ "The size, in octets, of the largest IPv6 packet that the
+ interface will send and receive.";
+ reference
+ "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+ Section 5";
+ }
+ list address {
+ key "ip";
+ description
+ "The list of IPv6 addresses on the interface.";
+
+ leaf ip {
+ type inet:ipv6-address-no-zone;
+ description
+ "The IPv6 address on the interface.";
+ }
+ leaf prefix-length {
+ type uint8 {
+ range "0..128";
+ }
+ mandatory true;
+ description
+ "The length of the subnet prefix.";
+ }
+ leaf origin {
+ type ip-address-origin;
+ description
+ "The origin of this address.";
+ }
+
+
+
+ leaf status {
+ type enumeration {
+ enum preferred {
+ description
+ "This is a valid address that can appear as the
+ destination or source address of a packet.";
+ }
+ enum deprecated {
+ description
+ "This is a valid but deprecated address that should
+ no longer be used as a source address in new
+ communications, but packets addressed to such an
+ address are processed as expected.";
+ }
+ enum invalid {
+ description
+ "This isn't a valid address, and it shouldn't appear
+ as the destination or source address of a packet.";
+ }
+ enum inaccessible {
+ description
+ "The address is not accessible because the interface
+ to which this address is assigned is not
+ operational.";
+ }
+ enum unknown {
+ description
+ "The status cannot be determined for some reason.";
+ }
+ enum tentative {
+ description
+ "The uniqueness of the address on the link is being
+ verified. Addresses in this state should not be
+ used for general communication and should only be
+ used to determine the uniqueness of the address.";
+ }
+ enum duplicate {
+ description
+ "The address has been determined to be non-unique on
+ the link and so must not be used.";
+ }
+
+
+
+
+
+
+
+ enum optimistic {
+ description
+ "The address is available for use, subject to
+ restrictions, while its uniqueness on a link is
+ being verified.";
+ }
+ }
+ description
+ "The status of an address. Most of the states correspond
+ to states from the IPv6 Stateless Address
+ Autoconfiguration protocol.";
+ reference
+ "RFC 4293: Management Information Base for the
+ Internet Protocol (IP)
+ - IpAddressStatusTC
+ RFC 4862: IPv6 Stateless Address Autoconfiguration";
+ }
+ }
+ list neighbor {
+ key "ip";
+ description
+ "A list of mappings from IPv6 addresses to
+ link-layer addresses.
+
+ This list represents the Neighbor Cache.";
+ reference
+ "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
+
+ leaf ip {
+ type inet:ipv6-address-no-zone;
+ description
+ "The IPv6 address of the neighbor node.";
+ }
+ leaf link-layer-address {
+ type yang:phys-address;
+ description
+ "The link-layer address of the neighbor node.";
+ }
+ leaf origin {
+ type neighbor-origin;
+ description
+ "The origin of this neighbor entry.";
+ }
+ leaf is-router {
+ type empty;
+ description
+ "Indicates that the neighbor node acts as a router.";
+ }
+ leaf state {
+ type enumeration {
+ enum incomplete {
+ description
+ "Address resolution is in progress, and the link-layer
+ address of the neighbor has not yet been
+ determined.";
+ }
+ enum reachable {
+ description
+ "Roughly speaking, the neighbor is known to have been
+ reachable recently (within tens of seconds ago).";
+ }
+ enum stale {
+ description
+ "The neighbor is no longer known to be reachable, but
+ until traffic is sent to the neighbor no attempt
+ should be made to verify its reachability.";
+ }
+ enum delay {
+ description
+ "The neighbor is no longer known to be reachable, and
+ traffic has recently been sent to the neighbor.
+ Rather than probe the neighbor immediately, however,
+ delay sending probes for a short while in order to
+ give upper-layer protocols a chance to provide
+ reachability confirmation.";
+ }
+ enum probe {
+ description
+ "The neighbor is no longer known to be reachable, and
+ unicast Neighbor Solicitation probes are being sent
+ to verify reachability.";
+ }
+ }
+ description
+ "The Neighbor Unreachability Detection state of this
+ entry.";
+ reference
+ "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
+ Section 7.3.2";
+ }
+ }
+ }
+ }
+}
diff --git a/tools/lint/examples/ietf-netconf-acm-when.yang b/tools/lint/examples/ietf-netconf-acm-when.yang
new file mode 100644
index 0000000..df8f801
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when.yang
@@ -0,0 +1,412 @@
+module ietf-netconf-acm-when2 {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
+ prefix nacm;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+
+ WG Chair: Bert Wijnen
+ <mailto:bertietf@bwijnen.net>
+
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+ description
+ "NETCONF Access Control Model.
+
+ Copyright (c) 2012 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD
+ License set forth in Section 4.c of the IETF Trust's
+ Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6536; see
+ the RFC itself for full legal notices.";
+
+ revision 2012-02-22 {
+ description
+ "Initial version";
+ reference
+ "RFC 6536: Network Configuration Protocol (NETCONF)
+ Access Control Model";
+ }
+
+ extension default-deny-write {
+ description
+ "Used to indicate that the data model node
+ represents a sensitive security system parameter.
+
+ If present, and the NACM module is enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), the NETCONF server
+ will only allow the designated 'recovery session' to have
+ write access to the node. An explicit access control rule is
+ required for all other users.
+
+ The 'default-deny-write' extension MAY appear within a data
+ definition statement. It is ignored otherwise.";
+ }
+
+ extension default-deny-all {
+ description
+ "Used to indicate that the data model node
+ controls a very sensitive security system parameter.
+
+ If present, and the NACM module is enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), the NETCONF server
+ will only allow the designated 'recovery session' to have
+ read, write, or execute access to the node. An explicit
+ access control rule is required for all other users.
+
+ The 'default-deny-all' extension MAY appear within a data
+ definition statement, 'rpc' statement, or 'notification'
+ statement. It is ignored otherwise.";
+ }
+
+ typedef user-name-type {
+ type string {
+ length "1..max";
+ }
+ description
+ "General Purpose Username string.";
+ }
+
+ typedef matchall-string-type {
+ type string {
+ pattern "\\*";
+ }
+ description
+ "The string containing a single asterisk '*' is used
+ to conceptually represent all possible values
+ for the particular leaf using this data type.";
+ }
+
+ typedef access-operations-type {
+ type bits {
+ bit create {
+ description
+ "Any protocol operation that creates a
+ new data node.";
+ }
+ bit read {
+ description
+ "Any protocol operation or notification that
+ returns the value of a data node.";
+ }
+ bit update {
+ description
+ "Any protocol operation that alters an existing
+ data node.";
+ }
+ bit delete {
+ description
+ "Any protocol operation that removes a data node.";
+ }
+ bit exec {
+ description
+ "Execution access to the specified protocol operation.";
+ }
+ }
+ description
+ "NETCONF Access Operation.";
+ }
+
+ typedef group-name-type {
+ type string {
+ length "1..max";
+ pattern "[^\\*].*";
+ }
+ description
+ "Name of administrative group to which
+ users can be assigned.";
+ }
+
+ typedef action-type {
+ type enumeration {
+ enum "permit" {
+ description
+ "Requested action is permitted.";
+ }
+ enum "deny" {
+ description
+ "Requested action is denied.";
+ }
+ }
+ description
+ "Action taken by the server when a particular
+ rule matches.";
+ }
+
+ typedef node-instance-identifier {
+ type yang:xpath1.0;
+ description
+ "Path expression used to represent a special
+ data node instance identifier string.
+
+ A node-instance-identifier value is an
+ unrestricted YANG instance-identifier expression.
+ All the same rules as an instance-identifier apply
+ except predicates for keys are optional. If a key
+ predicate is missing, then the node-instance-identifier
+ represents all possible server instances for that key.
+
+ This XPath expression is evaluated in the following context:
+
+ o The set of namespace declarations are those in scope on
+ the leaf element where this type is used.
+
+ o The set of variable bindings contains one variable,
+ 'USER', which contains the name of the user of the current
+ session.
+
+ o The function library is the core function library, but
+ note that due to the syntax restrictions of an
+ instance-identifier, no functions are allowed.
+
+ o The context node is the root node in the data tree.";
+ }
+
+ container nacm {
+ nacm:default-deny-all;
+ description
+ "Parameters for NETCONF Access Control Model.";
+ leaf enable-nacm {
+ type boolean;
+ default "true";
+ description
+ "Enables or disables all NETCONF access control
+ enforcement. If 'true', then enforcement
+ is enabled. If 'false', then enforcement
+ is disabled.";
+ }
+ leaf read-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether read access is granted if
+ no appropriate rule is found for a
+ particular read request.";
+ }
+ leaf write-default {
+ type action-type;
+ default "deny";
+ description
+ "Controls whether create, update, or delete access
+ is granted if no appropriate rule is found for a
+ particular write request.";
+ }
+ leaf exec-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether exec access is granted if no appropriate
+ rule is found for a particular protocol operation request.";
+ }
+ leaf enable-external-groups {
+ type boolean;
+ default "true";
+ description
+ "Controls whether the server uses the groups reported by the
+ NETCONF transport layer when it assigns the user to a set of
+ NACM groups. If this leaf has the value 'false', any group
+ names reported by the transport layer are ignored by the
+ server.";
+ }
+ leaf denied-operations {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request was denied.";
+ }
+ leaf denied-data-writes {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ when "../denied-operations > 0";
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request to alter
+ a configuration datastore was denied.";
+ }
+ leaf denied-notifications {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that
+ a notification was dropped for a subscription because
+ access to the event type was denied.";
+ }
+ container groups {
+ description
+ "NETCONF Access Control Groups.";
+ list group {
+ key "name";
+ description
+ "One NACM Group Entry. This list will only contain
+ configured entries, not any entries learned from
+ any transport protocols.";
+ leaf name {
+ type group-name-type;
+ description
+ "Group name associated with this entry.";
+ }
+ leaf-list user-name {
+ type user-name-type;
+ description
+ "Each entry identifies the username of
+ a member of the group associated with
+ this entry.";
+ }
+ }
+ }
+ list rule-list {
+ key "name";
+ ordered-by user;
+ description
+ "An ordered collection of access control rules.";
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule-list.";
+ }
+ leaf-list group {
+ type union {
+ type matchall-string-type;
+ type group-name-type;
+ }
+ description
+ "List of administrative groups that will be
+ assigned the associated access rights
+ defined by the 'rule' list.
+
+ The string '*' indicates that all groups apply to the
+ entry.";
+ }
+ list rule {
+ key "name";
+ ordered-by user;
+ description
+ "One access control rule.
+
+ Rules are processed in user-defined order until a match is
+ found. A rule matches if 'module-name', 'rule-type', and
+ 'access-operations' match the request. If a rule
+ matches, the 'action' leaf determines if access is granted
+ or not.";
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule.";
+ }
+ leaf module-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ default "*";
+ description
+ "Name of the module associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ object being accessed is defined in the module with the
+ specified module name.";
+ }
+ choice rule-type {
+ description
+ "This choice matches if all leafs present in the rule
+ match the request. If no leafs are present, the
+ choice matches all requests.";
+ case protocol-operation {
+ leaf rpc-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if
+ its value equals the requested protocol operation
+ name.";
+ }
+ }
+ case notification {
+ leaf notification-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if its
+ value equals the requested notification name.";
+ }
+ }
+ case data-node {
+ leaf path {
+ type node-instance-identifier;
+ mandatory true;
+ description
+ "Data Node Instance Identifier associated with the
+ data node controlled by this rule.
+
+ Configuration data or state data instance
+ identifiers start with a top-level data node. A
+ complete instance identifier is required for this
+ type of path value.
+
+ The special value '/' refers to all possible
+ datastore contents.";
+ }
+ }
+ }
+ leaf access-operations {
+ type union {
+ type matchall-string-type;
+ type access-operations-type;
+ }
+ default "*";
+ description
+ "Access operations associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ bit corresponding to the requested operation is set.";
+ }
+ leaf action {
+ type action-type;
+ mandatory true;
+ description
+ "The access control action associated with the
+ rule. If a rule is determined to match a
+ particular request, then this object is used
+ to determine whether to permit or deny the
+ request.";
+ }
+ leaf comment {
+ type string;
+ description
+ "A textual description of the access rule.";
+ }
+ }
+ }
+ }
+}
diff --git a/tools/lint/examples/ietf-netconf-acm-when.yin b/tools/lint/examples/ietf-netconf-acm-when.yin
new file mode 100644
index 0000000..cbff758
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when.yin
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types" name="ietf-netconf-acm-when">
+ <namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
+ <prefix value="nacm"/>
+ <import module="ietf-yang-types">
+ <prefix value="yang"/>
+ </import>
+ <organization>
+ <text>IETF NETCONF (Network Configuration) Working Group</text>
+ </organization>
+ <contact>
+ <text>WG Web: <http://tools.ietf.org/wg/netconf/>
+WG List: <mailto:netconf@ietf.org>
+
+WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+
+WG Chair: Bert Wijnen
+ <mailto:bertietf@bwijnen.net>
+
+Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com></text>
+ </contact>
+ <description>
+ <text>NETCONF Access Control Model.
+
+Copyright (c) 2012 IETF Trust and the persons identified as
+authors of the code. All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, is permitted pursuant to, and subject
+to the license terms contained in, the Simplified BSD
+License set forth in Section 4.c of the IETF Trust's
+Legal Provisions Relating to IETF Documents
+(http://trustee.ietf.org/license-info).
+
+This version of this YANG module is part of RFC 6536; see
+the RFC itself for full legal notices.</text>
+ </description>
+ <revision date="2012-02-22">
+ <description>
+ <text>Initial version</text>
+ </description>
+ <reference>
+ <text>RFC 6536: Network Configuration Protocol (NETCONF)
+ Access Control Model</text>
+ </reference>
+ </revision>
+ <extension name="default-deny-write">
+ <description>
+ <text>Used to indicate that the data model node
+represents a sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+write access to the node. An explicit access control rule is
+required for all other users.
+
+The 'default-deny-write' extension MAY appear within a data
+definition statement. It is ignored otherwise.</text>
+ </description>
+ </extension>
+ <extension name="default-deny-all">
+ <description>
+ <text>Used to indicate that the data model node
+controls a very sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+read, write, or execute access to the node. An explicit
+access control rule is required for all other users.
+
+The 'default-deny-all' extension MAY appear within a data
+definition statement, 'rpc' statement, or 'notification'
+statement. It is ignored otherwise.</text>
+ </description>
+ </extension>
+ <typedef name="user-name-type">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>General Purpose Username string.</text>
+ </description>
+ </typedef>
+ <typedef name="matchall-string-type">
+ <type name="string">
+ <pattern value="\*"/>
+ </type>
+ <description>
+ <text>The string containing a single asterisk '*' is used
+to conceptually represent all possible values
+for the particular leaf using this data type.</text>
+ </description>
+ </typedef>
+ <typedef name="access-operations-type">
+ <type name="bits">
+ <bit name="create">
+ <description>
+ <text>Any protocol operation that creates a
+new data node.</text>
+ </description>
+ </bit>
+ <bit name="read">
+ <description>
+ <text>Any protocol operation or notification that
+returns the value of a data node.</text>
+ </description>
+ </bit>
+ <bit name="update">
+ <description>
+ <text>Any protocol operation that alters an existing
+data node.</text>
+ </description>
+ </bit>
+ <bit name="delete">
+ <description>
+ <text>Any protocol operation that removes a data node.</text>
+ </description>
+ </bit>
+ <bit name="exec">
+ <description>
+ <text>Execution access to the specified protocol operation.</text>
+ </description>
+ </bit>
+ </type>
+ <description>
+ <text>NETCONF Access Operation.</text>
+ </description>
+ </typedef>
+ <typedef name="group-name-type">
+ <type name="string">
+ <length value="1..max"/>
+ <pattern value="[^\*].*"/>
+ </type>
+ <description>
+ <text>Name of administrative group to which
+users can be assigned.</text>
+ </description>
+ </typedef>
+ <typedef name="action-type">
+ <type name="enumeration">
+ <enum name="permit">
+ <description>
+ <text>Requested action is permitted.</text>
+ </description>
+ </enum>
+ <enum name="deny">
+ <description>
+ <text>Requested action is denied.</text>
+ </description>
+ </enum>
+ </type>
+ <description>
+ <text>Action taken by the server when a particular
+rule matches.</text>
+ </description>
+ </typedef>
+ <typedef name="node-instance-identifier">
+ <type name="yang:xpath1.0"/>
+ <description>
+ <text>Path expression used to represent a special
+data node instance identifier string.
+
+A node-instance-identifier value is an
+unrestricted YANG instance-identifier expression.
+All the same rules as an instance-identifier apply
+except predicates for keys are optional. If a key
+predicate is missing, then the node-instance-identifier
+represents all possible server instances for that key.
+
+This XPath expression is evaluated in the following context:
+
+ o The set of namespace declarations are those in scope on
+ the leaf element where this type is used.
+
+ o The set of variable bindings contains one variable,
+ 'USER', which contains the name of the user of the current
+ session.
+
+ o The function library is the core function library, but
+ note that due to the syntax restrictions of an
+ instance-identifier, no functions are allowed.
+
+ o The context node is the root node in the data tree.</text>
+ </description>
+ </typedef>
+ <container name="nacm">
+ <nacm:default-deny-all/>
+ <description>
+ <text>Parameters for NETCONF Access Control Model.</text>
+ </description>
+ <leaf name="enable-nacm">
+ <type name="boolean"/>
+ <default value="true"/>
+ <description>
+ <text>Enables or disables all NETCONF access control
+enforcement. If 'true', then enforcement
+is enabled. If 'false', then enforcement
+is disabled.</text>
+ </description>
+ </leaf>
+ <leaf name="read-default">
+ <type name="action-type"/>
+ <default value="permit"/>
+ <description>
+ <text>Controls whether read access is granted if
+no appropriate rule is found for a
+particular read request.</text>
+ </description>
+ </leaf>
+ <leaf name="write-default">
+ <type name="action-type"/>
+ <default value="deny"/>
+ <description>
+ <text>Controls whether create, update, or delete access
+is granted if no appropriate rule is found for a
+particular write request.</text>
+ </description>
+ </leaf>
+ <leaf name="exec-default">
+ <type name="action-type"/>
+ <default value="permit"/>
+ <description>
+ <text>Controls whether exec access is granted if no appropriate
+rule is found for a particular protocol operation request.</text>
+ </description>
+ </leaf>
+ <leaf name="enable-external-groups">
+ <type name="boolean"/>
+ <default value="true"/>
+ <description>
+ <text>Controls whether the server uses the groups reported by the
+NETCONF transport layer when it assigns the user to a set of
+NACM groups. If this leaf has the value 'false', any group
+names reported by the transport layer are ignored by the
+server.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-operations">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Number of times since the server last restarted that a
+protocol operation request was denied.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-data-writes">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <when value="../denied-operations > 0"/>
+ <description>
+ <text>Number of times since the server last restarted that a
+protocol operation request to alter
+a configuration datastore was denied.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-notifications">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Number of times since the server last restarted that
+a notification was dropped for a subscription because
+access to the event type was denied.</text>
+ </description>
+ </leaf>
+ <container name="groups">
+ <description>
+ <text>NETCONF Access Control Groups.</text>
+ </description>
+ <list name="group">
+ <key value="name"/>
+ <description>
+ <text>One NACM Group Entry. This list will only contain
+configured entries, not any entries learned from
+any transport protocols.</text>
+ </description>
+ <leaf name="name">
+ <type name="group-name-type"/>
+ <description>
+ <text>Group name associated with this entry.</text>
+ </description>
+ </leaf>
+ <leaf-list name="user-name">
+ <type name="user-name-type"/>
+ <description>
+ <text>Each entry identifies the username of
+a member of the group associated with
+this entry.</text>
+ </description>
+ </leaf-list>
+ </list>
+ </container>
+ <list name="rule-list">
+ <key value="name"/>
+ <ordered-by value="user"/>
+ <description>
+ <text>An ordered collection of access control rules.</text>
+ </description>
+ <leaf name="name">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>Arbitrary name assigned to the rule-list.</text>
+ </description>
+ </leaf>
+ <leaf-list name="group">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="group-name-type"/>
+ </type>
+ <description>
+ <text>List of administrative groups that will be
+assigned the associated access rights
+defined by the 'rule' list.
+
+The string '*' indicates that all groups apply to the
+entry.</text>
+ </description>
+ </leaf-list>
+ <list name="rule">
+ <key value="name"/>
+ <ordered-by value="user"/>
+ <description>
+ <text>One access control rule.
+
+Rules are processed in user-defined order until a match is
+found. A rule matches if 'module-name', 'rule-type', and
+'access-operations' match the request. If a rule
+matches, the 'action' leaf determines if access is granted
+or not.</text>
+ </description>
+ <leaf name="name">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>Arbitrary name assigned to the rule.</text>
+ </description>
+ </leaf>
+ <leaf name="module-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <default value="*"/>
+ <description>
+ <text>Name of the module associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+object being accessed is defined in the module with the
+specified module name.</text>
+ </description>
+ </leaf>
+ <choice name="rule-type">
+ <description>
+ <text>This choice matches if all leafs present in the rule
+match the request. If no leafs are present, the
+choice matches all requests.</text>
+ </description>
+ <case name="protocol-operation">
+ <leaf name="rpc-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <description>
+ <text>This leaf matches if it has the value '*' or if
+its value equals the requested protocol operation
+name.</text>
+ </description>
+ </leaf>
+ </case>
+ <case name="notification">
+ <leaf name="notification-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <description>
+ <text>This leaf matches if it has the value '*' or if its
+value equals the requested notification name.</text>
+ </description>
+ </leaf>
+ </case>
+ <case name="data-node">
+ <leaf name="path">
+ <type name="node-instance-identifier"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Data Node Instance Identifier associated with the
+data node controlled by this rule.
+
+Configuration data or state data instance
+identifiers start with a top-level data node. A
+complete instance identifier is required for this
+type of path value.
+
+The special value '/' refers to all possible
+datastore contents.</text>
+ </description>
+ </leaf>
+ </case>
+ </choice>
+ <leaf name="access-operations">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="access-operations-type"/>
+ </type>
+ <default value="*"/>
+ <description>
+ <text>Access operations associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+bit corresponding to the requested operation is set.</text>
+ </description>
+ </leaf>
+ <leaf name="action">
+ <type name="action-type"/>
+ <mandatory value="true"/>
+ <description>
+ <text>The access control action associated with the
+rule. If a rule is determined to match a
+particular request, then this object is used
+to determine whether to permit or deny the
+request.</text>
+ </description>
+ </leaf>
+ <leaf name="comment">
+ <type name="string"/>
+ <description>
+ <text>A textual description of the access rule.</text>
+ </description>
+ </leaf>
+ </list>
+ </list>
+ </container>
+</module>
diff --git a/tools/lint/examples/ietf-netconf-acm-when2.yin b/tools/lint/examples/ietf-netconf-acm-when2.yin
new file mode 100644
index 0000000..f8f25a0
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm-when2.yin
@@ -0,0 +1,447 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm" xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types" name="ietf-netconf-acm-when2">
+ <namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
+ <prefix value="nacm"/>
+ <import module="ietf-yang-types">
+ <prefix value="yang"/>
+ </import>
+ <organization>
+ <text>IETF NETCONF (Network Configuration) Working Group</text>
+ </organization>
+ <contact>
+ <text>WG Web: <http://tools.ietf.org/wg/netconf/>
+WG List: <mailto:netconf@ietf.org>
+
+WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+
+WG Chair: Bert Wijnen
+ <mailto:bertietf@bwijnen.net>
+
+Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com></text>
+ </contact>
+ <description>
+ <text>NETCONF Access Control Model.
+
+Copyright (c) 2012 IETF Trust and the persons identified as
+authors of the code. All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, is permitted pursuant to, and subject
+to the license terms contained in, the Simplified BSD
+License set forth in Section 4.c of the IETF Trust's
+Legal Provisions Relating to IETF Documents
+(http://trustee.ietf.org/license-info).
+
+This version of this YANG module is part of RFC 6536; see
+the RFC itself for full legal notices.</text>
+ </description>
+ <revision date="2012-02-22">
+ <description>
+ <text>Initial version</text>
+ </description>
+ <reference>
+ <text>RFC 6536: Network Configuration Protocol (NETCONF)
+ Access Control Model</text>
+ </reference>
+ </revision>
+ <extension name="default-deny-write">
+ <description>
+ <text>Used to indicate that the data model node
+represents a sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+write access to the node. An explicit access control rule is
+required for all other users.
+
+The 'default-deny-write' extension MAY appear within a data
+definition statement. It is ignored otherwise.</text>
+ </description>
+ </extension>
+ <extension name="default-deny-all">
+ <description>
+ <text>Used to indicate that the data model node
+controls a very sensitive security system parameter.
+
+If present, and the NACM module is enabled (i.e.,
+/nacm/enable-nacm object equals 'true'), the NETCONF server
+will only allow the designated 'recovery session' to have
+read, write, or execute access to the node. An explicit
+access control rule is required for all other users.
+
+The 'default-deny-all' extension MAY appear within a data
+definition statement, 'rpc' statement, or 'notification'
+statement. It is ignored otherwise.</text>
+ </description>
+ </extension>
+ <typedef name="user-name-type">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>General Purpose Username string.</text>
+ </description>
+ </typedef>
+ <typedef name="matchall-string-type">
+ <type name="string">
+ <pattern value="\*"/>
+ </type>
+ <description>
+ <text>The string containing a single asterisk '*' is used
+to conceptually represent all possible values
+for the particular leaf using this data type.</text>
+ </description>
+ </typedef>
+ <typedef name="access-operations-type">
+ <type name="bits">
+ <bit name="create">
+ <description>
+ <text>Any protocol operation that creates a
+new data node.</text>
+ </description>
+ </bit>
+ <bit name="read">
+ <description>
+ <text>Any protocol operation or notification that
+returns the value of a data node.</text>
+ </description>
+ </bit>
+ <bit name="update">
+ <description>
+ <text>Any protocol operation that alters an existing
+data node.</text>
+ </description>
+ </bit>
+ <bit name="delete">
+ <description>
+ <text>Any protocol operation that removes a data node.</text>
+ </description>
+ </bit>
+ <bit name="exec">
+ <description>
+ <text>Execution access to the specified protocol operation.</text>
+ </description>
+ </bit>
+ </type>
+ <description>
+ <text>NETCONF Access Operation.</text>
+ </description>
+ </typedef>
+ <typedef name="group-name-type">
+ <type name="string">
+ <length value="1..max"/>
+ <pattern value="[^\*].*"/>
+ </type>
+ <description>
+ <text>Name of administrative group to which
+users can be assigned.</text>
+ </description>
+ </typedef>
+ <typedef name="action-type">
+ <type name="enumeration">
+ <enum name="permit">
+ <description>
+ <text>Requested action is permitted.</text>
+ </description>
+ </enum>
+ <enum name="deny">
+ <description>
+ <text>Requested action is denied.</text>
+ </description>
+ </enum>
+ </type>
+ <description>
+ <text>Action taken by the server when a particular
+rule matches.</text>
+ </description>
+ </typedef>
+ <typedef name="node-instance-identifier">
+ <type name="yang:xpath1.0"/>
+ <description>
+ <text>Path expression used to represent a special
+data node instance identifier string.
+
+A node-instance-identifier value is an
+unrestricted YANG instance-identifier expression.
+All the same rules as an instance-identifier apply
+except predicates for keys are optional. If a key
+predicate is missing, then the node-instance-identifier
+represents all possible server instances for that key.
+
+This XPath expression is evaluated in the following context:
+
+ o The set of namespace declarations are those in scope on
+ the leaf element where this type is used.
+
+ o The set of variable bindings contains one variable,
+ 'USER', which contains the name of the user of the current
+ session.
+
+ o The function library is the core function library, but
+ note that due to the syntax restrictions of an
+ instance-identifier, no functions are allowed.
+
+ o The context node is the root node in the data tree.</text>
+ </description>
+ </typedef>
+ <container name="nacm">
+ <nacm:default-deny-all/>
+ <description>
+ <text>Parameters for NETCONF Access Control Model.</text>
+ </description>
+ <leaf name="enable-nacm">
+ <type name="boolean"/>
+ <default value="true"/>
+ <description>
+ <text>Enables or disables all NETCONF access control
+enforcement. If 'true', then enforcement
+is enabled. If 'false', then enforcement
+is disabled.</text>
+ </description>
+ </leaf>
+ <leaf name="read-default">
+ <type name="action-type"/>
+ <default value="permit"/>
+ <description>
+ <text>Controls whether read access is granted if
+no appropriate rule is found for a
+particular read request.</text>
+ </description>
+ </leaf>
+ <leaf name="write-default">
+ <type name="action-type"/>
+ <default value="deny"/>
+ <description>
+ <text>Controls whether create, update, or delete access
+is granted if no appropriate rule is found for a
+particular write request.</text>
+ </description>
+ </leaf>
+ <leaf name="exec-default">
+ <type name="action-type"/>
+ <default value="permit"/>
+ <description>
+ <text>Controls whether exec access is granted if no appropriate
+rule is found for a particular protocol operation request.</text>
+ </description>
+ </leaf>
+ <leaf name="enable-external-groups">
+ <type name="boolean"/>
+ <default value="true"/>
+ <description>
+ <text>Controls whether the server uses the groups reported by the
+NETCONF transport layer when it assigns the user to a set of
+NACM groups. If this leaf has the value 'false', any group
+names reported by the transport layer are ignored by the
+server.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-operations">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Number of times since the server last restarted that a
+protocol operation request was denied.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-data-writes">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <when condition="../denied-operations > 0"/>
+ <description>
+ <text>Number of times since the server last restarted that a
+protocol operation request to alter
+a configuration datastore was denied.</text>
+ </description>
+ </leaf>
+ <leaf name="denied-notifications">
+ <type name="yang:zero-based-counter32"/>
+ <config value="false"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Number of times since the server last restarted that
+a notification was dropped for a subscription because
+access to the event type was denied.</text>
+ </description>
+ </leaf>
+ <container name="groups">
+ <description>
+ <text>NETCONF Access Control Groups.</text>
+ </description>
+ <list name="group">
+ <key value="name"/>
+ <description>
+ <text>One NACM Group Entry. This list will only contain
+configured entries, not any entries learned from
+any transport protocols.</text>
+ </description>
+ <leaf name="name">
+ <type name="group-name-type"/>
+ <description>
+ <text>Group name associated with this entry.</text>
+ </description>
+ </leaf>
+ <leaf-list name="user-name">
+ <type name="user-name-type"/>
+ <description>
+ <text>Each entry identifies the username of
+a member of the group associated with
+this entry.</text>
+ </description>
+ </leaf-list>
+ </list>
+ </container>
+ <list name="rule-list">
+ <key value="name"/>
+ <ordered-by value="user"/>
+ <description>
+ <text>An ordered collection of access control rules.</text>
+ </description>
+ <leaf name="name">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>Arbitrary name assigned to the rule-list.</text>
+ </description>
+ </leaf>
+ <leaf-list name="group">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="group-name-type"/>
+ </type>
+ <description>
+ <text>List of administrative groups that will be
+assigned the associated access rights
+defined by the 'rule' list.
+
+The string '*' indicates that all groups apply to the
+entry.</text>
+ </description>
+ </leaf-list>
+ <list name="rule">
+ <key value="name"/>
+ <ordered-by value="user"/>
+ <description>
+ <text>One access control rule.
+
+Rules are processed in user-defined order until a match is
+found. A rule matches if 'module-name', 'rule-type', and
+'access-operations' match the request. If a rule
+matches, the 'action' leaf determines if access is granted
+or not.</text>
+ </description>
+ <leaf name="name">
+ <type name="string">
+ <length value="1..max"/>
+ </type>
+ <description>
+ <text>Arbitrary name assigned to the rule.</text>
+ </description>
+ </leaf>
+ <leaf name="module-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <default value="*"/>
+ <description>
+ <text>Name of the module associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+object being accessed is defined in the module with the
+specified module name.</text>
+ </description>
+ </leaf>
+ <choice name="rule-type">
+ <description>
+ <text>This choice matches if all leafs present in the rule
+match the request. If no leafs are present, the
+choice matches all requests.</text>
+ </description>
+ <case name="protocol-operation">
+ <leaf name="rpc-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <description>
+ <text>This leaf matches if it has the value '*' or if
+its value equals the requested protocol operation
+name.</text>
+ </description>
+ </leaf>
+ </case>
+ <case name="notification">
+ <leaf name="notification-name">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="string"/>
+ </type>
+ <description>
+ <text>This leaf matches if it has the value '*' or if its
+value equals the requested notification name.</text>
+ </description>
+ </leaf>
+ </case>
+ <case name="data-node">
+ <leaf name="path">
+ <type name="node-instance-identifier"/>
+ <mandatory value="true"/>
+ <description>
+ <text>Data Node Instance Identifier associated with the
+data node controlled by this rule.
+
+Configuration data or state data instance
+identifiers start with a top-level data node. A
+complete instance identifier is required for this
+type of path value.
+
+The special value '/' refers to all possible
+datastore contents.</text>
+ </description>
+ </leaf>
+ </case>
+ </choice>
+ <leaf name="access-operations">
+ <type name="union">
+ <type name="matchall-string-type"/>
+ <type name="access-operations-type"/>
+ </type>
+ <default value="*"/>
+ <description>
+ <text>Access operations associated with this rule.
+
+This leaf matches if it has the value '*' or if the
+bit corresponding to the requested operation is set.</text>
+ </description>
+ </leaf>
+ <leaf name="action">
+ <type name="action-type"/>
+ <mandatory value="true"/>
+ <description>
+ <text>The access control action associated with the
+rule. If a rule is determined to match a
+particular request, then this object is used
+to determine whether to permit or deny the
+request.</text>
+ </description>
+ </leaf>
+ <leaf name="comment">
+ <type name="string"/>
+ <description>
+ <text>A textual description of the access rule.</text>
+ </description>
+ </leaf>
+ </list>
+ </list>
+ </container>
+</module>
diff --git a/tools/lint/examples/ietf-netconf-acm.yang b/tools/lint/examples/ietf-netconf-acm.yang
new file mode 100644
index 0000000..dc3655e
--- /dev/null
+++ b/tools/lint/examples/ietf-netconf-acm.yang
@@ -0,0 +1,411 @@
+module ietf-netconf-acm {
+ namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
+ prefix nacm;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ WG Chair: Mehmet Ersue
+ <mailto:mehmet.ersue@nsn.com>
+
+ WG Chair: Bert Wijnen
+ <mailto:bertietf@bwijnen.net>
+
+ Editor: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Editor: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+ description
+ "NETCONF Access Control Model.
+
+ Copyright (c) 2012 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD
+ License set forth in Section 4.c of the IETF Trust's
+ Legal Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6536; see
+ the RFC itself for full legal notices.";
+
+ revision 2012-02-22 {
+ description
+ "Initial version";
+ reference
+ "RFC 6536: Network Configuration Protocol (NETCONF)
+ Access Control Model";
+ }
+
+ extension default-deny-write {
+ description
+ "Used to indicate that the data model node
+ represents a sensitive security system parameter.
+
+ If present, and the NACM module is enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), the NETCONF server
+ will only allow the designated 'recovery session' to have
+ write access to the node. An explicit access control rule is
+ required for all other users.
+
+ The 'default-deny-write' extension MAY appear within a data
+ definition statement. It is ignored otherwise.";
+ }
+
+ extension default-deny-all {
+ description
+ "Used to indicate that the data model node
+ controls a very sensitive security system parameter.
+
+ If present, and the NACM module is enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), the NETCONF server
+ will only allow the designated 'recovery session' to have
+ read, write, or execute access to the node. An explicit
+ access control rule is required for all other users.
+
+ The 'default-deny-all' extension MAY appear within a data
+ definition statement, 'rpc' statement, or 'notification'
+ statement. It is ignored otherwise.";
+ }
+
+ typedef user-name-type {
+ type string {
+ length "1..max";
+ }
+ description
+ "General Purpose Username string.";
+ }
+
+ typedef matchall-string-type {
+ type string {
+ pattern "\\*";
+ }
+ description
+ "The string containing a single asterisk '*' is used
+ to conceptually represent all possible values
+ for the particular leaf using this data type.";
+ }
+
+ typedef access-operations-type {
+ type bits {
+ bit create {
+ description
+ "Any protocol operation that creates a
+ new data node.";
+ }
+ bit read {
+ description
+ "Any protocol operation or notification that
+ returns the value of a data node.";
+ }
+ bit update {
+ description
+ "Any protocol operation that alters an existing
+ data node.";
+ }
+ bit delete {
+ description
+ "Any protocol operation that removes a data node.";
+ }
+ bit exec {
+ description
+ "Execution access to the specified protocol operation.";
+ }
+ }
+ description
+ "NETCONF Access Operation.";
+ }
+
+ typedef group-name-type {
+ type string {
+ length "1..max";
+ pattern "[^\\*].*";
+ }
+ description
+ "Name of administrative group to which
+ users can be assigned.";
+ }
+
+ typedef action-type {
+ type enumeration {
+ enum "permit" {
+ description
+ "Requested action is permitted.";
+ }
+ enum "deny" {
+ description
+ "Requested action is denied.";
+ }
+ }
+ description
+ "Action taken by the server when a particular
+ rule matches.";
+ }
+
+ typedef node-instance-identifier {
+ type yang:xpath1.0;
+ description
+ "Path expression used to represent a special
+ data node instance identifier string.
+
+ A node-instance-identifier value is an
+ unrestricted YANG instance-identifier expression.
+ All the same rules as an instance-identifier apply
+ except predicates for keys are optional. If a key
+ predicate is missing, then the node-instance-identifier
+ represents all possible server instances for that key.
+
+ This XPath expression is evaluated in the following context:
+
+ o The set of namespace declarations are those in scope on
+ the leaf element where this type is used.
+
+ o The set of variable bindings contains one variable,
+ 'USER', which contains the name of the user of the current
+ session.
+
+ o The function library is the core function library, but
+ note that due to the syntax restrictions of an
+ instance-identifier, no functions are allowed.
+
+ o The context node is the root node in the data tree.";
+ }
+
+ container nacm {
+ nacm:default-deny-all;
+ description
+ "Parameters for NETCONF Access Control Model.";
+ leaf enable-nacm {
+ type boolean;
+ default "true";
+ description
+ "Enables or disables all NETCONF access control
+ enforcement. If 'true', then enforcement
+ is enabled. If 'false', then enforcement
+ is disabled.";
+ }
+ leaf read-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether read access is granted if
+ no appropriate rule is found for a
+ particular read request.";
+ }
+ leaf write-default {
+ type action-type;
+ default "deny";
+ description
+ "Controls whether create, update, or delete access
+ is granted if no appropriate rule is found for a
+ particular write request.";
+ }
+ leaf exec-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether exec access is granted if no appropriate
+ rule is found for a particular protocol operation request.";
+ }
+ leaf enable-external-groups {
+ type boolean;
+ default "true";
+ description
+ "Controls whether the server uses the groups reported by the
+ NETCONF transport layer when it assigns the user to a set of
+ NACM groups. If this leaf has the value 'false', any group
+ names reported by the transport layer are ignored by the
+ server.";
+ }
+ leaf denied-operations {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request was denied.";
+ }
+ leaf denied-data-writes {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request to alter
+ a configuration datastore was denied.";
+ }
+ leaf denied-notifications {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that
+ a notification was dropped for a subscription because
+ access to the event type was denied.";
+ }
+ container groups {
+ description
+ "NETCONF Access Control Groups.";
+ list group {
+ key "name";
+ description
+ "One NACM Group Entry. This list will only contain
+ configured entries, not any entries learned from
+ any transport protocols.";
+ leaf name {
+ type group-name-type;
+ description
+ "Group name associated with this entry.";
+ }
+ leaf-list user-name {
+ type user-name-type;
+ description
+ "Each entry identifies the username of
+ a member of the group associated with
+ this entry.";
+ }
+ }
+ }
+ list rule-list {
+ key "name";
+ ordered-by user;
+ description
+ "An ordered collection of access control rules.";
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule-list.";
+ }
+ leaf-list group {
+ type union {
+ type matchall-string-type;
+ type group-name-type;
+ }
+ description
+ "List of administrative groups that will be
+ assigned the associated access rights
+ defined by the 'rule' list.
+
+ The string '*' indicates that all groups apply to the
+ entry.";
+ }
+ list rule {
+ key "name";
+ ordered-by user;
+ description
+ "One access control rule.
+
+ Rules are processed in user-defined order until a match is
+ found. A rule matches if 'module-name', 'rule-type', and
+ 'access-operations' match the request. If a rule
+ matches, the 'action' leaf determines if access is granted
+ or not.";
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule.";
+ }
+ leaf module-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ default "*";
+ description
+ "Name of the module associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ object being accessed is defined in the module with the
+ specified module name.";
+ }
+ choice rule-type {
+ description
+ "This choice matches if all leafs present in the rule
+ match the request. If no leafs are present, the
+ choice matches all requests.";
+ case protocol-operation {
+ leaf rpc-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if
+ its value equals the requested protocol operation
+ name.";
+ }
+ }
+ case notification {
+ leaf notification-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if its
+ value equals the requested notification name.";
+ }
+ }
+ case data-node {
+ leaf path {
+ type node-instance-identifier;
+ mandatory true;
+ description
+ "Data Node Instance Identifier associated with the
+ data node controlled by this rule.
+
+ Configuration data or state data instance
+ identifiers start with a top-level data node. A
+ complete instance identifier is required for this
+ type of path value.
+
+ The special value '/' refers to all possible
+ datastore contents.";
+ }
+ }
+ }
+ leaf access-operations {
+ type union {
+ type matchall-string-type;
+ type access-operations-type;
+ }
+ default "*";
+ description
+ "Access operations associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ bit corresponding to the requested operation is set.";
+ }
+ leaf action {
+ type action-type;
+ mandatory true;
+ description
+ "The access control action associated with the
+ rule. If a rule is determined to match a
+ particular request, then this object is used
+ to determine whether to permit or deny the
+ request.";
+ }
+ leaf comment {
+ type string;
+ description
+ "A textual description of the access rule.";
+ }
+ }
+ }
+ }
+}
diff --git a/tools/lint/examples/module1.yang b/tools/lint/examples/module1.yang
new file mode 100644
index 0000000..1df7bf1
--- /dev/null
+++ b/tools/lint/examples/module1.yang
@@ -0,0 +1,5 @@
+module module1 {
+ namespace "urn:yanglint:module";
+ prefix m;
+ leaf m { type string; }
+}
diff --git a/tools/lint/examples/module1b.yang b/tools/lint/examples/module1b.yang
new file mode 100644
index 0000000..463c936
--- /dev/null
+++ b/tools/lint/examples/module1b.yang
@@ -0,0 +1,5 @@
+module module1b {
+ namespace "urn:yanglint:module";
+ prefix m;
+ leaf mb { type string; }
+}
diff --git a/tools/lint/examples/module2.yang b/tools/lint/examples/module2.yang
new file mode 100644
index 0000000..c87c764
--- /dev/null
+++ b/tools/lint/examples/module2.yang
@@ -0,0 +1,5 @@
+module module2 {
+ namespace "urn:yanglint:module";
+ prefix m;
+ leaf m { ttype string; }
+}
diff --git a/tools/lint/examples/module2.yin b/tools/lint/examples/module2.yin
new file mode 100644
index 0000000..af6cb50
--- /dev/null
+++ b/tools/lint/examples/module2.yin
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module name="module2"
+ xmlns="urn:ietf:params:xml:ns:yang:yin:1"
+ xmlns:m="urn:yanglint:module">
+ <namespace uri="urn:yanglint:module"/>
+ <prefix value="m"/>
+ <leaf name="m">
+ <type value="string"/>
+ </leaf>
+</module>
diff --git a/tools/lint/examples/module3.yang b/tools/lint/examples/module3.yang
new file mode 100644
index 0000000..63754b1
--- /dev/null
+++ b/tools/lint/examples/module3.yang
@@ -0,0 +1,8 @@
+module module3 {
+ namespace "urn:yanglint:module";
+ prefix m;
+ leaf m { type string; must "../c/a"; }
+ container c {
+ leaf b { type string; }
+ }
+}
diff --git a/tools/lint/examples/module4.yang b/tools/lint/examples/module4.yang
new file mode 100644
index 0000000..23ea289
--- /dev/null
+++ b/tools/lint/examples/module4.yang
@@ -0,0 +1,52 @@
+module module4 {
+ yang-version 1.1;
+ namespace "urn:module4";
+ prefix m4;
+
+ container cont1 {
+ list list {
+ key "leaf1";
+ leaf leaf1 {
+ type string;
+ }
+ action act {
+ input {
+ leaf leaf2 {
+ type string;
+ }
+ }
+ output {
+ leaf leaf3 {
+ type string;
+ }
+ }
+ }
+ notification notif1 {
+ leaf leaf4 {
+ type string;
+ }
+ }
+ }
+ }
+
+ rpc rpc {
+ input {
+ leaf leaf5 {
+ type string;
+ }
+ }
+ output {
+ container cont2 {
+ leaf leaf6 {
+ type empty;
+ }
+ }
+ }
+ }
+
+ notification notif2 {
+ leaf leaf7 {
+ type empty;
+ }
+ }
+}
diff --git a/tools/lint/examples/nested-notification.xml b/tools/lint/examples/nested-notification.xml
new file mode 100644
index 0000000..024b65a
--- /dev/null
+++ b/tools/lint/examples/nested-notification.xml
@@ -0,0 +1,8 @@
+<cont1 xmlns="urn:module4">
+ <list>
+ <leaf1>key_val</leaf1>
+ <notif1>
+ <leaf4>some_value</leaf4>
+ </notif1>
+ </list>
+</cont1>
diff --git a/tools/lint/examples/notification.xml b/tools/lint/examples/notification.xml
new file mode 100644
index 0000000..803ddad
--- /dev/null
+++ b/tools/lint/examples/notification.xml
@@ -0,0 +1,3 @@
+<notif2 xmlns="urn:module4">
+ <leaf7/>
+</notif2>
diff --git a/tools/lint/examples/rpc-reply.xml b/tools/lint/examples/rpc-reply.xml
new file mode 100644
index 0000000..20469dd
--- /dev/null
+++ b/tools/lint/examples/rpc-reply.xml
@@ -0,0 +1,3 @@
+<cont2 xmlns="urn:module4">
+ <leaf6/>
+</cont2>
diff --git a/tools/lint/examples/rpc.xml b/tools/lint/examples/rpc.xml
new file mode 100644
index 0000000..ea8ca90
--- /dev/null
+++ b/tools/lint/examples/rpc.xml
@@ -0,0 +1,3 @@
+<rpc xmlns="urn:module4">
+ <leaf5>some_input</leaf5>
+</rpc>
diff --git a/tools/lint/linenoise/LICENSE b/tools/lint/linenoise/LICENSE
new file mode 100644
index 0000000..18e8148
--- /dev/null
+++ b/tools/lint/linenoise/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/lint/linenoise/linenoise.c b/tools/lint/linenoise/linenoise.c
new file mode 100644
index 0000000..eefbeb3
--- /dev/null
+++ b/tools/lint/linenoise/linenoise.c
@@ -0,0 +1,1226 @@
+/* linenoise.c -- VERSION 1.0
+ *
+ * Guerrilla line editing library against the idea that a line editing lib
+ * needs to be 20,000 lines of C code.
+ *
+ * You can find the latest source code at:
+ *
+ * http://github.com/antirez/linenoise
+ *
+ * Does a number of crazy assumptions that happen to be true in 99.9999% of
+ * the 2010 UNIX computers around.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * References:
+ * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+ * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
+ *
+ * Todo list:
+ * - Filter bogus Ctrl+<char> combinations.
+ * - Win32 support
+ *
+ * Bloat:
+ * - History search like Ctrl+r in readline?
+ *
+ * List of escape sequences used by this program, we do everything just
+ * with three sequences. In order to be so cheap we may have some
+ * flickering effect with some slow terminal, but the lesser sequences
+ * the more compatible.
+ *
+ * EL (Erase Line)
+ * Sequence: ESC [ n K
+ * Effect: if n is 0 or missing, clear from cursor to end of line
+ * Effect: if n is 1, clear from beginning of line to cursor
+ * Effect: if n is 2, clear entire line
+ *
+ * CUF (CUrsor Forward)
+ * Sequence: ESC [ n C
+ * Effect: moves cursor forward n chars
+ *
+ * CUB (CUrsor Backward)
+ * Sequence: ESC [ n D
+ * Effect: moves cursor backward n chars
+ *
+ * The following is used to get the terminal width if getting
+ * the width with the TIOCGWINSZ ioctl fails
+ *
+ * DSR (Device Status Report)
+ * Sequence: ESC [ 6 n
+ * Effect: reports the current cusor position as ESC [ n ; m R
+ * where n is the row and m is the column
+ *
+ * When multi line mode is enabled, we also use an additional escape
+ * sequence. However multi line editing is disabled by default.
+ *
+ * CUU (Cursor Up)
+ * Sequence: ESC [ n A
+ * Effect: moves cursor up of n chars.
+ *
+ * CUD (Cursor Down)
+ * Sequence: ESC [ n B
+ * Effect: moves cursor down of n chars.
+ *
+ * When linenoiseClearScreen() is called, two additional escape sequences
+ * are used in order to clear the screen and position the cursor at home
+ * position.
+ *
+ * CUP (Cursor position)
+ * Sequence: ESC [ H
+ * Effect: moves the cursor to upper left corner
+ *
+ * ED (Erase display)
+ * Sequence: ESC [ 2 J
+ * Effect: clear the whole screen
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <termios.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "linenoise.h"
+
+#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
+#define LINENOISE_MAX_LINE 4096
+static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
+static linenoiseCompletionCallback *completionCallback = NULL;
+
+static struct termios orig_termios; /* In order to restore at exit.*/
+static int mlmode = 0; /* Multi line mode. Default is single line. */
+static int atexit_registered = 0; /* Register atexit just 1 time. */
+static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
+static int history_len = 0;
+static char **history = NULL;
+
+/* The linenoiseState structure represents the state during line editing.
+ * We pass this state to functions implementing specific editing
+ * functionalities. */
+struct linenoiseState ls;
+
+enum KEY_ACTION{
+ KEY_NULL = 0, /* NULL */
+ CTRL_A = 1, /* Ctrl+a */
+ CTRL_B = 2, /* Ctrl-b */
+ CTRL_C = 3, /* Ctrl-c */
+ CTRL_D = 4, /* Ctrl-d */
+ CTRL_E = 5, /* Ctrl-e */
+ CTRL_F = 6, /* Ctrl-f */
+ CTRL_H = 8, /* Ctrl-h */
+ TAB = 9, /* Tab */
+ CTRL_K = 11, /* Ctrl+k */
+ CTRL_L = 12, /* Ctrl+l */
+ ENTER = 13, /* Enter */
+ CTRL_N = 14, /* Ctrl-n */
+ CTRL_P = 16, /* Ctrl-p */
+ CTRL_T = 20, /* Ctrl-t */
+ CTRL_U = 21, /* Ctrl+u */
+ CTRL_W = 23, /* Ctrl+w */
+ ESC = 27, /* Escape */
+ BACKSPACE = 127 /* Backspace */
+};
+
+static void linenoiseAtExit(void);
+int linenoiseHistoryAdd(const char *line);
+
+/* Debugging macro. */
+#if 0
+FILE *lndebug_fp = NULL;
+#define lndebug(...) \
+ do { \
+ if (lndebug_fp == NULL) { \
+ lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
+ fprintf(lndebug_fp, \
+ "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
+ (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
+ (int)l->maxrows,old_rows); \
+ } \
+ fprintf(lndebug_fp, ", " __VA_ARGS__); \
+ fflush(lndebug_fp); \
+ } while (0)
+#else
+#define lndebug(fmt, ...)
+#endif
+
+/* ======================= Low level terminal handling ====================== */
+
+/* Set if to use or not the multi line mode. */
+void linenoiseSetMultiLine(int ml) {
+ mlmode = ml;
+}
+
+/* Return true if the terminal name is in the list of terminals we know are
+ * not able to understand basic escape sequences. */
+static int isUnsupportedTerm(void) {
+ char *term = getenv("TERM");
+ int j;
+
+ if (term == NULL) return 0;
+ for (j = 0; unsupported_term[j]; j++)
+ if (!strcasecmp(term,unsupported_term[j])) return 1;
+ return 0;
+}
+
+/* Raw mode: 1960 magic shit. */
+int linenoiseEnableRawMode(int fd) {
+ struct termios raw;
+
+ if (!isatty(STDIN_FILENO)) goto fatal;
+ if (!atexit_registered) {
+ atexit(linenoiseAtExit);
+ atexit_registered = 1;
+ }
+ if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
+
+ raw = orig_termios; /* modify the original mode */
+ /* input modes: no break, no CR to NL, no parity check, no strip char,
+ * no start/stop output control. */
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ /* output modes - disable post processing */
+ raw.c_oflag &= ~(OPOST);
+ /* control modes - set 8 bit chars */
+ raw.c_cflag |= (CS8);
+ /* local modes - choing off, canonical off, no extended functions,
+ * no signal chars (^Z,^C) */
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ /* control chars - set return condition: min number of bytes and timer.
+ * We want read to return every single byte, without timeout. */
+ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+
+ /* put terminal in raw mode after flushing */
+ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
+ ls.rawmode = 1;
+ return 0;
+
+fatal:
+ errno = ENOTTY;
+ return -1;
+}
+
+void linenoiseDisableRawMode(int fd) {
+ /* Don't even check the return value as it's too late. */
+ if (ls.rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
+ ls.rawmode = 0;
+}
+
+/* Use the ESC [6n escape sequence to query the horizontal cursor position
+ * and return it. On error -1 is returned, on success the position of the
+ * cursor. */
+static int getCursorPosition(int ifd, int ofd) {
+ char buf[32];
+ int cols, rows;
+ unsigned int i = 0;
+
+ /* Report cursor location */
+ if (write(ofd, "\x1b[6n", 4) != 4) return -1;
+
+ /* Read the response: ESC [ rows ; cols R */
+ while (i < sizeof(buf)-1) {
+ if (read(ifd,buf+i,1) != 1) break;
+ if (buf[i] == 'R') break;
+ i++;
+ }
+ buf[i] = '\0';
+
+ /* Parse it. */
+ if (buf[0] != ESC || buf[1] != '[') return -1;
+ if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
+ return cols;
+}
+
+/* Try to get the number of columns in the current terminal, or assume 80
+ * if it fails. */
+static int getColumns(int ifd, int ofd) {
+ struct winsize ws;
+
+ if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
+ /* ioctl() failed. Try to query the terminal itself. */
+ int start, cols;
+
+ /* Get the initial position so we can restore it later. */
+ start = getCursorPosition(ifd,ofd);
+ if (start == -1) goto failed;
+
+ /* Go to right margin and get position. */
+ if (write(ofd,"\x1b[999C",6) != 6) goto failed;
+ cols = getCursorPosition(ifd,ofd);
+ if (cols == -1) goto failed;
+
+ /* Restore position. */
+ if (cols > start) {
+ char seq[32];
+ snprintf(seq,32,"\x1b[%dD",cols-start);
+ if (write(ofd,seq,strlen(seq)) == -1) {
+ /* Can't recover... */
+ }
+ }
+ return cols;
+ } else {
+ return ws.ws_col;
+ }
+
+failed:
+ return 80;
+}
+
+/* Clear the screen. Used to handle ctrl+l */
+void linenoiseClearScreen(void) {
+ if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
+ /* nothing to do, just to avoid warning. */
+ }
+}
+
+/* Beep, used for completion when there is nothing to complete or when all
+ * the choices were already shown. */
+static void linenoiseBeep(void) {
+ fprintf(stderr, "\x7");
+ fflush(stderr);
+}
+
+/* ============================== Completion ================================ */
+
+/* Free a list of completion option populated by linenoiseAddCompletion(). */
+static void freeCompletions(linenoiseCompletions *lc) {
+ size_t i;
+ for (i = 0; i < lc->len; i++)
+ free(lc->cvec[i]);
+ if (lc->cvec != NULL)
+ free(lc->cvec);
+}
+
+/* This is an helper function for linenoiseEdit() and is called when the
+ * user types the <tab> key in order to complete the string currently in the
+ * input.
+ *
+ * The state of the editing is encapsulated into the pointed linenoiseState
+ * structure as described in the structure definition. */
+static int completeLine(struct linenoiseState *ls) {
+ linenoiseCompletions lc = {0, 0, NULL};
+ int nread, nwritten, hint_len, hint_line_count, char_count;
+ char c = 0, *common, *hint;
+ struct winsize w;
+
+ /* Hint is only the string after the last space */
+ hint = strrchr(ls->buf, ' ');
+ if (!hint) {
+ hint = ls->buf;
+ } else {
+ ++hint;
+ }
+
+ completionCallback(ls->buf, hint, &lc);
+ if (lc.len == 0) {
+ linenoiseBeep();
+ } else {
+ unsigned int i, j;
+
+ /* Learn the longest common part */
+ common = strdup(lc.cvec[0]);
+ for (i = 1; i < lc.len; ++i) {
+ for (j = 0; j < strlen(lc.cvec[i]); ++j) {
+ if (lc.cvec[i][j] != common[j]) {
+ break;
+ }
+ }
+ common[j] = '\0';
+ }
+
+ /* Path completions have a different hint */
+ if (lc.path && strrchr(hint, '/')) {
+ hint = strrchr(hint, '/');
+ ++hint;
+ }
+
+ /* Show completion */
+ if ((lc.len == 1) && (common[strlen(common) - 1] != '/')) {
+ nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s ", common);
+ } else {
+ nwritten = snprintf(hint, ls->buflen - (hint - ls->buf), "%s", common);
+ }
+ free(common);
+ ls->len = ls->pos = (hint - ls->buf) + nwritten;
+ linenoiseRefreshLine();
+
+ /* A single hint */
+ if (lc.len == 1) {
+ freeCompletions(&lc);
+ return 0;
+ }
+
+ /* Read a char */
+ nread = read(ls->ifd,&c,1);
+ if (nread <= 0) {
+ freeCompletions(&lc);
+ return -1;
+ }
+
+ /* Not a tab */
+ if (c != 9) {
+ freeCompletions(&lc);
+ return c;
+ }
+
+ /* Learn terminal window size */
+ ioctl(ls->ifd, TIOCGWINSZ, &w);
+
+ /* Learn the longest hint */
+ hint_len = strlen(lc.cvec[0]);
+ for (i = 1; i < lc.len; ++i) {
+ if (strlen(lc.cvec[i]) > (unsigned)hint_len) {
+ hint_len = strlen(lc.cvec[i]);
+ }
+ }
+
+ /* Learn the number of hints that fit a line */
+ hint_line_count = 0;
+ while (1) {
+ char_count = 0;
+ if (hint_line_count) {
+ char_count += hint_line_count * (hint_len + 2);
+ }
+ char_count += hint_len;
+
+ /* Too much */
+ if (char_count > w.ws_col) {
+ break;
+ }
+
+ /* Still fits */
+ ++hint_line_count;
+ }
+
+ /* No hint fits, too bad */
+ if (!hint_line_count) {
+ freeCompletions(&lc);
+ return c;
+ }
+
+ while (c == 9) {
+ /* Second tab */
+ linenoiseDisableRawMode(ls->ifd);
+ printf("\n");
+ for (i = 0; i < lc.len; ++i) {
+ printf("%-*s", hint_len, lc.cvec[i]);
+ /* Line full or last hint */
+ if (((i + 1) % hint_line_count == 0) || (i == lc.len - 1)) {
+ printf("\n");
+ } else {
+ printf(" ");
+ }
+ }
+ linenoiseEnableRawMode(ls->ifd);
+ linenoiseRefreshLine();
+
+ /* Read a char */
+ nread = read(ls->ifd,&c,1);
+ if (nread <= 0) {
+ freeCompletions(&lc);
+ return -1;
+ }
+ }
+ }
+
+ freeCompletions(&lc);
+ return c; /* Return last read character */
+}
+
+/* Register a callback function to be called for tab-completion. */
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
+ completionCallback = fn;
+}
+
+/* This function can be called in user completion callback to fill
+ * path completion for them. hint parameter is actually the whole path
+ * and buf is unused, but included to match the completion callback prototype. */
+void linenoisePathCompletion(const char *buf, const char *hint, linenoiseCompletions *lc) {
+ const char *ptr;
+ char *full_path, *hint_ptr, match[FILENAME_MAX + 2];
+ DIR *dir;
+ struct dirent *ent;
+ struct stat st;
+
+ (void)buf;
+
+ lc->path = 1;
+
+ ptr = strrchr(hint, '/');
+
+ /* new relative path */
+ if (ptr == NULL) {
+ full_path = malloc(2 + FILENAME_MAX + 1);
+ strcpy(full_path, "./");
+
+ ptr = hint;
+ } else {
+ full_path = malloc((int)(ptr - hint) + FILENAME_MAX + 1);
+ ++ptr;
+ sprintf(full_path, "%.*s", (int)(ptr - hint), hint);
+ }
+ hint_ptr = full_path + strlen(full_path);
+
+ dir = opendir(full_path);
+ if (dir == NULL) {
+ free(full_path);
+ return;
+ }
+
+ while ((ent = readdir(dir))) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+
+ if (!strncmp(ptr, ent->d_name, strlen(ptr))) {
+ /* is it a directory? */
+ strcpy(hint_ptr, ent->d_name);
+ if (stat(full_path, &st)) {
+ /* skip this item */
+ continue;
+ }
+
+ strcpy(match, ent->d_name);
+ if (S_ISDIR(st.st_mode)) {
+ strcat(match, "/");
+ }
+
+ linenoiseAddCompletion(lc, match);
+ }
+ }
+
+ free(full_path);
+ closedir(dir);
+}
+
+/* This function is used by the callback function registered by the user
+ * in order to add completion options given the input string when the
+ * user typed <tab>. See the example.c source code for a very easy to
+ * understand example. */
+void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
+ size_t len = strlen(str);
+ char *copy, **cvec;
+
+ copy = malloc(len+1);
+ if (copy == NULL) return;
+ memcpy(copy,str,len+1);
+ cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
+ if (cvec == NULL) {
+ free(copy);
+ return;
+ }
+ lc->cvec = cvec;
+ lc->cvec[lc->len++] = copy;
+}
+
+/* =========================== Line editing ================================= */
+
+/* We define a very simple "append buffer" structure, that is an heap
+ * allocated string where we can append to. This is useful in order to
+ * write all the escape sequences in a buffer and flush them to the standard
+ * output in a single call, to avoid flickering effects. */
+struct abuf {
+ char *b;
+ int len;
+};
+
+static void abInit(struct abuf *ab) {
+ ab->b = NULL;
+ ab->len = 0;
+}
+
+static void abAppend(struct abuf *ab, const char *s, int len) {
+ char *new = realloc(ab->b,ab->len+len);
+
+ if (new == NULL) return;
+ memcpy(new+ab->len,s,len);
+ ab->b = new;
+ ab->len += len;
+}
+
+static void abFree(struct abuf *ab) {
+ free(ab->b);
+}
+
+/* Single line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshSingleLine(struct linenoiseState *l) {
+ char seq[64];
+ size_t plen = strlen(l->prompt);
+ int fd = l->ofd;
+ char *buf = l->buf;
+ size_t len = l->len;
+ size_t pos = l->pos;
+ struct abuf ab;
+
+ while((plen+pos) >= l->cols) {
+ buf++;
+ len--;
+ pos--;
+ }
+ while (plen+len > l->cols) {
+ len--;
+ }
+
+ abInit(&ab);
+ /* Cursor to left edge */
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+ /* Write the prompt and the current buffer content */
+ abAppend(&ab,l->prompt,strlen(l->prompt));
+ abAppend(&ab,buf,len);
+ /* Erase to right */
+ snprintf(seq,64,"\x1b[0K");
+ abAppend(&ab,seq,strlen(seq));
+ /* Move cursor to original position. */
+ snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
+ abAppend(&ab,seq,strlen(seq));
+ if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+ abFree(&ab);
+}
+
+/* Multi line low level line refresh.
+ *
+ * Rewrite the currently edited line accordingly to the buffer content,
+ * cursor position, and number of columns of the terminal. */
+static void refreshMultiLine(struct linenoiseState *l) {
+ char seq[64];
+ int plen = strlen(l->prompt);
+ int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
+ int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
+ int rpos2; /* rpos after refresh. */
+ int col; /* colum position, zero-based. */
+ int old_rows = l->maxrows;
+ int fd = l->ofd, j;
+ struct abuf ab;
+
+ /* Update maxrows if needed. */
+ if (rows > (int)l->maxrows) l->maxrows = rows;
+
+ /* First step: clear all the lines used before. To do so start by
+ * going to the last row. */
+ abInit(&ab);
+ if (old_rows-rpos > 0) {
+ lndebug("go down %d", old_rows-rpos);
+ snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Now for every row clear it, go up. */
+ for (j = 0; j < old_rows-1; j++) {
+ lndebug("clear+up");
+ snprintf(seq,64,"\r\x1b[0K\x1b[1A");
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Clean the top line. */
+ lndebug("clear");
+ snprintf(seq,64,"\r\x1b[0K");
+ abAppend(&ab,seq,strlen(seq));
+
+ /* Write the prompt and the current buffer content */
+ abAppend(&ab,l->prompt,strlen(l->prompt));
+ abAppend(&ab,l->buf,l->len);
+
+ /* If we are at the very end of the screen with our prompt, we need to
+ * emit a newline and move the prompt to the first column. */
+ if (l->pos &&
+ l->pos == l->len &&
+ (l->pos+plen) % l->cols == 0)
+ {
+ lndebug("<newline>");
+ abAppend(&ab,"\n",1);
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+ rows++;
+ if (rows > (int)l->maxrows) l->maxrows = rows;
+ }
+
+ /* Move cursor to right position. */
+ rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
+ lndebug("rpos2 %d", rpos2);
+
+ /* Go up till we reach the expected positon. */
+ if (rows-rpos2 > 0) {
+ lndebug("go-up %d", rows-rpos2);
+ snprintf(seq,64,"\x1b[%dA", rows-rpos2);
+ abAppend(&ab,seq,strlen(seq));
+ }
+
+ /* Set column. */
+ col = (plen+(int)l->pos) % (int)l->cols;
+ lndebug("set col %d", 1+col);
+ if (col)
+ snprintf(seq,64,"\r\x1b[%dC", col);
+ else
+ snprintf(seq,64,"\r");
+ abAppend(&ab,seq,strlen(seq));
+
+ lndebug("\n");
+ l->oldpos = l->pos;
+
+ if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
+ abFree(&ab);
+}
+
+/* Calls the two low level functions refreshSingleLine() or
+ * refreshMultiLine() according to the selected mode. */
+void linenoiseRefreshLine(void) {
+ if (mlmode)
+ refreshMultiLine(&ls);
+ else
+ refreshSingleLine(&ls);
+}
+
+/* Insert the character 'c' at cursor current position.
+ *
+ * On error writing to the terminal -1 is returned, otherwise 0. */
+int linenoiseEditInsert(struct linenoiseState *l, char c) {
+ if (l->len < l->buflen) {
+ if (l->len == l->pos) {
+ l->buf[l->pos] = c;
+ l->pos++;
+ l->len++;
+ l->buf[l->len] = '\0';
+ if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
+ /* Avoid a full update of the line in the
+ * trivial case. */
+ if (write(l->ofd,&c,1) == -1) return -1;
+ } else {
+ linenoiseRefreshLine();
+ }
+ } else {
+ memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
+ l->buf[l->pos] = c;
+ l->len++;
+ l->pos++;
+ l->buf[l->len] = '\0';
+ linenoiseRefreshLine();
+ }
+ }
+ return 0;
+}
+
+/* Move cursor on the left. */
+void linenoiseEditMoveLeft(struct linenoiseState *l) {
+ if (l->pos > 0) {
+ l->pos--;
+ linenoiseRefreshLine();
+ }
+}
+
+/* Move cursor on the right. */
+void linenoiseEditMoveRight(struct linenoiseState *l) {
+ if (l->pos != l->len) {
+ l->pos++;
+ linenoiseRefreshLine();
+ }
+}
+
+/* Move cursor to the start of the line. */
+void linenoiseEditMoveHome(struct linenoiseState *l) {
+ if (l->pos != 0) {
+ l->pos = 0;
+ linenoiseRefreshLine();
+ }
+}
+
+/* Move cursor to the end of the line. */
+void linenoiseEditMoveEnd(struct linenoiseState *l) {
+ if (l->pos != l->len) {
+ l->pos = l->len;
+ linenoiseRefreshLine();
+ }
+}
+
+/* Substitute the currently edited line with the next or previous history
+ * entry as specified by 'dir'. */
+#define LINENOISE_HISTORY_NEXT 0
+#define LINENOISE_HISTORY_PREV 1
+void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
+ if (history_len > 1) {
+ /* Update the current history entry before to
+ * overwrite it with the next one. */
+ free(history[history_len - 1 - l->history_index]);
+ history[history_len - 1 - l->history_index] = strdup(l->buf);
+ /* Show the new entry */
+ l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
+ if (l->history_index < 0) {
+ l->history_index = 0;
+ return;
+ } else if (l->history_index >= history_len) {
+ l->history_index = history_len-1;
+ return;
+ }
+ strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
+ l->buf[l->buflen-1] = '\0';
+ l->len = l->pos = strlen(l->buf);
+ linenoiseRefreshLine();
+ }
+}
+
+/* Delete the character at the right of the cursor without altering the cursor
+ * position. Basically this is what happens with the "Delete" keyboard key. */
+void linenoiseEditDelete(struct linenoiseState *l) {
+ if (l->len > 0 && l->pos < l->len) {
+ memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
+ l->len--;
+ l->buf[l->len] = '\0';
+ linenoiseRefreshLine();
+ }
+}
+
+/* Backspace implementation. */
+void linenoiseEditBackspace(struct linenoiseState *l) {
+ if (l->pos > 0 && l->len > 0) {
+ memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
+ l->pos--;
+ l->len--;
+ l->buf[l->len] = '\0';
+ linenoiseRefreshLine();
+ }
+}
+
+/* Delete the previosu word, maintaining the cursor at the start of the
+ * current word. */
+void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
+ size_t old_pos = l->pos;
+ size_t diff;
+
+ while (l->pos > 0 && l->buf[l->pos-1] == ' ')
+ l->pos--;
+ while (l->pos > 0 && l->buf[l->pos-1] != ' ')
+ l->pos--;
+ diff = old_pos - l->pos;
+ memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
+ l->len -= diff;
+ linenoiseRefreshLine();
+}
+
+/* This function is the core of the line editing capability of linenoise.
+ * It expects 'fd' to be already in "raw mode" so that every key pressed
+ * will be returned ASAP to read().
+ *
+ * The resulting string is put into 'buf' when the user type enter, or
+ * when ctrl+d is typed.
+ *
+ * The function returns the length of the current buffer. */
+static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
+{
+ /* Populate the linenoise state that we pass to functions implementing
+ * specific editing functionalities. */
+ ls.ifd = stdin_fd;
+ ls.ofd = stdout_fd;
+ ls.buf = buf;
+ ls.buflen = buflen;
+ ls.prompt = prompt;
+ ls.plen = strlen(prompt);
+ ls.oldpos = ls.pos = 0;
+ ls.len = 0;
+ ls.cols = getColumns(stdin_fd, stdout_fd);
+ ls.maxrows = 0;
+ ls.history_index = 0;
+
+ /* Buffer starts empty. */
+ ls.buf[0] = '\0';
+ ls.buflen--; /* Make sure there is always space for the nulterm */
+
+ /* The latest history entry is always our current buffer, that
+ * initially is just an empty string. */
+ linenoiseHistoryAdd("");
+
+ if (write(ls.ofd,prompt,ls.plen) == -1) return -1;
+ while(1) {
+ int c = 0, nread;
+ char seq[3];
+
+ nread = read(ls.ifd,&c,1);
+ if (nread <= 0) return ls.len;
+
+ /* Only autocomplete when the callback is set. It returns < 0 when
+ * there was an error reading from fd. Otherwise it will return the
+ * character that should be handled next. */
+ if (c == 9 && completionCallback != NULL) {
+ c = completeLine(&ls);
+ /* Return on errors */
+ if (c < 0) return ls.len;
+ /* Read next character when 0 */
+ if (c == 0) continue;
+ }
+
+ switch(c) {
+ case ENTER: /* enter */
+ history_len--;
+ free(history[history_len]);
+ if (mlmode) linenoiseEditMoveEnd(&ls);
+ return (int)ls.len;
+ case CTRL_C: /* ctrl-c */
+ errno = EAGAIN;
+ return -1;
+ case BACKSPACE: /* backspace */
+ case 8: /* ctrl-h */
+ linenoiseEditBackspace(&ls);
+ break;
+ case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
+ line is empty, act as end-of-file. */
+ if (ls.len > 0) {
+ linenoiseEditDelete(&ls);
+ } else {
+ history_len--;
+ free(history[history_len]);
+ return -1;
+ }
+ break;
+ case CTRL_T: /* ctrl-t, swaps current character with previous. */
+ if (ls.pos > 0 && ls.pos < ls.len) {
+ int aux = buf[ls.pos-1];
+ buf[ls.pos-1] = buf[ls.pos];
+ buf[ls.pos] = aux;
+ if (ls.pos != ls.len-1) ls.pos++;
+ linenoiseRefreshLine();
+ }
+ break;
+ case CTRL_B: /* ctrl-b */
+ linenoiseEditMoveLeft(&ls);
+ break;
+ case CTRL_F: /* ctrl-f */
+ linenoiseEditMoveRight(&ls);
+ break;
+ case CTRL_P: /* ctrl-p */
+ linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
+ break;
+ case CTRL_N: /* ctrl-n */
+ linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
+ break;
+ case ESC: /* escape sequence */
+ /* Read the next two bytes representing the escape sequence.
+ * Use two calls to handle slow terminals returning the two
+ * chars at different times. */
+ if (read(ls.ifd,seq,1) == -1) break;
+ if (read(ls.ifd,seq+1,1) == -1) break;
+
+ /* ESC [ sequences. */
+ if (seq[0] == '[') {
+ if (seq[1] >= '0' && seq[1] <= '9') {
+ /* Extended escape, read additional byte. */
+ if (read(ls.ifd,seq+2,1) == -1) break;
+ if (seq[2] == '~') {
+ switch(seq[1]) {
+ case '3': /* Delete key. */
+ linenoiseEditDelete(&ls);
+ break;
+ }
+ }
+ } else {
+ switch(seq[1]) {
+ case 'A': /* Up */
+ linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_PREV);
+ break;
+ case 'B': /* Down */
+ linenoiseEditHistoryNext(&ls, LINENOISE_HISTORY_NEXT);
+ break;
+ case 'C': /* Right */
+ linenoiseEditMoveRight(&ls);
+ break;
+ case 'D': /* Left */
+ linenoiseEditMoveLeft(&ls);
+ break;
+ case 'H': /* Home */
+ linenoiseEditMoveHome(&ls);
+ break;
+ case 'F': /* End*/
+ linenoiseEditMoveEnd(&ls);
+ break;
+ }
+ }
+ }
+
+ /* ESC O sequences. */
+ else if (seq[0] == 'O') {
+ switch(seq[1]) {
+ case 'H': /* Home */
+ linenoiseEditMoveHome(&ls);
+ break;
+ case 'F': /* End*/
+ linenoiseEditMoveEnd(&ls);
+ break;
+ }
+ }
+ break;
+ default:
+ if (linenoiseEditInsert(&ls,c)) return -1;
+ break;
+ case CTRL_U: /* Ctrl+u, delete the whole line. */
+ buf[0] = '\0';
+ ls.pos = ls.len = 0;
+ linenoiseRefreshLine();
+ break;
+ case CTRL_K: /* Ctrl+k, delete from current to end of line. */
+ buf[ls.pos] = '\0';
+ ls.len = ls.pos;
+ linenoiseRefreshLine();
+ break;
+ case CTRL_A: /* Ctrl+a, go to the start of the line */
+ linenoiseEditMoveHome(&ls);
+ break;
+ case CTRL_E: /* ctrl+e, go to the end of the line */
+ linenoiseEditMoveEnd(&ls);
+ break;
+ case CTRL_L: /* ctrl+l, clear screen */
+ linenoiseClearScreen();
+ linenoiseRefreshLine();
+ break;
+ case CTRL_W: /* ctrl+w, delete previous word */
+ linenoiseEditDeletePrevWord(&ls);
+ break;
+ }
+ }
+ return ls.len;
+}
+
+/* This special mode is used by linenoise in order to print scan codes
+ * on screen for debugging / development purposes. It is implemented
+ * by the linenoise_example program using the --keycodes option. */
+void linenoisePrintKeyCodes(void) {
+ char quit[4];
+
+ printf("Linenoise key codes debugging mode.\n"
+ "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
+ if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return;
+ memset(quit,' ',4);
+ while(1) {
+ char c;
+ int nread;
+
+ nread = read(STDIN_FILENO,&c,1);
+ if (nread <= 0) continue;
+ memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
+ quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
+ if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
+
+ printf("'%c' %02x (%d) (type quit to exit)\n",
+ isprint(c) ? c : '?', (int)c, (int)c);
+ printf("\r"); /* Go left edge manually, we are in raw mode. */
+ fflush(stdout);
+ }
+ linenoiseDisableRawMode(STDIN_FILENO);
+}
+
+/* This function calls the line editing function linenoiseEdit() using
+ * the STDIN file descriptor set in raw mode. */
+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
+ int count;
+
+ if (buflen == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!isatty(STDIN_FILENO)) {
+ /* Not a tty: read from file / pipe. */
+ if (fgets(buf, buflen, stdin) == NULL) return -1;
+ count = strlen(buf);
+ if (count && buf[count-1] == '\n') {
+ count--;
+ buf[count] = '\0';
+ }
+ } else {
+ /* Interactive editing. */
+ if (linenoiseEnableRawMode(STDIN_FILENO) == -1) return -1;
+ count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
+ linenoiseDisableRawMode(STDIN_FILENO);
+ printf("\n");
+ }
+ return count;
+}
+
+/* The high level function that is the main API of the linenoise library.
+ * This function checks if the terminal has basic capabilities, just checking
+ * for a blacklist of stupid terminals, and later either calls the line
+ * editing function or uses dummy fgets() so that you will be able to type
+ * something even in the most desperate of the conditions. */
+char *linenoise(const char *prompt) {
+ char buf[LINENOISE_MAX_LINE];
+ int count;
+
+ if (isUnsupportedTerm()) {
+ size_t len;
+
+ printf("%s",prompt);
+ fflush(stdout);
+ if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
+ len = strlen(buf);
+ while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
+ len--;
+ buf[len] = '\0';
+ }
+ return strdup(buf);
+ } else {
+ count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
+ if (count == -1) return NULL;
+ return strdup(buf);
+ }
+}
+
+/* ================================ History ================================= */
+
+/* Free the history, but does not reset it. Only used when we have to
+ * exit() to avoid memory leaks are reported by valgrind & co. */
+static void freeHistory(void) {
+ if (history) {
+ int j;
+
+ for (j = 0; j < history_len; j++)
+ free(history[j]);
+ free(history);
+ }
+}
+
+/* At exit we'll try to fix the terminal to the initial conditions. */
+static void linenoiseAtExit(void) {
+ linenoiseDisableRawMode(STDIN_FILENO);
+ freeHistory();
+}
+
+/* This is the API call to add a new entry in the linenoise history.
+ * It uses a fixed array of char pointers that are shifted (memmoved)
+ * when the history max length is reached in order to remove the older
+ * entry and make room for the new one, so it is not exactly suitable for huge
+ * histories, but will work well for a few hundred of entries.
+ *
+ * Using a circular buffer is smarter, but a bit more complex to handle. */
+int linenoiseHistoryAdd(const char *line) {
+ char *linecopy;
+
+ if (history_max_len == 0) return 0;
+
+ /* Initialization on first call. */
+ if (history == NULL) {
+ history = malloc(sizeof(char*)*history_max_len);
+ if (history == NULL) return 0;
+ memset(history,0,(sizeof(char*)*history_max_len));
+ }
+
+ /* Don't add duplicated lines. */
+ if (history_len && !strcmp(history[history_len-1], line)) return 0;
+
+ /* Add an heap allocated copy of the line in the history.
+ * If we reached the max length, remove the older line. */
+ linecopy = strdup(line);
+ if (!linecopy) return 0;
+ if (history_len == history_max_len) {
+ free(history[0]);
+ memmove(history,history+1,sizeof(char*)*(history_max_len-1));
+ history_len--;
+ }
+ history[history_len] = linecopy;
+ history_len++;
+ return 1;
+}
+
+/* Set the maximum length for the history. This function can be called even
+ * if there is already some history, the function will make sure to retain
+ * just the latest 'len' elements if the new history length value is smaller
+ * than the amount of items already inside the history. */
+int linenoiseHistorySetMaxLen(int len) {
+ char **new;
+
+ if (len < 1) return 0;
+ if (history) {
+ int tocopy = history_len;
+
+ new = malloc(sizeof(char*)*len);
+ if (new == NULL) return 0;
+
+ /* If we can't copy everything, free the elements we'll not use. */
+ if (len < tocopy) {
+ int j;
+
+ for (j = 0; j < tocopy-len; j++) free(history[j]);
+ tocopy = len;
+ }
+ memset(new,0,sizeof(char*)*len);
+ memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
+ free(history);
+ history = new;
+ }
+ history_max_len = len;
+ if (history_len > history_max_len)
+ history_len = history_max_len;
+ return 1;
+}
+
+/* Save the history in the specified file. On success 0 is returned
+ * otherwise -1 is returned. */
+int linenoiseHistorySave(const char *filename) {
+ FILE *fp = fopen(filename,"w");
+ int j;
+
+ if (fp == NULL) return -1;
+ for (j = 0; j < history_len; j++)
+ fprintf(fp,"%s\n",history[j]);
+ fclose(fp);
+ return 0;
+}
+
+/* Load the history from the specified file. If the file does not exist
+ * zero is returned and no operation is performed.
+ *
+ * If the file exists and the operation succeeded 0 is returned, otherwise
+ * on error -1 is returned. */
+int linenoiseHistoryLoad(const char *filename) {
+ FILE *fp = fopen(filename,"r");
+ char buf[LINENOISE_MAX_LINE];
+
+ if (fp == NULL) return -1;
+
+ while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
+ char *p;
+
+ p = strchr(buf,'\r');
+ if (!p) p = strchr(buf,'\n');
+ if (p) *p = '\0';
+ linenoiseHistoryAdd(buf);
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/tools/lint/linenoise/linenoise.h b/tools/lint/linenoise/linenoise.h
new file mode 100644
index 0000000..c708990
--- /dev/null
+++ b/tools/lint/linenoise/linenoise.h
@@ -0,0 +1,92 @@
+/* linenoise.h -- VERSION 1.0
+ *
+ * Guerrilla line editing library against the idea that a line editing lib
+ * needs to be 20,000 lines of C code.
+ *
+ * See linenoise.c for more information.
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINENOISE_H
+#define __LINENOISE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct linenoiseState {
+ int ifd; /* Terminal stdin file descriptor. */
+ int ofd; /* Terminal stdout file descriptor. */
+ char *buf; /* Edited line buffer. */
+ size_t buflen; /* Edited line buffer size. */
+ const char *prompt; /* Prompt to display. */
+ size_t plen; /* Prompt length. */
+ size_t pos; /* Current cursor position. */
+ size_t oldpos; /* Previous refresh cursor position. */
+ size_t len; /* Current edited line length. */
+ size_t cols; /* Number of columns in terminal. */
+ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
+ int rawmode;
+ int history_index; /* The history index we are currently editing. */
+};
+
+extern struct linenoiseState ls;
+
+typedef struct linenoiseCompletions {
+ int path;
+ size_t len;
+ char **cvec;
+} linenoiseCompletions;
+
+typedef void(linenoiseCompletionCallback)(const char *, const char *, linenoiseCompletions *);
+void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
+void linenoiseAddCompletion(linenoiseCompletions *, const char *);
+
+char *linenoise(const char *prompt);
+int linenoiseHistoryAdd(const char *line);
+int linenoiseHistorySetMaxLen(int len);
+int linenoiseHistorySave(const char *filename);
+int linenoiseHistoryLoad(const char *filename);
+void linenoiseClearScreen(void);
+void linenoiseSetMultiLine(int ml);
+void linenoisePrintKeyCodes(void);
+
+void linenoisePathCompletion(const char *, const char *, linenoiseCompletions *);
+void linenoiseRefreshLine(void);
+int linenoiseEnableRawMode(int fd);
+void linenoiseDisableRawMode(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LINENOISE_H */
diff --git a/tools/lint/main.c b/tools/lint/main.c
new file mode 100644
index 0000000..6b257da
--- /dev/null
+++ b/tools/lint/main.c
@@ -0,0 +1,111 @@
+/**
+ * @file main.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang's yanglint tool
+ *
+ * Copyright (c) 2015-2017 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "commands.h"
+#include "configuration.h"
+#include "completion.h"
+#include "./linenoise/linenoise.h"
+#include "libyang.h"
+
+int done;
+struct ly_ctx *ctx = NULL;
+
+/* main_ni.c */
+int main_ni(int argc, char *argv[]);
+
+int
+main(int argc, char* argv[])
+{
+ char *cmd, *cmdline, *cmdstart;
+ int i, j;
+
+ if (argc > 1) {
+ /* run in non-interactive mode */
+ return main_ni(argc, argv);
+ }
+
+ /* continue in interactive mode */
+ linenoiseSetCompletionCallback(complete_cmd);
+ load_config();
+
+ if (ly_ctx_new(NULL, 0, &ctx)) {
+ fprintf(stderr, "Failed to create context.\n");
+ return 1;
+ }
+
+ while (!done) {
+ /* get the command from user */
+ cmdline = linenoise(PROMPT);
+
+ /* EOF -> exit */
+ if (cmdline == NULL) {
+ done = 1;
+ cmdline = strdup("quit");
+ }
+
+ /* empty line -> wait for another command */
+ if (*cmdline == '\0') {
+ free(cmdline);
+ continue;
+ }
+
+ /* isolate the command word. */
+ for (i = 0; cmdline[i] && (cmdline[i] == ' '); i++);
+ cmdstart = cmdline + i;
+ for (j = 0; cmdline[i] && (cmdline[i] != ' '); i++, j++);
+ cmd = strndup(cmdstart, j);
+
+ /* parse the command line */
+ for (i = 0; commands[i].name; i++) {
+ if (strcmp(cmd, commands[i].name) == 0) {
+ break;
+ }
+ }
+
+ /* execute the command if any valid specified */
+ if (commands[i].name) {
+ /* display help */
+ if ((strchr(cmdstart, ' ') != NULL) && ((strncmp(strchr(cmdstart, ' ')+1, "-h", 2) == 0)
+ || (strncmp(strchr(cmdstart, ' ')+1, "--help", 6) == 0))) {
+ if (commands[i].help_func != NULL) {
+ commands[i].help_func();
+ } else {
+ printf("%s\n", commands[i].helpstring);
+ }
+ } else {
+ commands[i].func((const char *)cmdstart);
+ }
+ } else {
+ /* if unknown command specified, tell it to user */
+ fprintf(stderr, "%s: no such command, type 'help' for more information.\n", cmd);
+ }
+ linenoiseHistoryAdd(cmdline);
+
+ free(cmd);
+ free(cmdline);
+ }
+
+ store_config();
+ ly_ctx_destroy(ctx, NULL);
+
+ return 0;
+}
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
new file mode 100644
index 0000000..892d242
--- /dev/null
+++ b/tools/lint/main_ni.c
@@ -0,0 +1,1099 @@
+/**
+ * @file main_ni.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang's yanglint tool - noninteractive code
+ *
+ * Copyright (c) 2015-2018 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.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "commands.h"
+#include "libyang.h"
+
+volatile uint8_t verbose = 0;
+
+#if 0
+/* from commands.c */
+int print_list(FILE *out, struct ly_ctx *ctx, LYD_FORMAT outformat);
+#endif
+
+void
+help(int shortout)
+{
+ fprintf(stdout, "Usage:\n");
+ fprintf(stdout, " yanglint [options] [-f { yang | yin | tree | tree-rfc | jsons}] <file>...\n");
+ fprintf(stdout, " Validates the YANG module in <file>, and all its dependencies.\n\n");
+ fprintf(stdout, " yanglint [options] [-f { xml | json }] <schema>... <file>...\n");
+ fprintf(stdout, " Validates the YANG modeled data in <file> according to the <schema>.\n\n");
+ fprintf(stdout, " yanglint\n");
+ fprintf(stdout, " Starts interactive mode with more features.\n\n");
+
+ if (shortout) {
+ return;
+ }
+ fprintf(stdout, "Options:\n"
+ " -h, --help Show this help message and exit.\n"
+ " -v, --version Show version number and exit.\n"
+ " -V, --verbose Show verbose messages, can be used multiple times to\n"
+ " increase verbosity.\n"
+#ifndef NDEBUG
+ " -G GROUPS, --debug=GROUPS\n"
+ " Enable printing of specific debugging message group\n"
+ " (nothing will be printed unless verbosity is set to debug):\n"
+ " <group>[,<group>]* (dict, yang, yin, xpath, diff)\n\n"
+#endif
+ " -p PATH, --path=PATH Search path for schema (YANG/YIN) modules. The option can be used multiple times.\n"
+ " Current working directory and path of the module being added is used implicitly.\n\n"
+ " -D, --disable-searchdir\n"
+ " Do not implicitly search in CWD for schema modules. If specified a second time,\n"
+ " do not even search the module directory (all modules must be explicitly specified).\n\n"
+ " -s, --strict Strict data parsing (do not skip unknown data),\n"
+ " has no effect for schemas.\n\n"
+ " -m, --merge Merge input data files into a single tree and validate at once,\n"
+ " has no effect for the auto, rpc, rpcreply and notif TYPEs.\n\n"
+ " -f FORMAT, --format=FORMAT\n"
+ " Convert to FORMAT. Supported formats: \n"
+ " yang, yin, tree and jsons (JSON) for schemas,\n"
+ " xml, json for data.\n"
+ " -a, --auto Modify the xml output by adding envelopes for autodetection.\n\n"
+ " -i, --allimplemented Make all the imported modules implemented.\n\n"
+ " -l, --list Print info about the loaded schemas in ietf-yang-library format,\n"
+ " the -f option applies here to specify data encoding.\n"
+ " (i - imported module, I - implemented module)\n\n"
+ " -o OUTFILE, --output=OUTFILE\n"
+ " Write the output to OUTFILE instead of stdout.\n\n"
+ " -F FEATURES, --features=FEATURES\n"
+ " Features to support, default all.\n"
+ " <modname>:[<feature>,]*\n\n"
+ " -d MODE, --default=MODE\n"
+ " Print data with default values, according to the MODE\n"
+ " (to print attributes, ietf-netconf-with-defaults model\n"
+ " must be loaded):\n"
+ " all - Add missing default nodes.\n"
+ " all-tagged - Add missing default nodes and mark all the default\n"
+ " nodes with the attribute.\n"
+ " trim - Remove all nodes with a default value.\n"
+ " implicit-tagged - Add missing nodes and mark them with the attribute.\n\n"
+ " -t TYPE, --type=TYPE\n"
+ " Specify data tree type in the input data file:\n"
+ " auto - Resolve data type (one of the following) automatically\n"
+ " (as pyang does) - applicable only on XML input data.\n"
+ " data - Complete datastore with status data (default type).\n"
+ " config - Configuration datastore (without status data).\n"
+ " get - Result of the NETCONF <get> operation.\n"
+ " getconfig - Result of the NETCONF <get-config> operation.\n"
+ " edit - Content of the NETCONF <edit-config> operation.\n"
+ " rpc - Content of the NETCONF <rpc> message, defined as YANG's rpc input statement.\n"
+ " rpcreply - Reply to the RPC. The input data <file>s are expected in pairs - each RPC reply\n"
+ " input data <file> must be followed by the origin RPC input data <file> for the reply.\n"
+ " The same rule of pairing applies also in case of 'auto' TYPE and input data file\n"
+ " containing RPC reply.\n"
+ " notif - Notification instance (content of the <notification> element without <eventTime>.\n\n"
+ " -O FILE, --operational=FILE\n"
+ " - Optional parameter for 'rpc', 'rpcreply' and 'notif' TYPEs, the FILE contains running\n"
+ " configuration datastore and state data (operational datastore) referenced from\n"
+ " the RPC/Notification. The same data apply to all input data <file>s. Note that\n"
+ " the file is validated as 'data' TYPE. Special value '!' can be used as FILE argument\n"
+ " to ignore the external references.\n\n"
+ " -y YANGLIB_PATH - Path to a yang-library data describing the initial context.\n\n"
+ "Tree output specific options:\n"
+ " --tree-help - Print help on tree symbols and exit.\n"
+ " --tree-print-groupings\n"
+ " Print top-level groupings in a separate section.\n"
+ " --tree-print-uses - Print uses nodes instead the resolved grouping nodes.\n"
+ " --tree-no-leafref-target\n"
+ " Do not print target nodes of leafrefs.\n"
+ " --tree-path=SCHEMA_PATH\n"
+ " Print only the specified subtree.\n"
+ " --tree-line-length=LINE_LENGTH\n"
+ " Wrap lines if longer than the specified length (it is not a strict limit, longer lines\n"
+ " can often appear).\n"
+ "\n");
+}
+
+void
+tree_help(void)
+{
+ fprintf(stdout, "Each node is printed as:\n\n");
+ fprintf(stdout, "<status> <flags> <name> <opts> <type> <if-features>\n\n"
+ " <status> is one of:\n"
+ " + for current\n"
+ " x for deprecated\n"
+ " o for obsolete\n\n"
+ " <flags> is one of:\n"
+ " rw for configuration data\n"
+ " ro for status data\n"
+ " -x for RPCs\n"
+ " -n for Notification\n\n"
+ " <name> is the name of the node\n"
+ " (<name>) means that the node is a choice node\n"
+ " :(<name>) means that the node is a case node\n\n"
+ " if the node is augmented into the tree from another module,\n"
+ " it is printed with the module name as <module-name>:<name>.\n\n"
+ " <opts> is one of:\n"
+ " ? for an optional leaf or choice\n"
+ " ! for a presence container\n"
+ " * for a leaf-list or list\n"
+ " [<keys>] for a list's keys\n\n"
+ " <type> is the name of the type for leafs and leaf-lists\n"
+ " If there is a default value defined, it is printed within\n"
+ " angle brackets <default-value>.\n"
+ " If the type is a leafref, the type is printed as -> TARGET`\n\n"
+ " <if-features> is the list of features this node depends on,\n"
+ " printed within curly brackets and a question mark {...}?\n\n");
+}
+
+void
+version(void)
+{
+ fprintf(stdout, "yanglint %s\n", PROJECT_VERSION);
+}
+
+void
+libyang_verbclb(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+ char *levstr;
+
+ if (level <= verbose) {
+ switch(level) {
+ case LY_LLERR:
+ levstr = "err :";
+ break;
+ case LY_LLWRN:
+ levstr = "warn:";
+ break;
+ case LY_LLVRB:
+ levstr = "verb:";
+ break;
+ default:
+ levstr = "dbg :";
+ break;
+ }
+ if (path) {
+ fprintf(stderr, "%s %s (%s)\n", levstr, msg, path);
+ } else {
+ fprintf(stderr, "%s %s\n", levstr, msg);
+ }
+ }
+}
+
+/*
+ * return:
+ * 0 - error
+ * 1 - schema format
+ * 2 - data format
+ */
+static int
+get_fileformat(const char *filename, LYS_INFORMAT *schema/* TODO , LYD_FORMAT *data */)
+{
+ char *ptr;
+ LYS_INFORMAT informat_s;
+#if 0
+ LYD_FORMAT informat_d;
+#endif
+ /* get the file format */
+ if ((ptr = strrchr(filename, '.')) != NULL) {
+ ++ptr;
+ if (!strcmp(ptr, "yang")) {
+ informat_s = LYS_IN_YANG;
+#if 0
+ informat_d = 0;
+ } else if (!strcmp(ptr, "yin")) {
+ informat_s = LYS_IN_YIN;
+ informat_d = 0;
+ } else if (!strcmp(ptr, "xml")) {
+ informat_s = 0;
+ informat_d = LYD_XML;
+ } else if (!strcmp(ptr, "json")) {
+ informat_s = 0;
+ informat_d = LYD_JSON;
+#endif
+ } else {
+ fprintf(stderr, "yanglint error: input file in an unknown format \"%s\".\n", ptr);
+ return 0;
+ }
+ } else {
+ fprintf(stderr, "yanglint error: input file \"%s\" without file extension - unknown format.\n", filename);
+ return 0;
+ }
+#if 0
+ if (data) {
+ (*data) = informat_d;
+ }
+#endif
+ if (schema) {
+ (*schema) = informat_s;
+ }
+
+ if (informat_s) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+int
+main_ni(int argc, char* argv[])
+{
+ int ret = EXIT_FAILURE;
+ int opt, opt_index = 0, i, featsize = 0;
+ struct option options[] = {
+#if 0
+ {"auto", no_argument, NULL, 'a'},
+ {"default", required_argument, NULL, 'd'},
+#endif
+ {"format", required_argument, NULL, 'f'},
+ {"features", required_argument, NULL, 'F'},
+#if 0
+ {"tree-print-groupings", no_argument, NULL, 'g'},
+ {"tree-print-uses", no_argument, NULL, 'u'},
+ {"tree-no-leafref-target", no_argument, NULL, 'n'},
+ {"tree-path", required_argument, NULL, 'P'},
+ {"tree-line-length", required_argument, NULL, 'L'},
+#endif
+ {"help", no_argument, NULL, 'h'},
+#if 0
+ {"tree-help", no_argument, NULL, 'H'},
+#endif
+ {"allimplemented", no_argument, NULL, 'i'},
+ {"disable-cwd-search", no_argument, NULL, 'D'},
+ {"list", no_argument, NULL, 'l'},
+#if 0
+ {"merge", no_argument, NULL, 'm'},
+#endif
+ {"output", required_argument, NULL, 'o'},
+ {"path", required_argument, NULL, 'p'},
+#if 0
+ {"running", required_argument, NULL, 'r'},
+ {"operational", required_argument, NULL, 'O'},
+ {"strict", no_argument, NULL, 's'},
+ {"type", required_argument, NULL, 't'},
+#endif
+ {"version", no_argument, NULL, 'v'},
+ {"verbose", no_argument, NULL, 'V'},
+#ifndef NDEBUG
+ {"debug", required_argument, NULL, 'G'},
+#endif
+ {NULL, required_argument, NULL, 'y'},
+ {NULL, 0, NULL, 0}
+ };
+ FILE *out = stdout;
+ struct ly_ctx *ctx = NULL;
+ const struct lys_module *mod;
+ LYS_OUTFORMAT outformat_s = 0;
+ LYS_INFORMAT informat_s;
+#if 0
+ LYD_FORMAT informat_d, outformat_d = 0, ylformat = 0;
+#endif
+ struct ly_set *searchpaths = NULL;
+ const char *outtarget_s = NULL;
+ char **feat = NULL, *ptr, *featlist, *dir;
+ struct stat st;
+ uint32_t u;
+ int options_ctx = LY_CTX_NOYANGLIBRARY, list = 0, outoptions_s = 0, outline_length_s = 0;
+#if 0
+ const char *oper_file = NULL, *envelope_s = NULL;
+ char *ylpath = NULL;
+ int options_dflt = 0, options_parser = 0, envelope = 0, autodetection = 0, merge = 0;
+ struct dataitem {
+ const char *filename;
+ struct lyxml_elem *xml;
+ struct lyd_node *tree;
+ struct dataitem *next;
+ LYD_FORMAT format;
+ int type;
+ } *data = NULL, *data_item, *data_prev = NULL;
+ struct lyxml_elem *iter, *elem;
+ struct lyd_node *oper = NULL, *subroot, *next, *node;
+#endif
+ struct ly_set *mods = NULL;
+ void *p;
+ int index = 0;
+
+ opterr = 0;
+#ifndef NDEBUG
+ while ((opt = getopt_long(argc, argv, "ad:f:F:gunP:L:hHiDlmo:p:r:O:st:vVG:y:", options, &opt_index)) != -1)
+#else
+ while ((opt = getopt_long(argc, argv, "ad:f:F:gunP:L:hHiDlmo:p:r:O:st:vVy:", options, &opt_index)) != -1)
+#endif
+ {
+ switch (opt) {
+#if 0
+ case 'a':
+ envelope = 1;
+ break;
+ case 'd':
+ if (!strcmp(optarg, "all")) {
+ options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_ALL;
+ } else if (!strcmp(optarg, "all-tagged")) {
+ options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_ALL_TAG;
+ } else if (!strcmp(optarg, "trim")) {
+ options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_TRIM;
+ } else if (!strcmp(optarg, "implicit-tagged")) {
+ options_dflt = (options_dflt & ~LYP_WD_MASK) | LYP_WD_IMPL_TAG;
+ } else {
+ fprintf(stderr, "yanglint error: unknown default mode %s\n", optarg);
+ help(1);
+ goto cleanup;
+ }
+ break;
+#endif
+ case 'f':
+ if (!strcasecmp(optarg, "yang")) {
+ outformat_s = LYS_OUT_YANG;
+#if 0
+ outformat_d = 0;
+ } else if (!strcasecmp(optarg, "tree")) {
+ outformat_s = LYS_OUT_TREE;
+ outformat_d = 0;
+ } else if (!strcasecmp(optarg, "tree-rfc")) {
+ outformat_s = LYS_OUT_TREE;
+ outoptions_s |= LYS_OUTOPT_TREE_RFC;
+ outformat_d = 0;
+ } else if (!strcasecmp(optarg, "yin")) {
+ outformat_s = LYS_OUT_YIN;
+ outformat_d = 0;
+ } else if (!strcasecmp(optarg, "jsons")) {
+ outformat_s = LYS_OUT_JSON;
+ outformat_d = 0;
+ } else if (!strcasecmp(optarg, "xml")) {
+ outformat_s = 0;
+ outformat_d = LYD_XML;
+ } else if (!strcasecmp(optarg, "json")) {
+ outformat_s = 0;
+ outformat_d = LYD_JSON;
+#endif
+ } else {
+ fprintf(stderr, "yanglint error: unknown output format %s\n", optarg);
+ help(1);
+ goto cleanup;
+ }
+ break;
+ case 'F':
+ featsize++;
+ if (!feat) {
+ p = malloc(sizeof *feat);
+ } else {
+ p = realloc(feat, featsize * sizeof *feat);
+ }
+ if (!p) {
+ fprintf(stderr, "yanglint error: Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno));
+ goto cleanup;
+ }
+ feat = p;
+ feat[featsize - 1] = strdup(optarg);
+ ptr = strchr(feat[featsize - 1], ':');
+ if (!ptr) {
+ fprintf(stderr, "yanglint error: Invalid format of the features specification (%s)", optarg);
+ goto cleanup;
+ }
+ *ptr = '\0';
+
+ break;
+#if 0
+ case 'g':
+ outoptions_s |= LYS_OUTOPT_TREE_GROUPING;
+ break;
+ case 'u':
+ outoptions_s |= LYS_OUTOPT_TREE_USES;
+ break;
+ case 'n':
+ outoptions_s |= LYS_OUTOPT_TREE_NO_LEAFREF;
+ break;
+ case 'P':
+ outtarget_s = optarg;
+ break;
+ case 'L':
+ outline_length_s = atoi(optarg);
+ break;
+#endif
+ case 'h':
+ help(0);
+ ret = EXIT_SUCCESS;
+ goto cleanup;
+#if 0
+ case 'H':
+ tree_help();
+ ret = EXIT_SUCCESS;
+ goto cleanup;
+#endif
+ case 'i':
+ options_ctx |= LY_CTX_ALLIMPLEMENTED;
+ break;
+ case 'D':
+ if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
+ fprintf(stderr, "yanglint error: -D specified too many times.\n");
+ goto cleanup;
+ } else if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
+ options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
+ options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
+ } else {
+ options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
+ }
+ break;
+ case 'l':
+ list = 1;
+ break;
+#if 0
+ case 'm':
+ merge = 1;
+ break;
+#endif
+ case 'o':
+ if (out != stdout) {
+ fclose(out);
+ }
+ out = fopen(optarg, "w");
+ if (!out) {
+ fprintf(stderr, "yanglint error: unable open output file %s (%s)\n", optarg, strerror(errno));
+ goto cleanup;
+ }
+ break;
+ case 'p':
+ if (stat(optarg, &st) == -1) {
+ fprintf(stderr, "yanglint error: Unable to use search path (%s) - %s.\n", optarg, strerror(errno));
+ goto cleanup;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "yanglint error: Provided search path is not a directory.\n");
+ goto cleanup;
+ }
+ if (!searchpaths) {
+ searchpaths = ly_set_new();
+ }
+ ly_set_add(searchpaths, optarg, 0);
+ break;
+#if 0
+ case 'r':
+ case 'O':
+ if (oper_file || (options_parser & LYD_OPT_NOEXTDEPS)) {
+ fprintf(stderr, "yanglint error: The operational datastore (-O) cannot be set multiple times.\n");
+ goto cleanup;
+ }
+ if (optarg[0] == '!') {
+ /* ignore extenral dependencies to the operational datastore */
+ options_parser |= LYD_OPT_NOEXTDEPS;
+ } else {
+ /* external file with the operational datastore */
+ oper_file = optarg;
+ }
+ break;
+ case 's':
+ options_parser |= LYD_OPT_STRICT;
+ break;
+ case 't':
+ if (!strcmp(optarg, "auto")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK);
+ autodetection = 1;
+ } else if (!strcmp(optarg, "config")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+ } else if (!strcmp(optarg, "get")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+ } else if (!strcmp(optarg, "getconfig")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+ } else if (!strcmp(optarg, "edit")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+ } else if (!strcmp(optarg, "data")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_NO_YANGLIB;
+ } else if (!strcmp(optarg, "rpc")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+ } else if (!strcmp(optarg, "rpcreply")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY;
+ } else if (!strcmp(optarg, "notif")) {
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+ } else {
+ fprintf(stderr, "yanglint error: unknown data tree type %s\n", optarg);
+ help(1);
+ goto cleanup;
+ }
+ break;
+#endif
+ case 'v':
+ version();
+ ret = EXIT_SUCCESS;
+ goto cleanup;
+ case 'V':
+ verbose++;
+ break;
+#ifndef NDEBUG
+ case 'G':
+ u = 0;
+ ptr = optarg;
+ while (ptr[0]) {
+ if (!strncmp(ptr, "dict", 4)) {
+ u |= LY_LDGDICT;
+ ptr += 4;
+ } else if (!strncmp(ptr, "yang", 4)) {
+ u |= LY_LDGYANG;
+ ptr += 4;
+ } else if (!strncmp(ptr, "yin", 3)) {
+ u |= LY_LDGYIN;
+ ptr += 3;
+ } else if (!strncmp(ptr, "xpath", 5)) {
+ u |= LY_LDGXPATH;
+ ptr += 5;
+ } else if (!strncmp(ptr, "diff", 4)) {
+ u |= LY_LDGDIFF;
+ ptr += 4;
+ }
+
+ if (ptr[0]) {
+ if (ptr[0] != ',') {
+ fprintf(stderr, "yanglint error: unknown debug group string \"%s\"\n", optarg);
+ goto cleanup;
+ }
+ ++ptr;
+ }
+ }
+ ly_verb_dbg(u);
+ break;
+#endif
+#if 0
+ case 'y':
+ ptr = strrchr(optarg, '.');
+ if (ptr) {
+ ptr++;
+ if (!strcmp(ptr, "xml")) {
+ ylformat = LYD_XML;
+ } else if (!strcmp(ptr, "json")) {
+ ylformat = LYD_JSON;
+ } else {
+ fprintf(stderr, "yanglint error: yang-library file in an unknown format \"%s\".\n", ptr);
+ goto cleanup;
+ }
+ } else {
+ fprintf(stderr, "yanglint error: yang-library file in an unknown format.\n");
+ goto cleanup;
+ }
+ ylpath = optarg;
+ break;
+#endif
+ default:
+ help(1);
+ if (optopt) {
+ fprintf(stderr, "yanglint error: invalid option: -%c\n", optopt);
+ } else {
+ fprintf(stderr, "yanglint error: invalid option: %s\n", argv[optind - 1]);
+ }
+ goto cleanup;
+ }
+ }
+
+ /* check options compatibility */
+ if (!list && optind >= argc) {
+ help(1);
+ fprintf(stderr, "yanglint error: missing <file> to process\n");
+ goto cleanup;
+ }
+ if (outformat_s && outformat_s != LYS_OUT_TREE && (optind + 1) < argc) {
+ /* we have multiple schemas to be printed as YIN or YANG */
+ fprintf(stderr, "yanglint error: too many schemas to convert and store.\n");
+ goto cleanup;
+ }
+ if (outoptions_s || outtarget_s || outline_length_s) {
+#if 0
+ if (outformat_d || (outformat_s && outformat_s != LYS_OUT_TREE)) {
+ /* we have --tree-print-grouping with other output format than tree */
+ fprintf(stderr,
+ "yanglint warning: --tree options take effect only in case of the tree output format.\n");
+ }
+ }
+ if (merge) {
+ if (autodetection || (options_parser & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF))) {
+ fprintf(stderr, "yanglint warning: merging not allowed, ignoring option -m.\n");
+ merge = 0;
+ } else {
+ /* first, files will be parsed as trusted to allow missing data, then the data trees will be merged
+ * and the result will be validated */
+ options_parser |= LYD_OPT_TRUSTED;
+ }
+#endif
+ }
+#if 0
+ if (!outformat_d && options_dflt) {
+ /* we have options for printing default nodes, but data output not specified */
+ fprintf(stderr, "yanglint warning: default mode is ignored when not printing data.\n");
+ }
+ if (outformat_s && (options_parser || autodetection)) {
+ /* we have options for printing data tree, but output is schema */
+ fprintf(stderr, "yanglint warning: data parser options are ignored when printing schema.\n");
+ }
+ if (oper_file && (!autodetection && !(options_parser & (LYD_OPT_RPC | LYD_OPT_RPCREPLY | LYD_OPT_NOTIF)))) {
+ fprintf(stderr, "yanglint warning: operational datastore applies only to RPCs or Notifications.\n");
+ /* ignore operational datastore file */
+ oper_file = NULL;
+ }
+ if ((options_parser & LYD_OPT_TYPEMASK) == LYD_OPT_DATA) {
+ /* add option to ignore ietf-yang-library data for implicit data type */
+ options_parser |= LYD_OPT_DATA_NO_YANGLIB;
+ }
+#endif
+
+ /* set callback for printing libyang messages */
+ ly_set_log_clb(libyang_verbclb, 1);
+#if 0
+ /* create libyang context */
+ if (ylpath) {
+ ctx = ly_ctx_new_ylpath(searchpaths ? (const char*)searchpaths->set.g[0] : NULL, ylpath, ylformat, options_ctx);
+ } else {
+#else
+ {
+#endif
+ ly_ctx_new(NULL, options_ctx, &ctx);
+ }
+ if (!ctx) {
+ goto cleanup;
+ }
+
+ /* set searchpaths */
+ if (searchpaths) {
+ for (u = 0; u < searchpaths->count; u++) {
+ ly_ctx_set_searchdir(ctx, (const char*)searchpaths->objs[u]);
+ }
+ index = u + 1;
+ }
+
+ /* derefered setting of verbosity in libyang after context initiation */
+ ly_verb(verbose);
+
+ mods = ly_set_new();
+
+
+ /* divide input files */
+ for (i = 0; i < argc - optind; i++) {
+ /* get the file format */
+ if (!get_fileformat(argv[optind + i], &informat_s/* TODO, &informat_d */)) {
+ goto cleanup;
+ }
+
+ if (informat_s) {
+ /* load/validate schema */
+ if (verbose >= 2) {
+ fprintf(stdout, "Validating %s schema file.\n", argv[optind + i]);
+ }
+ dir = strdup(argv[optind + i]);
+ ly_ctx_set_searchdir(ctx, ptr = dirname(dir));
+ mod = lys_parse_path(ctx, argv[optind + i], informat_s);
+ ly_ctx_unset_searchdir(ctx, index);
+ free(dir);
+ if (!mod) {
+ goto cleanup;
+ }
+ ly_set_add(mods, (void *)mod, 0);
+#if 0
+ } else {
+ if (autodetection && informat_d != LYD_XML) {
+ /* data file content autodetection is possible only for XML input */
+ fprintf(stderr, "yanglint error: data type autodetection is applicable only to XML files.\n");
+ goto cleanup;
+ }
+
+ /* remember data filename and its format */
+ if (!data) {
+ data = data_item = malloc(sizeof *data);
+ } else {
+ for (data_item = data; data_item->next; data_item = data_item->next);
+ data_item->next = malloc(sizeof *data_item);
+ data_item = data_item->next;
+ }
+ data_item->filename = argv[optind + i];
+ data_item->format = informat_d;
+ data_item->type = options_parser & LYD_OPT_TYPEMASK;
+ data_item->tree = NULL;
+ data_item->xml = NULL;
+ data_item->next = NULL;
+#endif
+ }
+ }
+#if 0
+ if (outformat_d && !data && !list) {
+ fprintf(stderr, "yanglint error: no input data file for the specified data output format.\n");
+ goto cleanup;
+ }
+#endif
+
+ /* enable specified features, if not specified, all the module's features are enabled */
+ u = 4; /* skip internal libyang modules */
+ while ((mod = ly_ctx_get_module_iter(ctx, &u))) {
+ for (i = 0; i < featsize; i++) {
+ if (!strcmp(feat[i], mod->name)) {
+ /* parse features spec */
+ featlist = strdup(feat[i] + strlen(feat[i]) + 1);
+ ptr = NULL;
+ while((ptr = strtok(ptr ? NULL : featlist, ","))) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Enabling feature %s in module %s.\n", ptr, mod->name);
+ }
+ if (lys_feature_enable(mod, ptr)) {
+ fprintf(stderr, "Feature %s not defined in module %s.\n", ptr, mod->name);
+ }
+ }
+ free(featlist);
+ break;
+ }
+ }
+ if (i == featsize) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Enabling all features in module %s.\n", mod->name);
+ }
+ lys_feature_enable(mod, "*");
+ }
+ }
+
+ /* convert (print) to FORMAT */
+ if (outformat_s) {
+ if (outformat_s == LYS_OUT_JSON && mods->count > 1) {
+ fputs("[", out);
+ }
+ for (u = 0; u < mods->count; u++) {
+ if (u) {
+ if (outformat_s == LYS_OUT_JSON) {
+ fputs(",\n", out);
+ } else {
+ fputs("\n", out);
+ }
+ }
+ lys_print_file(out, (struct lys_module *)mods->objs[u], outformat_s, outline_length_s, outoptions_s);
+ }
+ if (outformat_s == LYS_OUT_JSON) {
+ if (mods->count > 1) {
+ fputs("]\n", out);
+ } else if (mods->count == 1) {
+ fputs("\n", out);
+ }
+ }
+#if 0
+ } else if (data) {
+ ly_errno = 0;
+
+ /* prepare operational datastore when specified for RPC/Notification */
+ if (oper_file) {
+ /* get the file format */
+ if (!get_fileformat(oper_file, NULL, &informat_d)) {
+ goto cleanup;
+ } else if (!informat_d) {
+ fprintf(stderr, "yanglint error: The operational data are expected in XML or JSON format.\n");
+ goto cleanup;
+ }
+ oper = lyd_parse_path(ctx, oper_file, informat_d, LYD_OPT_DATA_NO_YANGLIB | LYD_OPT_TRUSTED);
+ if (!oper) {
+ fprintf(stderr, "yanglint error: Failed to parse the operational datastore file for RPC/Notification validation.\n");
+ goto cleanup;
+ }
+ }
+
+ for (data_item = data, data_prev = NULL; data_item; data_prev = data_item, data_item = data_item->next) {
+ /* parse data file - via LYD_OPT_TRUSTED postpone validation when all data are loaded and merged */
+ if (autodetection) {
+ /* erase option not covered by LYD_OPT_TYPEMASK, but used according to the type */
+ options_parser &= ~LYD_OPT_DATA_NO_YANGLIB;
+ /* automatically detect data type from the data top level */
+ data_item->xml = lyxml_parse_path(ctx, data_item->filename, 0);
+ if (!data_item->xml) {
+ fprintf(stderr, "yanglint error: parsing XML data for data type autodetection failed.\n");
+ goto cleanup;
+ }
+
+ /* NOTE: namespace is ignored to simplify usage of this feature */
+ if (!strcmp(data_item->xml->name, "data")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as complete datastore.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_DATA_NO_YANGLIB;
+ data_item->type = LYD_OPT_DATA;
+ } else if (!strcmp(data_item->xml->name, "config")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as config data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_CONFIG;
+ data_item->type = LYD_OPT_CONFIG;
+ } else if (!strcmp(data_item->xml->name, "get-reply")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <get> reply data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GET;
+ data_item->type = LYD_OPT_GET;
+ } else if (!strcmp(data_item->xml->name, "get-config-reply")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <get-config> reply data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_GETCONFIG;
+ data_item->type = LYD_OPT_GETCONFIG;
+ } else if (!strcmp(data_item->xml->name, "edit-config")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <edit-config> data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_EDIT;
+ data_item->type = LYD_OPT_EDIT;
+ } else if (!strcmp(data_item->xml->name, "rpc")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <rpc> data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC;
+ data_item->type = LYD_OPT_RPC;
+ } else if (!strcmp(data_item->xml->name, "rpc-reply")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <rpc-reply> data.\n", data_item->filename);
+ }
+
+ data_item->type = LYD_OPT_RPCREPLY;
+ if (!data_item->next || (data_prev && !data_prev->tree)) {
+ fprintf(stderr, "RPC reply (%s) must be paired with the original RPC, see help.\n", data_item->filename);
+ goto cleanup;
+ }
+
+ continue;
+ } else if (!strcmp(data_item->xml->name, "notification")) {
+ if (verbose >= 2) {
+ fprintf(stdout, "Parsing %s as <notification> data.\n", data_item->filename);
+ }
+ options_parser = (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_NOTIF;
+ data_item->type = LYD_OPT_NOTIF;
+
+ /* ignore eventTime element if present */
+ while (data_item->xml->child && !strcmp(data_item->xml->child->name, "eventTime")) {
+ lyxml_free(ctx, data_item->xml->child);
+ }
+ } else {
+ fprintf(stderr, "yanglint error: invalid top-level element \"%s\" for data type autodetection.\n",
+ data_item->xml->name);
+ goto cleanup;
+ }
+
+ data_item->tree = lyd_parse_xml(ctx, &data_item->xml->child, options_parser, oper);
+ if (data_prev && data_prev->type == LYD_OPT_RPCREPLY) {
+parse_reply:
+ /* check result of the RPC parsing, we are going to do another parsing in this step */
+ if (ly_errno) {
+ goto cleanup;
+ }
+
+ /* check that we really have RPC for the reply */
+ if (data_item->type != LYD_OPT_RPC) {
+ fprintf(stderr, "yanglint error: RPC reply (%s) must be paired with the original RPC, see help.\n", data_prev->filename);
+ goto cleanup;
+ }
+
+ if (data_prev->format == LYD_XML) {
+ /* ignore <ok> and <rpc-error> elements if present */
+ u = 0;
+ LY_TREE_FOR_SAFE(data_prev->xml->child, iter, elem) {
+ if (!strcmp(data_prev->xml->child->name, "ok")) {
+ if (u) {
+ /* rpc-error or ok already present */
+ u = 0x8; /* error flag */
+ } else {
+ u = 0x1 | 0x4; /* <ok> flag with lyxml_free() flag */
+ }
+ } else if (!strcmp(data_prev->xml->child->name, "rpc-error")) {
+ if (u && (u & 0x1)) {
+ /* ok already present, rpc-error can be present multiple times */
+ u = 0x8; /* error flag */
+ } else {
+ u = 0x2 | 0x4; /* <rpc-error> flag with lyxml_free() flag */
+ }
+ }
+
+ if (u == 0x8) {
+ fprintf(stderr, "yanglint error: Invalid RPC reply (%s) content.\n", data_prev->filename);
+ goto cleanup;
+ } else if (u & 0x4) {
+ lyxml_free(ctx, data_prev->xml->child);
+ u &= ~0x4; /* unset lyxml_free() flag */
+ }
+ }
+
+ /* finally, parse RPC reply from the previous step */
+ data_prev->tree = lyd_parse_xml(ctx, &data_prev->xml->child,
+ (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY, data_item->tree, oper);
+ } else { /* LYD_JSON */
+ data_prev->tree = lyd_parse_path(ctx, data_prev->filename, data_item->format,
+ (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPCREPLY, data_item->tree, oper);
+ }
+ }
+ } else if ((options_parser & LYD_OPT_TYPEMASK) == LYD_OPT_RPCREPLY) {
+ if (data_prev && !data_prev->tree) {
+ /* now we should have RPC for the preceding RPC reply */
+ data_item->tree = lyd_parse_path(ctx, data_item->filename, data_item->format,
+ (options_parser & ~LYD_OPT_TYPEMASK) | LYD_OPT_RPC, oper);
+ data_item->type = LYD_OPT_RPC;
+ goto parse_reply;
+ } else {
+ /* now we have RPC reply which will be parsed in next step together with its RPC */
+ if (!data_item->next) {
+ fprintf(stderr, "yanglint error: RPC reply (%s) must be paired with the original RPC, see help.\n", data_item->filename);
+ goto cleanup;
+ }
+ if (data_item->format == LYD_XML) {
+ /* create rpc-reply container to unify handling with autodetection */
+ data_item->xml = calloc(1, sizeof *data_item->xml);
+ if (!data_item->xml) {
+ fprintf(stderr, "yanglint error: Memory allocation failed failed.\n");
+ goto cleanup;
+ }
+ data_item->xml->name = lydict_insert(ctx, "rpc-reply", 9);
+ data_item->xml->prev = data_item->xml;
+ data_item->xml->child = lyxml_parse_path(ctx, data_item->filename, LYXML_PARSE_MULTIROOT | LYXML_PARSE_NOMIXEDCONTENT);
+ if (data_item->xml->child) {
+ data_item->xml->child->parent = data_item->xml;
+ }
+ }
+ continue;
+ }
+ } else {
+ data_item->tree = lyd_parse_path(ctx, data_item->filename, data_item->format, options_parser, oper);
+ }
+ if (ly_errno) {
+ goto cleanup;
+ }
+
+ if (merge && data != data_item) {
+ if (!data->tree) {
+ data->tree = data_item->tree;
+ } else if (data_item->tree) {
+ /* merge results */
+ if (lyd_merge(data->tree, data_item->tree, LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
+ fprintf(stderr, "yanglint error: merging multiple data trees failed.\n");
+ goto cleanup;
+ }
+ }
+ data_item->tree = NULL;
+ }
+ }
+
+ if (merge) {
+ /* validate the merged data tree, do not trust the input, invalidate all the data first */
+ LY_TREE_FOR(data->tree, subroot) {
+ LY_TREE_DFS_BEGIN(subroot, next, node) {
+ node->validity = LYD_VAL_OK;
+ switch (node->schema->nodetype) {
+ case LYS_LEAFLIST:
+ case LYS_LEAF:
+ if (((struct lys_node_leaf *)node->schema)->type.base == LY_TYPE_LEAFREF) {
+ node->validity |= LYD_VAL_LEAFREF;
+ }
+ break;
+ case LYS_LIST:
+ node->validity |= LYD_VAL_UNIQUE;
+ /* falls through */
+ case LYS_CONTAINER:
+ case LYS_NOTIF:
+ case LYS_RPC:
+ case LYS_ACTION:
+ node->validity |= LYD_VAL_MAND;
+ break;
+ default:
+ break;
+ }
+ LY_TREE_DFS_END(subroot, next, node)
+ }
+ }
+ if (lyd_validate(&data->tree, options_parser & ~LYD_OPT_TRUSTED, ctx)) {
+ goto cleanup;
+ }
+ }
+
+ /* print only if data output format specified */
+ if (outformat_d) {
+ for (data_item = data; data_item; data_item = data_item->next) {
+ if (!merge && verbose >= 2) {
+ fprintf(stdout, "File %s:\n", data_item->filename);
+ }
+ if (outformat_d == LYD_XML && envelope) {
+ switch (data_item->type) {
+ case LYD_OPT_DATA:
+ envelope_s = "data";
+ break;
+ case LYD_OPT_CONFIG:
+ envelope_s = "config";
+ break;
+ case LYD_OPT_GET:
+ envelope_s = "get-reply";
+ break;
+ case LYD_OPT_GETCONFIG:
+ envelope_s = "get-config-reply";
+ break;
+ case LYD_OPT_EDIT:
+ envelope_s = "edit-config";
+ break;
+ case LYD_OPT_RPC:
+ envelope_s = "rpc";
+ break;
+ case LYD_OPT_RPCREPLY:
+ envelope_s = "rpc-reply";
+ break;
+ case LYD_OPT_NOTIF:
+ envelope_s = "notification";
+ break;
+ }
+ fprintf(out, "<%s>\n", envelope_s);
+ if (data_item->type == LYD_OPT_RPC && data_item->tree->schema->nodetype != LYS_RPC) {
+ /* action */
+ fprintf(out, "<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">\n");
+ }
+ }
+ lyd_print_file(out, (data_item->type == LYD_OPT_RPCREPLY) ? data_item->tree->child : data_item->tree,
+ outformat_d, LYP_WITHSIBLINGS | LYP_FORMAT | options_dflt);
+ if (envelope_s) {
+ if (data_item->type == LYD_OPT_RPC && data_item->tree->schema->nodetype != LYS_RPC) {
+ fprintf(out, "</action>\n");
+ }
+ fprintf(out, "</%s>\n", envelope_s);
+ }
+ if (merge) {
+ /* stop after first item */
+ break;
+ }
+ }
+ }
+#endif
+ }
+#if 0
+ if (list) {
+ print_list(out, ctx, outformat_d);
+ }
+#endif
+
+ ret = EXIT_SUCCESS;
+
+cleanup:
+ if (out && out != stdout) {
+ fclose(out);
+ }
+ ly_set_free(mods, NULL);
+ ly_set_free(searchpaths, NULL);
+ for (i = 0; i < featsize; i++) {
+ free(feat[i]);
+ }
+ free(feat);
+#if 0
+ for (; data; data = data_item) {
+ data_item = data->next;
+ lyxml_free(ctx, data->xml);
+ lyd_free_withsiblings(data->tree);
+ free(data);
+ }
+ lyd_free_withsiblings(oper);
+#endif
+ ly_ctx_destroy(ctx, NULL);
+
+ return ret;
+}
diff --git a/tools/lint/yanglint.1 b/tools/lint/yanglint.1
new file mode 100644
index 0000000..4b7060d
--- /dev/null
+++ b/tools/lint/yanglint.1
@@ -0,0 +1,136 @@
+.\" Manpage for yanglint.
+.\" Process this file with
+.\" groff -man -Tascii yanglint.1
+.\"
+
+.TH YANGLINT 1 "2016-10-27" "libyang"
+.SH NAME
+yanglint \- YANG lint tool
+.
+.SH SYNOPSIS
+.B yanglint
+.br
+.B yanglint
+[\fIOPTIONS\fP]
+[\-f { \fByang\fP | \fByin\fP | \fBtree\fP } ]
+.I FILE ...
+.br
+.B yanglint
+[\fIOPTIONS\fP]
+[\-f { \fBxml\fP | \fBjson\fP } ]
+\fISCHEMA\fP...
+\fIFILE\fP...
+.
+.SH DESCRIPTION
+\fByanglint\fP is a command-line tool for validating and converting YANG
+schemas and the YANG modeled data. For a simple use, it validates the provided
+file and if the output format specified, it converts input data into the output
+format. If started with no argument, \fByanglint\fP opens interactive
+environment where the user is allowed to work with schemas and data in a more
+complex way.
+.
+.SH OPTIONS
+.TP
+.BR "\-h\fR,\fP \-\^\-help"
+Outputs usage help and exits.
+.TP
+.BR "\-v\fR,\fP \-\^\-version"
+Outputs the version number and exits.
+.TP
+.BR "\-V\fR,\fP \-\^\-verbose"
+Increases the verbosity level. If not specified, only errors are printed, with
+each appearance it adds: warnings, verbose messages, debug messages (if compiled
+with debug information).
+.TP
+.BR "\-p \fIPATH\fP\fR,\fP \-\^\-path=\fIPATH\fP"
+Specifies search path for getting imported modules or included submodules. The option
+can be used multiple times. The current working directory and path of the module
+being added is used implicitly.
+.TP
+.BR "\-s\fR,\fP \-\^\-strict"
+Changes handling of unknown data nodes - instead of silently ignoring unknown data,
+error is printed and data parsing fails. This option applies only on data parsing.
+.TP
+.BR "\-f \fIFORMAT\fP\fR,\fP \-\^\-format=\fIFORMAT\fP"
+Converts the content of the input \fIFILE\fPs into the specified \fIFORMAT\fP. If no
+\fIOUTFILE\fP is specified, the data are printed on the standard output. Only the
+compatible formats for the input \fIFILE\fPs are allowed, see the section \fBFORMATS\fP.
+.TP
+.BR "\-o \fIOUTFILE\fP\fR,\fP \-\^\-output=\fIOUTFILE\fP"
+Writes the output data into the specified \fIOUTFILE\fP. The option can be used
+only in combination with \fB--format\fR option. In case of converting schema, only
+a single input schema \fIFILE\fP is allowed. In case of data input \fIFILE\fPs,
+input is merged and printed into a single \fIOUTFILE\fP.
+.TP
+.BR "\-F \fIFEATURES\fP\fR,\fP \-\^\-features=\fIFEATURES\fP"
+Specifies the list of enabled features in the format
+\fIMODULE\fP:[\fIFEATURE\fP,...]. In case of processing multiple modules, the
+option can be used repeatedly. To disable all the features, use an empty list
+specified for the particular module.
+.TP
+.BR "\-d \fIMODE\fP\fR,\fP \-\^\-default=\fIMODE\fP"
+Print data with default values, according to the \fIMODE\fP (to print attributes,
+the ietf-netconf-with-defaults model must be loaded). The \fIMODE\fP is one of the following:
+ \[bu] \fBall\fP - add missing default nodes
+ \[bu] \fBall-tagged\fP - add missing default nodes and mark all the default nodes with the attribute
+ \[bu] \fBtrim\fP - remove all nodes with a default value
+ \[bu] \fBimplicit-tagged\fP - add missing nodes and mark them with the attribute
+.TP
+.BR "\-t \fITYPE\fP\fR,\fP \-\^\-type=\fITYPE\fP"
+Specify data tree type in the input data \fIFILE\fPs. The \fITYPE\fP is one of the following:
+ \[bu] \fBauto\fP - Resolve data type (one of the following) automatically (as pyang does). Applicable only on XML input data.
+ \[bu] \fBdata\fP - Complete datastore with status data (default type).
+ \[bu] \fBconfig\fP - Configuration datastore (without status data).
+ \[bu] \fBget\fP - Result of the NETCONF <get> operation.
+ \[bu] \fBgetconfig\fP - Result of the NETCONF <get-config> operation.
+ \[bu] \fBedit\fP - Content of the NETCONF <edit-config> operation.
+ \[bu] \fBrpc\fP - Content of the NETCONF <rpc> message, defined as YANG's rpc input statement.
+ \[bu] \fBrpcreply\fP - Reply to the RPC. This is just a virtual \fITYPE\fP, for parsing replies, '\fBauto\fP' must be used since the data \fIFILE\fPs are expected in pairs.
+.br
+ The first input data \fIFILE\fP is expected as '\fBrpc\fP' \fITYPE\fP, the second \fIFILE\fP is expected as reply to the previous RPC.
+ \[bu] \fBnotif\fP - Notification instance (content of the <notification> element without <eventTime>.
+.TP
+.BR "\-O \fIFILE\fP\fR,\fP \-\^\-operational=\fIFILE\fP]
+Optional parameter for '\fBrpc\fP' and '\fBnotif\fP' \fITYPE\fPs, the \fIFILE\fP contains running configuration datastore and
+state data referenced from the RPC/Notification. The same data apply to all input data \fIFILE\fPs. Note that the file
+is validated as '\fBdata\fP' \fITYPE\fP. Special value '\fB!\fP' can be used as \fIFILE\fP argument to ignore the external references.
+.TP
+.BR "\-y \fIYANGLIB_PATH\fP"
+Specify path to a yang-library data file (XML or JSON) describing the initial context.
+If provided, yanglint loads the modules according to the content of the yang-library data tree.
+Otherwise, an empty content with only the internal libyang modules is used. This does
+not limit user to load another modules explicitly specified as command line parameters.
+.
+.SH FORMATS
+There are two types of formats to use.
+.TP
+.I Schemas
+In case of schemas, the content can be converted into the '\fByang\fP', '\fByin\fP'
+and '\fBtree\fP' formats. As input, only YANG and YIN files are
+accepted. Note, that the corresponding file extension is required.
+.TP
+.I Data\ \ \
+In case of YANG modeled data, the content can be converted between '\fBxml\fP'
+and '\fBjson\fP' formats. Remember that the corresponding file extension of the
+input file is required.
+.
+
+.SH EXAMPLES
+.IP \[bu] 2
+Open interactive environment:
+ yanglint
+.IP \[bu]
+Convert YANG model into YIN and print it to the stdout:
+ yanglint --format=yin ./ietf-system.yang
+.IP \[bu]
+Convert ietf-system configuration data from XML to JSON:
+ yanglint --format=json --type=config --output=data.json ./ietf-system.yang ./data.xml
+
+.SH SEE ALSO
+https://github.com/CESNET/libyang (libyang homepage and Git repository)
+.
+.SH AUTHORS
+Radek Krejci <rkrejci@cesnet.cz>, Michal Vasko <mvasko@cesnet.cz>
+.
+.SH COPYRIGHT
+Copyright \(co 2015-2017 CESNET, a.l.e.