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 }