put more descriptive names on anonymous sections when running uci show (can be reused...
[project/uci.git] / cli.c
1 /*
2 * cli - Command Line Interface for the Unified Configuration Interface
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #include <strings.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include "uci.h"
19
20 #define MAX_ARGS 4 /* max command line arguments for batch mode */
21
22 static const char *delimiter = " ";
23 static const char *appname;
24 static enum {
25 CLI_FLAG_MERGE = (1 << 0),
26 CLI_FLAG_QUIET = (1 << 1),
27 CLI_FLAG_NOCOMMIT = (1 << 2),
28 CLI_FLAG_BATCH = (1 << 3),
29 } flags;
30
31 static FILE *input;
32
33 static struct uci_context *ctx;
34 enum {
35 /* section cmds */
36 CMD_GET,
37 CMD_SET,
38 CMD_ADD_LIST,
39 CMD_DEL,
40 CMD_RENAME,
41 CMD_REVERT,
42 /* package cmds */
43 CMD_SHOW,
44 CMD_CHANGES,
45 CMD_EXPORT,
46 CMD_COMMIT,
47 /* other cmds */
48 CMD_ADD,
49 CMD_IMPORT,
50 CMD_HELP,
51 };
52
53 struct uci_type_list {
54 unsigned int idx;
55 const char *name;
56 struct uci_type_list *next;
57 };
58
59 static struct uci_type_list *type_list = NULL;
60 static char *typestr = NULL;
61 static const char *cur_section_ref = NULL;
62
63 static int uci_cmd(int argc, char **argv);
64
65 static void
66 uci_reset_typelist(void)
67 {
68 struct uci_type_list *type;
69 while (type_list != NULL) {
70 type = type_list;
71 type_list = type_list->next;
72 free(type);
73 }
74 if (typestr) {
75 free(typestr);
76 typestr = NULL;
77 }
78 cur_section_ref = NULL;
79 }
80
81 static char *
82 uci_lookup_section_ref(struct uci_section *s)
83 {
84 struct uci_type_list *ti = type_list;
85 int maxlen;
86
87 if (!s->anonymous)
88 return s->e.name;
89
90 /* look up in section type list */
91 while (ti) {
92 if (strcmp(ti->name, s->type) == 0)
93 break;
94 ti = ti->next;
95 }
96 if (!ti) {
97 ti = malloc(sizeof(struct uci_type_list));
98 memset(ti, 0, sizeof(struct uci_type_list));
99 ti->next = type_list;
100 type_list = ti;
101 ti->name = s->type;
102 }
103
104 maxlen = strlen(s->type) + 1 + 2 + 10;
105 if (!typestr) {
106 typestr = malloc(maxlen);
107 } else {
108 typestr = realloc(typestr, maxlen);
109 }
110 sprintf(typestr, "@%s[%d]", ti->name, ti->idx);
111 ti->idx++;
112 return typestr;
113 }
114
115 static void uci_usage(void)
116 {
117 fprintf(stderr,
118 "Usage: %s [<options>] <command> [<arguments>]\n\n"
119 "Commands:\n"
120 "\tbatch\n"
121 "\texport [<config>]\n"
122 "\timport [<config>]\n"
123 "\tchanges [<config>]\n"
124 "\tcommit [<config>]\n"
125 "\tadd <config> <section-type>\n"
126 "\tadd_list <config>.<section>.<option>=<string>\n"
127 "\tshow [<config>[.<section>[.<option>]]]\n"
128 "\tget <config>.<section>[.<option>]\n"
129 "\tset <config>.<section>[.<option>]=<value>\n"
130 "\tdelete <config>[.<section[.<option>]]\n"
131 "\trename <config>.<section>[.<option>]=<name>\n"
132 "\trevert <config>[.<section>[.<option>]]\n"
133 "\n"
134 "Options:\n"
135 "\t-c <path> set the search path for config files (default: /etc/config)\n"
136 "\t-d <str> set the delimiter for list values in uci show\n"
137 "\t-f <file> use <file> as input instead of stdin\n"
138 "\t-m when importing, merge data into an existing package\n"
139 "\t-n name unnamed sections on export (default)\n"
140 "\t-N don't name unnamed sections\n"
141 "\t-p <path> add a search path for config change files\n"
142 "\t-P <path> add a search path for config change files and use as default\n"
143 "\t-q quiet mode (don't print error messages)\n"
144 "\t-s force strict mode (stop on parser errors, default)\n"
145 "\t-S disable strict mode\n"
146 "\n",
147 appname
148 );
149 }
150
151 static void cli_perror(void)
152 {
153 if (flags & CLI_FLAG_QUIET)
154 return;
155
156 uci_perror(ctx, appname);
157 }
158
159 static void uci_show_value(struct uci_option *o)
160 {
161 struct uci_element *e;
162 bool sep = false;
163
164 switch(o->type) {
165 case UCI_TYPE_STRING:
166 printf("%s\n", o->v.string);
167 break;
168 case UCI_TYPE_LIST:
169 uci_foreach_element(&o->v.list, e) {
170 printf("%s%s", (sep ? delimiter : ""), e->name);
171 sep = true;
172 }
173 printf("\n");
174 break;
175 default:
176 printf("<unknown>\n");
177 break;
178 }
179 }
180
181 static void uci_show_option(struct uci_option *o)
182 {
183 printf("%s.%s.%s=",
184 o->section->package->e.name,
185 (cur_section_ref ? cur_section_ref : o->section->e.name),
186 o->e.name);
187 uci_show_value(o);
188 }
189
190 static void uci_show_section(struct uci_section *s)
191 {
192 struct uci_element *e;
193 const char *cname;
194 const char *sname;
195
196 cname = s->package->e.name;
197 sname = (cur_section_ref ? cur_section_ref : s->e.name);
198 printf("%s.%s=%s\n", cname, sname, s->type);
199 uci_foreach_element(&s->options, e) {
200 uci_show_option(uci_to_option(e));
201 }
202 }
203
204 static void uci_show_package(struct uci_package *p)
205 {
206 struct uci_element *e;
207
208 uci_reset_typelist();
209 uci_foreach_element( &p->sections, e) {
210 struct uci_section *s = uci_to_section(e);
211 cur_section_ref = uci_lookup_section_ref(s);
212 uci_show_section(s);
213 }
214 uci_reset_typelist();
215 }
216
217 static void uci_show_changes(struct uci_package *p)
218 {
219 struct uci_element *e;
220
221 uci_foreach_element(&p->saved_history, e) {
222 struct uci_history *h = uci_to_history(e);
223 char *prefix = "";
224 char *op = "=";
225
226 switch(h->cmd) {
227 case UCI_CMD_REMOVE:
228 prefix = "-";
229 break;
230 case UCI_CMD_LIST_ADD:
231 op = "+=";
232 break;
233 default:
234 break;
235 }
236 printf("%s%s.%s", prefix, p->e.name, h->section);
237 if (e->name)
238 printf(".%s", e->name);
239 if (h->cmd != UCI_CMD_REMOVE)
240 printf("%s%s", op, h->value);
241 printf("\n");
242 }
243 }
244
245 static int package_cmd(int cmd, char *tuple)
246 {
247 struct uci_element *e = NULL;
248 struct uci_ptr ptr;
249
250 if (uci_lookup_ptr(ctx, &ptr, tuple, true) != UCI_OK) {
251 cli_perror();
252 return 1;
253 }
254
255 e = ptr.last;
256 switch(cmd) {
257 case CMD_CHANGES:
258 uci_show_changes(ptr.p);
259 break;
260 case CMD_COMMIT:
261 if (flags & CLI_FLAG_NOCOMMIT)
262 return 0;
263 if (uci_commit(ctx, &ptr.p, false) != UCI_OK)
264 cli_perror();
265 break;
266 case CMD_EXPORT:
267 uci_export(ctx, stdout, ptr.p, true);
268 break;
269 case CMD_SHOW:
270 if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
271 ctx->err = UCI_ERR_NOTFOUND;
272 cli_perror();
273 return 1;
274 }
275 switch(e->type) {
276 case UCI_TYPE_PACKAGE:
277 uci_show_package(ptr.p);
278 break;
279 case UCI_TYPE_SECTION:
280 uci_show_section(ptr.s);
281 break;
282 case UCI_TYPE_OPTION:
283 uci_show_option(ptr.o);
284 break;
285 default:
286 /* should not happen */
287 return 1;
288 }
289 break;
290 }
291
292 uci_unload(ctx, ptr.p);
293 return 0;
294 }
295
296 static int uci_do_import(int argc, char **argv)
297 {
298 struct uci_package *package = NULL;
299 char *name = NULL;
300 int ret = UCI_OK;
301 bool merge = false;
302
303 if (argc > 2)
304 return 255;
305
306 if (argc == 2)
307 name = argv[1];
308 else if (flags & CLI_FLAG_MERGE)
309 /* need a package to merge */
310 return 255;
311
312 if (flags & CLI_FLAG_MERGE) {
313 if (uci_load(ctx, name, &package) != UCI_OK)
314 package = NULL;
315 else
316 merge = true;
317 }
318 ret = uci_import(ctx, input, name, &package, (name != NULL));
319 if (ret == UCI_OK) {
320 if (merge) {
321 ret = uci_save(ctx, package);
322 } else {
323 struct uci_element *e;
324 /* loop through all config sections and overwrite existing data */
325 uci_foreach_element(&ctx->root, e) {
326 struct uci_package *p = uci_to_package(e);
327 ret = uci_commit(ctx, &p, true);
328 }
329 }
330 }
331
332 if (ret != UCI_OK) {
333 cli_perror();
334 return 1;
335 }
336
337 return 0;
338 }
339
340 static int uci_do_package_cmd(int cmd, int argc, char **argv)
341 {
342 char **configs = NULL;
343 char **p;
344
345 if (argc > 2)
346 return 255;
347
348 if (argc == 2)
349 return package_cmd(cmd, argv[1]);
350
351 if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs) {
352 cli_perror();
353 return 1;
354 }
355
356 for (p = configs; *p; p++) {
357 package_cmd(cmd, *p);
358 }
359
360 return 0;
361 }
362
363 static int uci_do_add(int argc, char **argv)
364 {
365 struct uci_package *p = NULL;
366 struct uci_section *s = NULL;
367 int ret;
368
369 if (argc != 3)
370 return 255;
371
372 ret = uci_load(ctx, argv[1], &p);
373 if (ret != UCI_OK)
374 goto done;
375
376 ret = uci_add_section(ctx, p, argv[2], &s);
377 if (ret != UCI_OK)
378 goto done;
379
380 ret = uci_save(ctx, p);
381
382 done:
383 if (ret != UCI_OK)
384 cli_perror();
385 else if (s)
386 fprintf(stdout, "%s\n", s->e.name);
387
388 return ret;
389 }
390
391 static int uci_do_section_cmd(int cmd, int argc, char **argv)
392 {
393 struct uci_element *e;
394 struct uci_ptr ptr;
395 int ret = UCI_OK;
396
397 if (argc != 2)
398 return 255;
399
400 if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
401 cli_perror();
402 return 1;
403 }
404
405 if (ptr.value && (cmd != CMD_SET) && (cmd != CMD_ADD_LIST) && (cmd != CMD_RENAME))
406 return 1;
407
408 e = ptr.last;
409 switch(cmd) {
410 case CMD_GET:
411 if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
412 ctx->err = UCI_ERR_NOTFOUND;
413 cli_perror();
414 return 1;
415 }
416 switch(e->type) {
417 case UCI_TYPE_SECTION:
418 printf("%s\n", ptr.s->type);
419 break;
420 case UCI_TYPE_OPTION:
421 uci_show_value(ptr.o);
422 break;
423 default:
424 break;
425 }
426 /* throw the value to stdout */
427 break;
428 case CMD_RENAME:
429 ret = uci_rename(ctx, &ptr);
430 break;
431 case CMD_REVERT:
432 ret = uci_revert(ctx, &ptr);
433 break;
434 case CMD_SET:
435 ret = uci_set(ctx, &ptr);
436 break;
437 case CMD_ADD_LIST:
438 ret = uci_add_list(ctx, &ptr);
439 break;
440 case CMD_DEL:
441 ret = uci_delete(ctx, &ptr);
442 break;
443 }
444
445 /* no save necessary for get */
446 if ((cmd == CMD_GET) || (cmd == CMD_REVERT))
447 return 0;
448
449 /* save changes, but don't commit them yet */
450 if (ret == UCI_OK)
451 ret = uci_save(ctx, ptr.p);
452
453 if (ret != UCI_OK) {
454 cli_perror();
455 return 1;
456 }
457
458 return 0;
459 }
460
461 static int uci_batch_cmd(void)
462 {
463 char *argv[MAX_ARGS];
464 char *str = NULL;
465 int ret = 0;
466 int i, j;
467
468 for(i = 0; i <= MAX_ARGS; i++) {
469 if (i == MAX_ARGS) {
470 fprintf(stderr, "Too many arguments\n");
471 return 1;
472 }
473 argv[i] = NULL;
474 if ((ret = uci_parse_argument(ctx, input, &str, &argv[i])) != UCI_OK) {
475 cli_perror();
476 i = 0;
477 break;
478 }
479 if (!argv[i][0])
480 break;
481 argv[i] = strdup(argv[i]);
482 if (!argv[i]) {
483 perror("uci");
484 return 1;
485 }
486 }
487 argv[i] = NULL;
488
489 if (i > 0) {
490 if (!strcasecmp(argv[0], "exit"))
491 return 254;
492 ret = uci_cmd(i, argv);
493 } else
494 return 0;
495
496 for (j = 0; j < i; j++) {
497 if (argv[j])
498 free(argv[j]);
499 }
500
501 return ret;
502 }
503
504 static int uci_batch(void)
505 {
506 int ret = 0;
507
508 flags |= CLI_FLAG_BATCH;
509 while (!feof(input)) {
510 struct uci_element *e, *tmp;
511
512 ret = uci_batch_cmd();
513 if (ret == 254)
514 return 0;
515 else if (ret == 255)
516 fprintf(stderr, "Unknown command\n");
517
518 /* clean up */
519 uci_foreach_element_safe(&ctx->root, tmp, e) {
520 uci_unload(ctx, uci_to_package(e));
521 }
522 }
523 flags &= ~CLI_FLAG_BATCH;
524
525 return 0;
526 }
527
528 static int uci_cmd(int argc, char **argv)
529 {
530 int cmd = 0;
531
532 if (!strcasecmp(argv[0], "batch") && !(flags & CLI_FLAG_BATCH))
533 return uci_batch();
534 else if (!strcasecmp(argv[0], "show"))
535 cmd = CMD_SHOW;
536 else if (!strcasecmp(argv[0], "changes"))
537 cmd = CMD_CHANGES;
538 else if (!strcasecmp(argv[0], "export"))
539 cmd = CMD_EXPORT;
540 else if (!strcasecmp(argv[0], "commit"))
541 cmd = CMD_COMMIT;
542 else if (!strcasecmp(argv[0], "get"))
543 cmd = CMD_GET;
544 else if (!strcasecmp(argv[0], "set"))
545 cmd = CMD_SET;
546 else if (!strcasecmp(argv[0], "ren") ||
547 !strcasecmp(argv[0], "rename"))
548 cmd = CMD_RENAME;
549 else if (!strcasecmp(argv[0], "revert"))
550 cmd = CMD_REVERT;
551 else if (!strcasecmp(argv[0], "del") ||
552 !strcasecmp(argv[0], "delete"))
553 cmd = CMD_DEL;
554 else if (!strcasecmp(argv[0], "import"))
555 cmd = CMD_IMPORT;
556 else if (!strcasecmp(argv[0], "help"))
557 cmd = CMD_HELP;
558 else if (!strcasecmp(argv[0], "add"))
559 cmd = CMD_ADD;
560 else if (!strcasecmp(argv[0], "add_list"))
561 cmd = CMD_ADD_LIST;
562 else
563 cmd = -1;
564
565 switch(cmd) {
566 case CMD_ADD_LIST:
567 case CMD_GET:
568 case CMD_SET:
569 case CMD_DEL:
570 case CMD_RENAME:
571 case CMD_REVERT:
572 return uci_do_section_cmd(cmd, argc, argv);
573 case CMD_SHOW:
574 case CMD_EXPORT:
575 case CMD_COMMIT:
576 case CMD_CHANGES:
577 return uci_do_package_cmd(cmd, argc, argv);
578 case CMD_IMPORT:
579 return uci_do_import(argc, argv);
580 case CMD_ADD:
581 return uci_do_add(argc, argv);
582 case CMD_HELP:
583 uci_usage();
584 return 0;
585 default:
586 return 255;
587 }
588 }
589
590 int main(int argc, char **argv)
591 {
592 int ret;
593 int c;
594
595 appname = argv[0];
596 input = stdin;
597 ctx = uci_alloc_context();
598 if (!ctx) {
599 fprintf(stderr, "Out of memory\n");
600 return 1;
601 }
602
603 while((c = getopt(argc, argv, "c:d:f:mnNp:P:sSq")) != -1) {
604 switch(c) {
605 case 'c':
606 uci_set_confdir(ctx, optarg);
607 break;
608 case 'd':
609 delimiter = optarg;
610 break;
611 case 'f':
612 input = fopen(optarg, "r");
613 if (!input) {
614 perror("uci");
615 return 1;
616 }
617 break;
618 case 'm':
619 flags |= CLI_FLAG_MERGE;
620 break;
621 case 's':
622 ctx->flags |= UCI_FLAG_STRICT;
623 break;
624 case 'S':
625 ctx->flags &= ~UCI_FLAG_STRICT;
626 ctx->flags |= UCI_FLAG_PERROR;
627 break;
628 case 'n':
629 ctx->flags |= UCI_FLAG_EXPORT_NAME;
630 break;
631 case 'N':
632 ctx->flags &= ~UCI_FLAG_EXPORT_NAME;
633 break;
634 case 'p':
635 uci_add_history_path(ctx, optarg);
636 break;
637 case 'P':
638 uci_add_history_path(ctx, ctx->savedir);
639 uci_set_savedir(ctx, optarg);
640 flags |= CLI_FLAG_NOCOMMIT;
641 break;
642 case 'q':
643 flags |= CLI_FLAG_QUIET;
644 break;
645 default:
646 uci_usage();
647 return 0;
648 }
649 }
650 if (optind > 1)
651 argv[optind - 1] = argv[0];
652 argv += optind - 1;
653 argc -= optind - 1;
654
655 if (argc < 2) {
656 uci_usage();
657 return 0;
658 }
659 ret = uci_cmd(argc - 1, argv + 1);
660 if (input != stdin)
661 fclose(input);
662 if (ret == 255) {
663 uci_usage();
664 return 0;
665 }
666
667 uci_free_context(ctx);
668
669 return ret;
670 }