blob: 5e2d8a63cf16af36cd9a4d4de0300b4a8b551a73 [file] [log] [blame]
Michal Vaskoe0cb2522015-07-01 10:24:53 +02001/**
2 * @file commands.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang's yanglint tool commands
Michal Vaskof3e59f12015-06-18 11:53:56 +02005 *
Michal Vaskoe0cb2522015-07-01 10:24:53 +02006 * Copyright (c) 2015 CESNET, z.s.p.o.
Michal Vaskof3e59f12015-06-18 11:53:56 +02007 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
Michal Vaskof3e59f12015-06-18 11:53:56 +020020 */
Michal Vaskoe0cb2522015-07-01 10:24:53 +020021
Michal Vaskof3e59f12015-06-18 11:53:56 +020022#define _GNU_SOURCE
23#include <string.h>
24#include <stdio.h>
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/mman.h>
29#include <fcntl.h>
Michal Vaskoea31f192015-08-03 15:21:56 +020030#include <assert.h>
Michal Vaskof3e59f12015-06-18 11:53:56 +020031#include <unistd.h>
32#include <getopt.h>
33
Michal Vasko203b4e72015-06-30 15:25:15 +020034#include "commands.h"
Michal Vaskof3e59f12015-06-18 11:53:56 +020035#include "../../src/libyang.h"
36#include "../../src/tree.h"
Michal Vasko520d4732015-07-13 15:53:33 +020037#include "../../src/parser.h"
Michal Vaskof3e59f12015-06-18 11:53:56 +020038
Michal Vasko203b4e72015-06-30 15:25:15 +020039COMMAND commands[];
Michal Vaskof3e59f12015-06-18 11:53:56 +020040extern int done;
41extern struct ly_ctx *ctx;
42extern char *search_path;
43
44void
Michal Vaskof3e59f12015-06-18 11:53:56 +020045cmd_add_help(void)
46{
Michal Vasko370d9102015-08-21 13:06:11 +020047 printf("add <path-to-model> [<other-models> ...]\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020048}
49
50void
51cmd_print_help(void)
52{
Michal Vaskoadfcfa12015-08-12 14:33:44 +020053 printf("print [-f (yang | tree | info)] [-t <info-target-node>] [-o <output-file>] <model-name>(@<revision>)\n\n");
Michal Vasko7df7f142015-07-15 12:10:53 +020054 printf("\tinfo-target-node: <absolute-schema-node> | typedef/<typedef-name> |\n");
Michal Vasko035f5232015-07-15 12:26:52 +020055 printf("\t | identity/<identity-name> | feature/<feature-name> |\n");
Michal Vaskod04dbea2015-08-06 15:10:19 +020056 printf("\t | grouping/<grouping-name>(<absolute-schema-nodeid>) |\n");
Michal Vasko035f5232015-07-15 12:26:52 +020057 printf("\t | type/<absolute-schema-node-leaf-or-leaflist>\n");
Michal Vaskod04dbea2015-08-06 15:10:19 +020058 printf("\n");
59 printf("\tabsolute-schema-nodeid: ( /(<import-prefix>:)<node-identifier> )+\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +020060}
61
Radek Krejcib9120952015-08-12 10:03:51 +020062static void
63cmd_parse_help(const char *name)
64{
65 printf("%s [-f (xml | json)] [-o <output-file>] <%s-file-name>\n", name, name);
66}
67
Michal Vaskof3e59f12015-06-18 11:53:56 +020068void
Michal Vasko520d4732015-07-13 15:53:33 +020069cmd_data_help(void)
70{
Radek Krejcib9120952015-08-12 10:03:51 +020071 cmd_parse_help("data");
72}
73
74void
75cmd_config_help(void)
76{
77 cmd_parse_help("config");
78}
79
80void
81cmd_filter_help(void)
82{
83 cmd_parse_help("filter");
Michal Vasko520d4732015-07-13 15:53:33 +020084}
85
86void
Michal Vaskof3e59f12015-06-18 11:53:56 +020087cmd_list_help(void)
88{
89 printf("list\n");
90}
91
92void
Michal Vasko50cfb782015-07-07 11:37:34 +020093cmd_feature_help(void)
94{
Michal Vasko4b484272015-08-12 14:41:25 +020095 printf("feature -(-p)rint | (-(-e)nable | -(-d)isable (* | <feature-name>)) <model-name>(@<revision>)\n");
Michal Vasko50cfb782015-07-07 11:37:34 +020096}
97
98void
Michal Vaskof3e59f12015-06-18 11:53:56 +020099cmd_searchpath_help(void)
100{
Michal Vasko6572fb42015-07-07 09:55:05 +0200101 printf("searchpath <model-dir-path>\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +0200102}
103
104void
105cmd_verb_help(void)
106{
Michal Vaskob93d0142015-08-11 16:08:25 +0200107 printf("verb (error/0 | warning/1 | verbose/2 | debug/3)\n");
Michal Vaskof3e59f12015-06-18 11:53:56 +0200108}
109
110int
111cmd_add(const char *arg)
112{
Michal Vasko370d9102015-08-21 13:06:11 +0200113 int fd, path_len;
114 char *addr, *ptr, *path;
115 const char *arg_ptr;
Radek Krejcib8048692015-08-05 13:36:34 +0200116 struct lys_module *model;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200117 struct stat sb;
Radek Krejcia9167ef2015-08-03 11:01:11 +0200118 LYS_INFORMAT format;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200119
Michal Vasko203b4e72015-06-30 15:25:15 +0200120 if (strlen(arg) < 5) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200121 cmd_add_help();
122 return 1;
123 }
124
Michal Vasko370d9102015-08-21 13:06:11 +0200125 arg_ptr = arg + strlen("add ");
126 while (arg_ptr[0] == ' ') {
127 ++arg_ptr;
128 }
129 if (strchr(arg_ptr, ' ')) {
130 path_len = strchr(arg_ptr, ' ') - arg_ptr;
131 } else {
132 path_len = strlen(arg_ptr);
133 }
Michal Vasko203b4e72015-06-30 15:25:15 +0200134
Michal Vasko370d9102015-08-21 13:06:11 +0200135 path = strndup(arg_ptr, path_len);
136
137 while (path) {
138 if ((ptr = strrchr(path, '.')) != NULL) {
139 ++ptr;
140 if (!strcmp(ptr, "yin")) {
141 format = LYS_IN_YIN;
142 } else if (!strcmp(ptr, "yang")) {
143 format = LYS_IN_YANG;
144 } else {
145 fprintf(stderr, "Input file in an unknown format \"%s\".\n", ptr);
146 free(path);
147 return 1;
148 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200149 } else {
Michal Vasko370d9102015-08-21 13:06:11 +0200150 fprintf(stdout, "Input file \"%.*s\" without extension, assuming YIN format.\n", path_len, arg_ptr);
151 format = LYS_IN_YIN;
152 }
153
154 fd = open(path, O_RDONLY);
155 free(path);
156 if (fd == -1) {
157 fprintf(stderr, "Opening input file \"%.*s\" failed (%s).\n", path_len, arg_ptr, strerror(errno));
Michal Vaskof3e59f12015-06-18 11:53:56 +0200158 return 1;
159 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200160
Michal Vasko370d9102015-08-21 13:06:11 +0200161 if (fstat(fd, &sb) == -1) {
162 fprintf(stderr, "Unable to get input file \"%.*s\" information (%s).\n", path_len, arg_ptr, strerror(errno));
163 close(fd);
164 return 1;
165 }
Radek Krejci4041a2d2015-07-02 09:16:42 +0200166
Michal Vasko370d9102015-08-21 13:06:11 +0200167 if (!S_ISREG(sb.st_mode)) {
168 fprintf(stderr, "Input file \"%.*s\" not a file.\n", path_len, arg_ptr);
169 close(fd);
170 return 1;
171 }
172
173 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
174
175 model = lys_parse(ctx, addr, format);
176 munmap(addr, sb.st_size);
Radek Krejci4041a2d2015-07-02 09:16:42 +0200177 close(fd);
Radek Krejci4041a2d2015-07-02 09:16:42 +0200178
Michal Vasko370d9102015-08-21 13:06:11 +0200179 if (!model) {
180 /* libyang printed the error messages */
181 return 1;
182 }
Radek Krejci4041a2d2015-07-02 09:16:42 +0200183
Michal Vasko370d9102015-08-21 13:06:11 +0200184 /* next model */
185 arg_ptr += path_len;
186 while (arg_ptr[0] == ' ') {
187 ++arg_ptr;
188 }
189 if (strchr(arg_ptr, ' ')) {
190 path_len = strchr(arg_ptr, ' ') - arg_ptr;
191 } else {
192 path_len = strlen(arg_ptr);
193 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200194
Michal Vasko370d9102015-08-21 13:06:11 +0200195 if (path_len) {
196 path = strndup(arg_ptr, path_len);
197 } else {
198 path = NULL;
199 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200200 }
201
Michal Vaskof3e59f12015-06-18 11:53:56 +0200202 return 0;
203}
204
205int
206cmd_print(const char *arg)
207{
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200208 int c, i, argc, option_index, ret = 1;
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200209 char **argv = NULL, *ptr, *target_node = NULL, *model_name, *revision;
210 const char **names, *out_path = NULL;
Radek Krejcib8048692015-08-05 13:36:34 +0200211 struct lys_module *model, *parent_model;
Radek Krejcia9167ef2015-08-03 11:01:11 +0200212 LYS_OUTFORMAT format = LYS_OUT_TREE;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200213 FILE *output = stdout;
214 static struct option long_options[] = {
215 {"help", no_argument, 0, 'h'},
216 {"format", required_argument, 0, 'f'},
217 {"output", required_argument, 0, 'o'},
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200218 {"target-node", required_argument, 0, 't'},
Michal Vaskof3e59f12015-06-18 11:53:56 +0200219 {NULL, 0, 0, 0}
220 };
221
222 argc = 1;
223 argv = malloc(2*sizeof *argv);
224 *argv = strdup(arg);
225 ptr = strtok(*argv, " ");
226 while ((ptr = strtok(NULL, " "))) {
227 argv = realloc(argv, (argc+2)*sizeof *argv);
228 argv[argc++] = ptr;
229 }
230 argv[argc] = NULL;
231
Michal Vasko50cfb782015-07-07 11:37:34 +0200232 optind = 0;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200233 while (1) {
Michal Vasko1074ce92015-07-03 16:16:31 +0200234 option_index = 0;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200235 c = getopt_long(argc, argv, "hf:o:t:", long_options, &option_index);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200236 if (c == -1) {
237 break;
238 }
239
240 switch (c) {
241 case 'h':
242 cmd_print_help();
243 ret = 0;
244 goto cleanup;
245 case 'f':
246 if (!strcmp(optarg, "yang")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200247 format = LYS_OUT_YANG;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200248 } else if (!strcmp(optarg, "tree")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200249 format = LYS_OUT_TREE;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200250 } else if (!strcmp(optarg, "info")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200251 format = LYS_OUT_INFO;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200252 } else {
253 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
254 goto cleanup;
255 }
256 break;
257 case 'o':
258 if (out_path) {
259 fprintf(stderr, "Output specified twice.\n");
260 goto cleanup;
261 }
262 out_path = optarg;
263 break;
Michal Vaskodd3b8bc2015-07-07 11:42:28 +0200264 case 't':
265 target_node = optarg;
266 break;
Michal Vaskof3e59f12015-06-18 11:53:56 +0200267 case '?':
268 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
269 goto cleanup;
270 }
271 }
272
273 /* file name */
274 if (optind == argc) {
275 fprintf(stderr, "Missing the model name.\n");
276 goto cleanup;
277 }
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200278
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200279 /* model, revision */
280 model_name = argv[optind];
281 revision = NULL;
282 if (strchr(model_name, '@')) {
283 revision = strchr(model_name, '@');
284 revision[0] = '\0';
285 ++revision;
286 }
287
288 model = ly_ctx_get_module(ctx, model_name, revision);
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200289 if (model == NULL) {
290 names = ly_ctx_get_module_names(ctx);
291 for (i = 0; names[i]; i++) {
292 if (!model) {
Radek Krejci63a91a92015-07-29 13:31:04 +0200293 parent_model = ly_ctx_get_module(ctx, names[i], NULL);
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200294 model = (struct lys_module *)ly_ctx_get_submodule(parent_model, model_name, revision);
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200295 }
Michal Vaskocf0a41c2015-07-07 11:43:10 +0200296 }
297 free(names);
298 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200299
300 if (model == NULL) {
Michal Vaskoadfcfa12015-08-12 14:33:44 +0200301 if (revision) {
302 fprintf(stderr, "No model \"%s\" in revision %s found.\n", model_name, revision);
303 } else {
304 fprintf(stderr, "No model \"%s\" found.\n", model_name);
305 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200306 goto cleanup;
307 }
308
309 if (out_path) {
310 output = fopen(out_path, "w");
311 if (!output) {
312 fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
313 goto cleanup;
314 }
315 }
316
Radek Krejci912da452015-07-29 14:10:06 +0200317 ret = lys_print(output, model, format, target_node);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200318
319cleanup:
320 free(*argv);
321 free(argv);
322
Radek Krejci94f05832015-06-19 09:58:53 +0200323 if (output && (output != stdout)) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200324 fclose(output);
325 }
326
327 return ret;
328}
329
Radek Krejcib9120952015-08-12 10:03:51 +0200330static int
331cmd_parse(const char *arg, int options)
Michal Vasko520d4732015-07-13 15:53:33 +0200332{
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200333 int c, argc, option_index, ret = 1, fd = -1;
334 struct stat sb;
335 char **argv = NULL, *ptr, *addr;
Michal Vasko520d4732015-07-13 15:53:33 +0200336 const char *out_path = NULL;
Radek Krejci0e1d1a62015-07-31 11:17:01 +0200337 struct lyd_node *data = NULL, *next, *iter;
Radek Krejcia9167ef2015-08-03 11:01:11 +0200338 LYD_FORMAT format = LYD_UNKNOWN;
Michal Vasko520d4732015-07-13 15:53:33 +0200339 FILE *output = stdout;
340 static struct option long_options[] = {
341 {"help", no_argument, 0, 'h'},
342 {"format", required_argument, 0, 'f'},
343 {"output", required_argument, 0, 'o'},
Radek Krejcib9120952015-08-12 10:03:51 +0200344 {"strict", no_argument, 0, 's'},
Michal Vasko520d4732015-07-13 15:53:33 +0200345 {NULL, 0, 0, 0}
346 };
347
348 argc = 1;
349 argv = malloc(2*sizeof *argv);
350 *argv = strdup(arg);
351 ptr = strtok(*argv, " ");
352 while ((ptr = strtok(NULL, " "))) {
353 argv = realloc(argv, (argc+2)*sizeof *argv);
354 argv[argc++] = ptr;
355 }
356 argv[argc] = NULL;
357
358 optind = 0;
359 while (1) {
360 option_index = 0;
Radek Krejcib9120952015-08-12 10:03:51 +0200361 c = getopt_long(argc, argv, "hf:o:xyz", long_options, &option_index);
Michal Vasko520d4732015-07-13 15:53:33 +0200362 if (c == -1) {
363 break;
364 }
365
366 switch (c) {
367 case 'h':
368 cmd_data_help();
369 ret = 0;
370 goto cleanup;
371 case 'f':
372 if (!strcmp(optarg, "xml")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200373 format = LYD_XML;
Michal Vasko520d4732015-07-13 15:53:33 +0200374 } else if (!strcmp(optarg, "json")) {
Radek Krejcia9167ef2015-08-03 11:01:11 +0200375 format = LYD_JSON;
Michal Vasko520d4732015-07-13 15:53:33 +0200376 } else {
377 fprintf(stderr, "Unknown output format \"%s\".\n", optarg);
378 goto cleanup;
379 }
380 break;
381 case 'o':
382 if (out_path) {
383 fprintf(stderr, "Output specified twice.\n");
384 goto cleanup;
385 }
386 out_path = optarg;
387 break;
Radek Krejcib9120952015-08-12 10:03:51 +0200388 case 's':
389 options |= LYD_OPT_STRICT;
390 break;
Michal Vasko520d4732015-07-13 15:53:33 +0200391 case '?':
392 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
393 goto cleanup;
394 }
395 }
396
397 /* file name */
398 if (optind == argc) {
399 fprintf(stderr, "Missing the data file name.\n");
400 goto cleanup;
401 }
402
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200403 fd = open(argv[optind], O_RDONLY);
404 if (fd == -1) {
Michal Vasko0c16d662015-07-13 15:54:37 +0200405 fprintf(stderr, "The input file could not be opened (%s).\n", strerror(errno));
Michal Vasko520d4732015-07-13 15:53:33 +0200406 goto cleanup;
407 }
408
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200409 if (fstat(fd, &sb) == -1) {
410 fprintf(stderr, "Unable to get input file information (%s).\n", strerror(errno));
411 goto cleanup;
412 }
Michal Vasko520d4732015-07-13 15:53:33 +0200413
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200414 if (!S_ISREG(sb.st_mode)) {
415 fprintf(stderr, "Input file not a file.\n");
416 goto cleanup;
417 }
418
419 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Radek Krejcib9120952015-08-12 10:03:51 +0200420 data = lyd_parse(ctx, addr, LYD_XML, options);
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200421 munmap(addr, sb.st_size);
422
Michal Vasko520d4732015-07-13 15:53:33 +0200423 if (data == NULL) {
424 fprintf(stderr, "Failed to parse data.\n");
425 goto cleanup;
426 }
427
428 if (out_path) {
429 output = fopen(out_path, "w");
430 if (!output) {
431 fprintf(stderr, "Could not open the output file (%s).\n", strerror(errno));
432 goto cleanup;
433 }
434
Radek Krejcia9167ef2015-08-03 11:01:11 +0200435 if (format == LYD_UNKNOWN) {
Michal Vasko520d4732015-07-13 15:53:33 +0200436 /* default */
Radek Krejcia9167ef2015-08-03 11:01:11 +0200437 format = LYD_XML;
Michal Vasko520d4732015-07-13 15:53:33 +0200438 }
439 }
440
Radek Krejcia9167ef2015-08-03 11:01:11 +0200441 if (format != LYD_UNKNOWN) {
Radek Krejci912da452015-07-29 14:10:06 +0200442 lyd_print(output, data, format);
Michal Vasko520d4732015-07-13 15:53:33 +0200443 }
444
445cleanup:
446 free(*argv);
447 free(argv);
448
449 if (output && (output != stdout)) {
450 fclose(output);
451 }
452
Michal Vaskoa3b45ca2015-07-14 16:01:20 +0200453 if (fd != -1) {
454 close(fd);
455 }
456
Radek Krejci0e1d1a62015-07-31 11:17:01 +0200457 LY_TREE_FOR_SAFE(data, next, iter) {
458 lyd_free(iter);
459 }
Michal Vasko520d4732015-07-13 15:53:33 +0200460
461 return ret;
462}
463
464int
Radek Krejcib9120952015-08-12 10:03:51 +0200465cmd_data(const char *arg)
466{
467 return cmd_parse(arg, 0);
468}
469
470int
471cmd_config(const char *arg)
472{
473 return cmd_parse(arg, LYD_OPT_EDIT);
474}
475
476int
477cmd_filter(const char *arg)
478{
479 return cmd_parse(arg, LYD_OPT_FILTER);
480}
481
482int
Michal Vaskof3e59f12015-06-18 11:53:56 +0200483cmd_list(const char *UNUSED(arg))
484{
Michal Vaskoea31f192015-08-03 15:21:56 +0200485 struct lyd_node *ylib, *module, *submodule, *node;
486 int has_modules = 0;
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200487
Radek Krejci7ab25152015-08-07 14:48:45 +0200488 ylib = ly_ctx_info(ctx);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200489
Michal Vaskoea31f192015-08-03 15:21:56 +0200490 LY_TREE_FOR(ylib->child, node) {
491 if (!strcmp(node->schema->name, "module-set-id")) {
492 printf("List of the loaded models (mod-set-id %s):\n", ((struct lyd_node_leaf *)node)->value_str);
493 break;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200494 }
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200495 }
Michal Vaskoea31f192015-08-03 15:21:56 +0200496 assert(node);
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200497
Michal Vaskoea31f192015-08-03 15:21:56 +0200498 LY_TREE_FOR(ylib->child, module) {
499 if (!strcmp(module->schema->name, "module")) {
500 has_modules = 1;
501
502 /* module print */
503 LY_TREE_FOR(module->child, node) {
504 if (!strcmp(node->schema->name, "name")) {
505 printf("\t%s", ((struct lyd_node_leaf *)node)->value_str);
506 } else if (!strcmp(node->schema->name, "revision")) {
507 if (((struct lyd_node_leaf *)node)->value_str[0] == '\0') {
508 printf("\n");
509 } else {
510 printf("@%s\n", ((struct lyd_node_leaf *)node)->value_str);
511 }
512 }
513 }
514
515 /* submodules print */
516 LY_TREE_FOR(module->child, submodule) {
517 if (!strcmp(submodule->schema->name, "submodules")) {
518 LY_TREE_FOR(submodule->child, submodule) {
519 if (!strcmp(submodule->schema->name, "submodule")) {
520 LY_TREE_FOR(submodule->child, node) {
521 if (!strcmp(node->schema->name, "name")) {
522 printf("\t\t%s", ((struct lyd_node_leaf *)node)->value_str);
523 } else if (!strcmp(node->schema->name, "revision")) {
524 if (((struct lyd_node_leaf *)node)->value_str[0] == '\0') {
525 printf("\n");
526 } else {
527 printf("@%s\n", ((struct lyd_node_leaf *)node)->value_str);
528 }
529 }
530 }
531 }
532 }
533 break;
534 }
535 }
536 }
537 }
538
539 if (!has_modules) {
Michal Vaskoe0cb2522015-07-01 10:24:53 +0200540 printf("\t(none)\n");
541 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200542
Michal Vaskoea31f192015-08-03 15:21:56 +0200543 lyd_free(ylib);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200544 return 0;
545}
546
547int
Michal Vasko50cfb782015-07-07 11:37:34 +0200548cmd_feature(const char *arg)
549{
550 int c, i, argc, option_index, ret = 1, task = -1;
Michal Vaskob011e6b2015-08-06 09:57:46 +0200551 unsigned int max_len;
Michal Vasko4b484272015-08-12 14:41:25 +0200552 char **argv = NULL, *ptr, *model_name, *revision;
Radek Krejci96a10da2015-07-30 11:00:14 +0200553 const char *feat_name = NULL, **names;
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200554 uint8_t *states;
Radek Krejcib8048692015-08-05 13:36:34 +0200555 struct lys_module *model, *parent_model;
Michal Vasko50cfb782015-07-07 11:37:34 +0200556 static struct option long_options[] = {
557 {"help", no_argument, 0, 'h'},
558 {"print", no_argument, 0, 'p'},
559 {"enable", required_argument, 0, 'e'},
560 {"disable", required_argument, 0, 'd'},
561 {NULL, 0, 0, 0}
562 };
563
564 argc = 1;
565 argv = malloc(2*sizeof *argv);
566 *argv = strdup(arg);
567 ptr = strtok(*argv, " ");
568 while ((ptr = strtok(NULL, " "))) {
569 argv = realloc(argv, (argc+2)*sizeof *argv);
570 argv[argc++] = ptr;
571 }
572 argv[argc] = NULL;
573
574 optind = 0;
575 while (1) {
576 option_index = 0;
577 c = getopt_long(argc, argv, "hpe:d:", long_options, &option_index);
578 if (c == -1) {
579 break;
580 }
581
582 switch (c) {
583 case 'h':
584 cmd_feature_help();
585 ret = 0;
586 goto cleanup;
587 case 'p':
588 if (task != -1) {
589 fprintf(stderr, "Only one of print, enable, or disable can be specified.\n");
590 goto cleanup;
591 }
592 task = 0;
593 break;
594 case 'e':
595 if (task != -1) {
596 fprintf(stderr, "Only one of print, enable, or disable can be specified.\n");
597 goto cleanup;
598 }
599 task = 1;
600 feat_name = optarg;
601 break;
602 case 'd':
603 if (task != -1) {
604 fprintf(stderr, "Only one of print, enable, or disable can be specified.\n");
605 goto cleanup;
606 }
607 task = 2;
608 feat_name = optarg;
609 break;
610 case '?':
611 fprintf(stderr, "Unknown option \"%d\".\n", (char)c);
612 goto cleanup;
613 }
614 }
615
616 /* model name */
617 if (optind == argc) {
618 fprintf(stderr, "Missing the model name.\n");
619 goto cleanup;
620 }
Michal Vasko4b484272015-08-12 14:41:25 +0200621
622 revision = NULL;
623 model_name = argv[optind];
624 if (strchr(model_name, '@')) {
625 revision = strchr(model_name, '@');
626 revision[0] = '\0';
627 ++revision;
628 }
629
630 model = ly_ctx_get_module(ctx, model_name, revision);
Michal Vasko50cfb782015-07-07 11:37:34 +0200631 if (model == NULL) {
632 names = ly_ctx_get_module_names(ctx);
633 for (i = 0; names[i]; i++) {
634 if (!model) {
Radek Krejci63a91a92015-07-29 13:31:04 +0200635 parent_model = ly_ctx_get_module(ctx, names[i], NULL);
Michal Vasko4b484272015-08-12 14:41:25 +0200636 model = (struct lys_module *)ly_ctx_get_submodule(parent_model, model_name, revision);
Michal Vasko50cfb782015-07-07 11:37:34 +0200637 }
Michal Vasko50cfb782015-07-07 11:37:34 +0200638 }
639 free(names);
640 }
641 if (model == NULL) {
Michal Vasko4b484272015-08-12 14:41:25 +0200642 if (revision) {
643 fprintf(stderr, "No model \"%s\" in revision %s found.\n", model_name, revision);
644 } else {
645 fprintf(stderr, "No model \"%s\" found.\n", model_name);
646 }
Michal Vasko50cfb782015-07-07 11:37:34 +0200647 goto cleanup;
648 }
649
650 if (task == -1) {
651 fprintf(stderr, "One of print, enable, or disable must be specified.\n");
652 goto cleanup;
653 }
654
655 if (task == 0) {
656 printf("%s features:\n", model->name);
657
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200658 names = lys_features_list(model, &states);
Michal Vaskob011e6b2015-08-06 09:57:46 +0200659
660 /* get the max len */
661 max_len = 0;
Michal Vasko50cfb782015-07-07 11:37:34 +0200662 for (i = 0; names[i]; ++i) {
Michal Vaskob011e6b2015-08-06 09:57:46 +0200663 if (strlen(names[i]) > max_len) {
664 max_len = strlen(names[i]);
665 }
666 }
667 for (i = 0; names[i]; ++i) {
668 printf("\t%-*s (%s)\n", max_len, names[i], states[i] ? "on" : "off");
Michal Vasko50cfb782015-07-07 11:37:34 +0200669 }
670 free(names);
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200671 free(states);
Michal Vasko50cfb782015-07-07 11:37:34 +0200672 if (!i) {
673 printf("\t(none)\n");
674 }
675 } else if (task == 1) {
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200676 if (lys_features_enable(model, feat_name)) {
Michal Vasko50cfb782015-07-07 11:37:34 +0200677 fprintf(stderr, "Feature \"%s\" not found.\n", feat_name);
678 ret = 1;
679 }
680 } else if (task == 2) {
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200681 if (lys_features_disable(model, feat_name)) {
Michal Vasko50cfb782015-07-07 11:37:34 +0200682 fprintf(stderr, "Feature \"%s\" not found.\n", feat_name);
683 ret = 1;
684 }
685 }
686
687cleanup:
688 free(*argv);
689 free(argv);
690
691 return ret;
692}
693
694int
Michal Vaskof3e59f12015-06-18 11:53:56 +0200695cmd_searchpath(const char *arg)
696{
697 const char *path;
698 struct stat st;
699
700 if (strchr(arg, ' ') == NULL) {
701 fprintf(stderr, "Missing the search path.\n");
702 return 1;
703 }
704 path = strchr(arg, ' ')+1;
705
706 if (!strcmp(path, "-h") || !strcmp(path, "--help")) {
707 cmd_searchpath_help();
708 return 0;
709 }
710
711 if (stat(path, &st) == -1) {
712 fprintf(stderr, "Failed to stat the search path (%s).\n", strerror(errno));
713 return 1;
714 }
715 if (!S_ISDIR(st.st_mode)) {
716 fprintf(stderr, "\"%s\" is not a directory.\n", path);
717 return 1;
718 }
719
720 free(search_path);
721 search_path = strdup(path);
722
Michal Vasko6572fb42015-07-07 09:55:05 +0200723 ly_ctx_set_searchdir(ctx, search_path);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200724
Michal Vasko6572fb42015-07-07 09:55:05 +0200725 return 0;
726}
Michal Vaskof3e59f12015-06-18 11:53:56 +0200727
Michal Vasko50cfb782015-07-07 11:37:34 +0200728int
729cmd_clear(const char *UNUSED(arg))
730{
731 ly_ctx_destroy(ctx);
732 ctx = ly_ctx_new(search_path);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200733 return 0;
734}
735
736int
737cmd_verb(const char *arg)
738{
739 const char *verb;
Radek Krejci7408bf12015-07-20 18:15:51 +0200740 if (strlen(arg) < 5) {
741 cmd_verb_help();
742 return 1;
743 }
Michal Vaskof3e59f12015-06-18 11:53:56 +0200744
745 verb = arg + 5;
Michal Vaskob93d0142015-08-11 16:08:25 +0200746 if (!strcmp(verb, "error") || !strcmp(verb, "0")) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200747 ly_verb(0);
Michal Vaskob93d0142015-08-11 16:08:25 +0200748 } else if (!strcmp(verb, "warning") || !strcmp(verb, "1")) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200749 ly_verb(1);
Michal Vaskob93d0142015-08-11 16:08:25 +0200750 } else if (!strcmp(verb, "verbose") || !strcmp(verb, "2")) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200751 ly_verb(2);
Michal Vaskob93d0142015-08-11 16:08:25 +0200752 } else if (!strcmp(verb, "debug") || !strcmp(verb, "3")) {
Michal Vaskof3e59f12015-06-18 11:53:56 +0200753 ly_verb(3);
754 } else {
Radek Krejci7408bf12015-07-20 18:15:51 +0200755 fprintf(stderr, "Unknown verbosity \"%s\"\n", verb);
Michal Vaskof3e59f12015-06-18 11:53:56 +0200756 return 1;
757 }
758
759 return 0;
760}
761
762int
763cmd_quit(const char *UNUSED(arg))
764{
765 done = 1;
766 return 0;
767}
768
769int
770cmd_help(const char *arg)
771{
772 int i;
773 char *args = strdupa(arg);
774 char *cmd = NULL;
775
776 strtok(args, " ");
777 if ((cmd = strtok(NULL, " ")) == NULL) {
778
779generic_help:
780 fprintf(stdout, "Available commands:\n");
781
782 for (i = 0; commands[i].name; i++) {
783 if (commands[i].helpstring != NULL) {
784 fprintf(stdout, " %-15s %s\n", commands[i].name, commands[i].helpstring);
785 }
786 }
787 } else {
788 /* print specific help for the selected command */
789
790 /* get the command of the specified name */
791 for (i = 0; commands[i].name; i++) {
792 if (strcmp(cmd, commands[i].name) == 0) {
793 break;
794 }
795 }
796
797 /* execute the command's help if any valid command specified */
798 if (commands[i].name) {
799 if (commands[i].help_func != NULL) {
800 commands[i].help_func();
801 } else {
802 printf("%s\n", commands[i].helpstring);
803 }
804 } else {
805 /* if unknown command specified, print the list of commands */
806 printf("Unknown command \'%s\'\n", cmd);
807 goto generic_help;
808 }
809 }
810
811 return 0;
812}
813
814COMMAND commands[] = {
815 {"help", cmd_help, NULL, "Display commands description"},
816 {"add", cmd_add, cmd_add_help, "Add a new model"},
817 {"print", cmd_print, cmd_print_help, "Print model"},
Radek Krejcib9120952015-08-12 10:03:51 +0200818 {"data", cmd_data, cmd_data_help, "Load, validate and optionally print complete datastore data"},
819 {"config", cmd_config, cmd_config_help, "Load, validate and optionally print edit-config's data"},
820 {"filter", cmd_filter, cmd_filter_help, "Load, validate and optionally print subtree filter data"},
Michal Vaskof3e59f12015-06-18 11:53:56 +0200821 {"list", cmd_list, cmd_list_help, "List all the loaded models"},
Michal Vasko50cfb782015-07-07 11:37:34 +0200822 {"feature", cmd_feature, cmd_feature_help, "Print/enable/disable all/specific features of models"},
Michal Vaskof3e59f12015-06-18 11:53:56 +0200823 {"searchpath", cmd_searchpath, cmd_searchpath_help, "Set the search path for models"},
Michal Vasko6572fb42015-07-07 09:55:05 +0200824 {"clear", cmd_clear, NULL, "Clear the context - remove all the loaded models"},
Michal Vaskof3e59f12015-06-18 11:53:56 +0200825 {"verb", cmd_verb, cmd_verb_help, "Change verbosity"},
826 {"quit", cmd_quit, NULL, "Quit the program"},
827 /* synonyms for previous commands */
828 {"?", cmd_help, NULL, "Display commands description"},
829 {"exit", cmd_quit, NULL, "Quit the program"},
830 {NULL, NULL, NULL, NULL}
831};