• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uci/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 <stdarg.h>
 18 #include <errno.h>
 19 #include <unistd.h>
 20 #include "uci.h"
 21 
 22 #define MAX_ARGS        4 /* max command line arguments for batch mode */
 23 
 24 static const char *delimiter = " ";
 25 static const char *appname;
 26 static enum {
 27         CLI_FLAG_MERGE =    (1 << 0),
 28         CLI_FLAG_QUIET =    (1 << 1),
 29         CLI_FLAG_NOCOMMIT = (1 << 2),
 30         CLI_FLAG_BATCH =    (1 << 3),
 31         CLI_FLAG_SHOW_EXT = (1 << 4),
 32 } flags;
 33 
 34 static FILE *input;
 35 
 36 static struct uci_context *ctx;
 37 enum {
 38         /* section cmds */
 39         CMD_GET,
 40         CMD_SET,
 41         CMD_ADD_LIST,
 42         CMD_DEL_LIST,
 43         CMD_DEL,
 44         CMD_RENAME,
 45         CMD_REVERT,
 46         CMD_REORDER,
 47         /* package cmds */
 48         CMD_SHOW,
 49         CMD_CHANGES,
 50         CMD_EXPORT,
 51         CMD_COMMIT,
 52         /* other cmds */
 53         CMD_ADD,
 54         CMD_IMPORT,
 55         CMD_HELP,
 56 };
 57 
 58 struct uci_type_list {
 59         unsigned int idx;
 60         const char *name;
 61         struct uci_type_list *next;
 62 };
 63 
 64 static struct uci_type_list *type_list = NULL;
 65 static char *typestr = NULL;
 66 static const char *cur_section_ref = NULL;
 67 
 68 static int uci_cmd(int argc, char **argv);
 69 
 70 static void
 71 uci_reset_typelist(void)
 72 {
 73         struct uci_type_list *type;
 74         while (type_list != NULL) {
 75                         type = type_list;
 76                         type_list = type_list->next;
 77                         free(type);
 78         }
 79         if (typestr) {
 80                 free(typestr);
 81                 typestr = NULL;
 82         }
 83         cur_section_ref = NULL;
 84 }
 85 
 86 static char *
 87 uci_lookup_section_ref(struct uci_section *s)
 88 {
 89         struct uci_type_list *ti = type_list;
 90         char *ret;
 91         int maxlen;
 92 
 93         if (!(flags & CLI_FLAG_SHOW_EXT))
 94                 return s->e.name;
 95 
 96         /* look up in section type list */
 97         while (ti) {
 98                 if (strcmp(ti->name, s->type) == 0)
 99                         break;
100                 ti = ti->next;
101         }
102         if (!ti) {
103                 ti = calloc(1, sizeof(struct uci_type_list));
104                 if (!ti)
105                         return NULL;
106                 ti->next = type_list;
107                 type_list = ti;
108                 ti->name = s->type;
109         }
110 
111         if (s->anonymous) {
112                 maxlen = strlen(s->type) + 1 + 2 + 10;
113                 if (!typestr) {
114                         typestr = malloc(maxlen);
115                         if (!typestr)
116                                 return NULL;
117                 } else {
118                         void *p = realloc(typestr, maxlen);
119                         if (!p) {
120                                 free(typestr);
121                                 return NULL;
122                         }
123 
124                         typestr = p;
125                 }
126 
127                 if (typestr)
128                         sprintf(typestr, "@%s[%d]", ti->name, ti->idx);
129 
130                 ret = typestr;
131         } else {
132                 ret = s->e.name;
133         }
134 
135         ti->idx++;
136 
137         return ret;
138 }
139 
140 static void uci_usage(void)
141 {
142         fprintf(stderr,
143                 "Usage: %s [<options>] <command> [<arguments>]\n\n"
144                 "Commands:\n"
145                 "\tbatch\n"
146                 "\texport     [<config>]\n"
147                 "\timport     [<config>]\n"
148                 "\tchanges    [<config>]\n"
149                 "\tcommit     [<config>]\n"
150                 "\tadd        <config> <section-type>\n"
151                 "\tadd_list   <config>.<section>.<option>=<string>\n"
152                 "\tdel_list   <config>.<section>.<option>=<string>\n"
153                 "\tshow       [<config>[.<section>[.<option>]]]\n"
154                 "\tget        <config>.<section>[.<option>]\n"
155                 "\tset        <config>.<section>[.<option>]=<value>\n"
156                 "\tdelete     <config>[.<section>[[.<option>][=<id>]]]\n"
157                 "\trename     <config>.<section>[.<option>]=<name>\n"
158                 "\trevert     <config>[.<section>[.<option>]]\n"
159                 "\treorder    <config>.<section>=<position>\n"
160                 "\n"
161                 "Options:\n"
162                 "\t-c <path>  set the search path for config files (default: "UCI_CONFDIR")\n"
163                 "\t-C <path>  set the search path for config override files (default: "UCI_CONF2DIR")\n"
164                 "\t-d <str>   set the delimiter for list values in uci show\n"
165                 "\t-f <file>  use <file> as input instead of stdin\n"
166                 "\t-m         when importing, merge data into an existing package\n"
167                 "\t-n         name unnamed sections on export (default)\n"
168                 "\t-N         don't name unnamed sections\n"
169                 "\t-p <path>  add a search path for config change files\n"
170                 "\t-P <path>  add a search path for config change files and use as default\n"
171                 "\t-t <path>  set save path for config change files\n"
172                 "\t-q         quiet mode (don't print error messages)\n"
173                 "\t-s         force strict mode (stop on parser errors, default)\n"
174                 "\t-S         disable strict mode\n"
175                 "\t-X         do not use extended syntax on 'show'\n"
176                 "\n",
177                 appname
178         );
179 }
180 
181 static void cli_perror(void)
182 {
183         if (flags & CLI_FLAG_QUIET)
184                 return;
185 
186         uci_perror(ctx, appname);
187 }
188 
189 __attribute__((format(printf, 1, 2)))
190 static void cli_error(const char *fmt, ...)
191 {
192         va_list ap;
193 
194         if (flags & CLI_FLAG_QUIET)
195                 return;
196 
197         va_start(ap, fmt);
198         vfprintf(stderr, fmt, ap);
199         va_end(ap);
200 }
201 
202 static void uci_print_value(FILE *f, const char *v)
203 {
204         fprintf(f, "'");
205         while (*v) {
206                 if (*v != '\'')
207                         fputc(*v, f);
208                 else
209                         fprintf(f, "'\\''");
210                 v++;
211         }
212         fprintf(f, "'");
213 }
214 
215 static void uci_show_value(struct uci_option *o, bool quote)
216 {
217         struct uci_element *e;
218         bool sep = false;
219         char *space;
220 
221         switch(o->type) {
222         case UCI_TYPE_STRING:
223                 if (quote)
224                         uci_print_value(stdout, o->v.string);
225                 else
226                         printf("%s", o->v.string);
227                 printf("\n");
228                 break;
229         case UCI_TYPE_LIST:
230                 uci_foreach_element(&o->v.list, e) {
231                         printf("%s", (sep ? delimiter : ""));
232                         space = strpbrk(e->name, " \t\r\n");
233                         if (!space && !quote)
234                                 printf("%s", e->name);
235                         else
236                                 uci_print_value(stdout, e->name);
237                         sep = true;
238                 }
239                 printf("\n");
240                 break;
241         default:
242                 printf("<unknown>\n");
243                 break;
244         }
245 }
246 
247 static void uci_show_option(struct uci_option *o, bool quote)
248 {
249         printf("%s.%s.%s=",
250                 o->section->package->e.name,
251                 (cur_section_ref ? cur_section_ref : o->section->e.name),
252                 o->e.name);
253         uci_show_value(o, quote);
254 }
255 
256 static void uci_show_section(struct uci_section *s)
257 {
258         struct uci_element *e;
259         const char *cname;
260         const char *sname;
261 
262         cname = s->package->e.name;
263         sname = (cur_section_ref ? cur_section_ref : s->e.name);
264         printf("%s.%s=%s\n", cname, sname, s->type);
265         uci_foreach_element(&s->options, e) {
266                 uci_show_option(uci_to_option(e), true);
267         }
268 }
269 
270 static void uci_show_package(struct uci_package *p)
271 {
272         struct uci_element *e;
273 
274         uci_reset_typelist();
275         uci_foreach_element( &p->sections, e) {
276                 struct uci_section *s = uci_to_section(e);
277                 cur_section_ref = uci_lookup_section_ref(s);
278                 uci_show_section(s);
279         }
280         uci_reset_typelist();
281 }
282 
283 static void uci_show_changes(struct uci_package *p)
284 {
285         struct uci_element *e;
286 
287         uci_foreach_element(&p->saved_delta, e) {
288                 struct uci_delta *h = uci_to_delta(e);
289                 char *prefix = "";
290                 char *op = "=";
291 
292                 switch(h->cmd) {
293                 case UCI_CMD_REMOVE:
294                         prefix = "-";
295                         break;
296                 case UCI_CMD_LIST_ADD:
297                         op = "+=";
298                         break;
299                 case UCI_CMD_LIST_DEL:
300                         op = "-=";
301                         break;
302                 default:
303                         break;
304                 }
305                 printf("%s%s.%s", prefix, p->e.name, h->section);
306                 if (e->name)
307                         printf(".%s", e->name);
308                 if (h->cmd != UCI_CMD_REMOVE) {
309                         printf("%s", op);
310                         uci_print_value(stdout, h->value);
311                 }
312                 printf("\n");
313         }
314 }
315 
316 static int package_cmd(int cmd, char *tuple)
317 {
318         struct uci_ptr ptr;
319         int ret = 1;
320 
321         if (uci_lookup_ptr(ctx, &ptr, tuple, true) != UCI_OK) {
322                 cli_perror();
323                 return 1;
324         }
325 
326         switch(cmd) {
327         case CMD_CHANGES:
328                 uci_show_changes(ptr.p);
329                 break;
330         case CMD_COMMIT:
331                 if (flags & CLI_FLAG_NOCOMMIT) {
332                         ret = 0;
333                         goto out;
334                 }
335                 if (uci_commit(ctx, &ptr.p, false) != UCI_OK) {
336                         cli_perror();
337                         goto out;
338                 }
339                 break;
340         case CMD_EXPORT:
341                 if (uci_export(ctx, stdout, ptr.p, true) != UCI_OK) {
342                         goto out;
343                 }
344                 break;
345         case CMD_SHOW:
346                 if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
347                         ctx->err = UCI_ERR_NOTFOUND;
348                         cli_perror();
349                         goto out;
350                 }
351                 if (ptr.o)
352                         uci_show_option(ptr.o, true);
353                 else if (ptr.s)
354                         uci_show_section(ptr.s);
355                 else if (ptr.p)
356                         uci_show_package(ptr.p);
357                 else
358                         goto out; /* should not happen */
359                 break;
360         }
361 
362         ret = 0;
363 
364 out:
365         if (ptr.p)
366                 uci_unload(ctx, ptr.p);
367         return ret;
368 }
369 
370 static int uci_do_import(int argc, char **argv)
371 {
372         struct uci_package *package = NULL;
373         char *name = NULL;
374         int ret = UCI_OK;
375         bool merge = false;
376 
377         if (argc > 2)
378                 return 255;
379 
380         if (argc == 2)
381                 name = argv[1];
382         else if (flags & CLI_FLAG_MERGE)
383                 /* need a package to merge */
384                 return 255;
385 
386         if (flags & CLI_FLAG_MERGE) {
387                 if (uci_load(ctx, name, &package) != UCI_OK)
388                         package = NULL;
389                 else
390                         merge = true;
391         }
392         ret = uci_import(ctx, input, name, &package, (name != NULL));
393         if (ret == UCI_OK) {
394                 if (merge) {
395                         ret = uci_save(ctx, package);
396                 } else {
397                         struct uci_element *e;
398                         /* loop through all config sections and overwrite existing data */
399                         uci_foreach_element(&ctx->root, e) {
400                                 struct uci_package *p = uci_to_package(e);
401                                 ret = uci_commit(ctx, &p, true);
402                         }
403                 }
404         }
405 
406         if (ret != UCI_OK) {
407                 cli_perror();
408                 return 1;
409         }
410 
411         return 0;
412 }
413 
414 static int uci_do_package_cmd(int cmd, int argc, char **argv)
415 {
416         char **configs = NULL;
417         char **p;
418         int ret = 1;
419 
420         if (argc > 2)
421                 return 255;
422 
423         if (argc == 2)
424                 return package_cmd(cmd, argv[1]);
425 
426         if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs) {
427                 cli_perror();
428                 goto out;
429         }
430 
431         for (p = configs; *p; p++) {
432                 package_cmd(cmd, *p);
433         }
434 
435         ret = 0;
436 out:
437         free(configs);
438         return ret;
439 }
440 
441 static int uci_do_add(int argc, char **argv)
442 {
443         struct uci_package *p = NULL;
444         struct uci_section *s = NULL;
445         int ret;
446 
447         if (argc != 3)
448                 return 255;
449 
450         ret = uci_load(ctx, argv[1], &p);
451         if (ret != UCI_OK)
452                 goto done;
453 
454         ret = uci_add_section(ctx, p, argv[2], &s);
455         if (ret != UCI_OK)
456                 goto done;
457 
458         ret = uci_save(ctx, p);
459 
460 done:
461         if (ret != UCI_OK)
462                 cli_perror();
463         else if (s)
464                 fprintf(stdout, "%s\n", s->e.name);
465 
466         return ret;
467 }
468 
469 static int uci_do_section_cmd(int cmd, int argc, char **argv)
470 {
471         struct uci_ptr ptr;
472         int ret = UCI_OK;
473         int dummy;
474 
475         if (argc != 2)
476                 return 255;
477 
478         if (uci_lookup_ptr(ctx, &ptr, argv[1], true) != UCI_OK) {
479                 cli_perror();
480                 return 1;
481         }
482 
483         if (ptr.value && (cmd != CMD_SET) && (cmd != CMD_DEL) &&
484             (cmd != CMD_ADD_LIST) && (cmd != CMD_DEL_LIST) &&
485             (cmd != CMD_RENAME) && (cmd != CMD_REORDER))
486                 return 1;
487 
488         switch(cmd) {
489         case CMD_GET:
490                 if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
491                         ctx->err = UCI_ERR_NOTFOUND;
492                         cli_perror();
493                         return 1;
494                 }
495                 if (ptr.o)
496                         uci_show_value(ptr.o, false);
497                 else if (ptr.s)
498                         printf("%s\n", ptr.s->type);
499                 break;
500         case CMD_RENAME:
501                 ret = uci_rename(ctx, &ptr);
502                 break;
503         case CMD_REVERT:
504                 ret = uci_revert(ctx, &ptr);
505                 break;
506         case CMD_SET:
507                 ret = uci_set(ctx, &ptr);
508                 break;
509         case CMD_ADD_LIST:
510                 ret = uci_add_list(ctx, &ptr);
511                 break;
512         case CMD_DEL_LIST:
513                 ret = uci_del_list(ctx, &ptr);
514                 break;
515         case CMD_REORDER:
516                 if (!ptr.s || !ptr.value) {
517                         ctx->err = UCI_ERR_NOTFOUND;
518                         cli_perror();
519                         return 1;
520                 }
521                 ret = uci_reorder_section(ctx, ptr.s, strtoul(ptr.value, NULL, 10));
522                 break;
523         case CMD_DEL:
524                 if (ptr.value && !sscanf(ptr.value, "%d", &dummy))
525                         return 1;
526                 ret = uci_delete(ctx, &ptr);
527                 break;
528         }
529 
530         /* no save necessary for get */
531         if ((cmd == CMD_GET) || (cmd == CMD_REVERT))
532                 return 0;
533 
534         /* save changes, but don't commit them yet */
535         if (ret == UCI_OK)
536                 ret = uci_save(ctx, ptr.p);
537 
538         if (ret != UCI_OK) {
539                 cli_perror();
540                 return 1;
541         }
542 
543         return 0;
544 }
545 
546 static int uci_batch_cmd(void)
547 {
548         char *argv[MAX_ARGS + 2];
549         char *str = NULL;
550         int ret = 0;
551         int i, j;
552 
553         for(i = 0; i <= MAX_ARGS; i++) {
554                 if (i == MAX_ARGS) {
555                         cli_error("Too many arguments\n");
556                         return 1;
557                 }
558                 argv[i] = NULL;
559                 if (uci_parse_argument(ctx, input, &str, &argv[i]) != UCI_OK) {
560                         cli_perror();
561                         i = 0;
562                         break;
563                 }
564                 if (!argv[i][0])
565                         break;
566                 argv[i] = strdup(argv[i]);
567                 if (!argv[i]) {
568                         cli_error("uci: %s", strerror(errno));
569                         return 1;
570                 }
571         }
572         argv[i] = NULL;
573 
574         if (i > 0) {
575                 if (!strcasecmp(argv[0], "exit"))
576                         return 254;
577                 ret = uci_cmd(i, argv);
578         } else
579                 return 0;
580 
581         for (j = 0; j < i; j++) {
582                 free(argv[j]);
583         }
584 
585         return ret;
586 }
587 
588 static int uci_batch(void)
589 {
590         int ret = 0;
591 
592         flags |= CLI_FLAG_BATCH;
593         while (!feof(input)) {
594                 struct uci_element *e, *tmp;
595 
596                 ret = uci_batch_cmd();
597                 if (ret == 254)
598                         return 0;
599                 else if (ret == 255)
600                         cli_error("Unknown command\n");
601 
602                 /* clean up */
603                 uci_foreach_element_safe(&ctx->root, tmp, e) {
604                         uci_unload(ctx, uci_to_package(e));
605                 }
606         }
607         flags &= ~CLI_FLAG_BATCH;
608 
609         return 0;
610 }
611 
612 static int uci_cmd(int argc, char **argv)
613 {
614         int cmd = 0;
615 
616         if (!strcasecmp(argv[0], "batch") && !(flags & CLI_FLAG_BATCH))
617                 return uci_batch();
618         else if (!strcasecmp(argv[0], "show"))
619                 cmd = CMD_SHOW;
620         else if (!strcasecmp(argv[0], "changes"))
621                 cmd = CMD_CHANGES;
622         else if (!strcasecmp(argv[0], "export"))
623                 cmd = CMD_EXPORT;
624         else if (!strcasecmp(argv[0], "commit"))
625                 cmd = CMD_COMMIT;
626         else if (!strcasecmp(argv[0], "get"))
627                 cmd = CMD_GET;
628         else if (!strcasecmp(argv[0], "set"))
629                 cmd = CMD_SET;
630         else if (!strcasecmp(argv[0], "ren") ||
631                  !strcasecmp(argv[0], "rename"))
632                 cmd = CMD_RENAME;
633         else if (!strcasecmp(argv[0], "revert"))
634                 cmd = CMD_REVERT;
635         else if (!strcasecmp(argv[0], "reorder"))
636                 cmd = CMD_REORDER;
637         else if (!strcasecmp(argv[0], "del") ||
638                  !strcasecmp(argv[0], "delete"))
639                 cmd = CMD_DEL;
640         else if (!strcasecmp(argv[0], "import"))
641                 cmd = CMD_IMPORT;
642         else if (!strcasecmp(argv[0], "help"))
643                 cmd = CMD_HELP;
644         else if (!strcasecmp(argv[0], "add"))
645                 cmd = CMD_ADD;
646         else if (!strcasecmp(argv[0], "add_list"))
647                 cmd = CMD_ADD_LIST;
648         else if (!strcasecmp(argv[0], "del_list"))
649                 cmd = CMD_DEL_LIST;
650         else
651                 cmd = -1;
652 
653         switch(cmd) {
654                 case CMD_ADD_LIST:
655                 case CMD_DEL_LIST:
656                 case CMD_GET:
657                 case CMD_SET:
658                 case CMD_DEL:
659                 case CMD_RENAME:
660                 case CMD_REVERT:
661                 case CMD_REORDER:
662                         return uci_do_section_cmd(cmd, argc, argv);
663                 case CMD_SHOW:
664                 case CMD_EXPORT:
665                 case CMD_COMMIT:
666                 case CMD_CHANGES:
667                         return uci_do_package_cmd(cmd, argc, argv);
668                 case CMD_IMPORT:
669                         return uci_do_import(argc, argv);
670                 case CMD_ADD:
671                         return uci_do_add(argc, argv);
672                 case CMD_HELP:
673                         uci_usage();
674                         return 0;
675                 default:
676                         return 255;
677         }
678 }
679 
680 int main(int argc, char **argv)
681 {
682         int ret;
683         int c;
684 
685         flags = CLI_FLAG_SHOW_EXT;
686         appname = argv[0];
687         input = stdin;
688         ctx = uci_alloc_context();
689         if (!ctx) {
690                 cli_error("Out of memory\n");
691                 return 1;
692         }
693 
694         while((c = getopt(argc, argv, "c:C:d:f:LmnNp:P:qsSt:X")) != -1) {
695                 switch(c) {
696                         case 'c':
697                                 uci_set_confdir(ctx, optarg);
698                                 break;
699                         case 'C':
700                                 uci_set_conf2dir(ctx, optarg);
701                                 break;
702                         case 'd':
703                                 delimiter = optarg;
704                                 break;
705                         case 'f':
706                                 if (input != stdin) {
707                                         fclose(input);
708                                         cli_error("Too many input files.\n");
709                                         return 1;
710                                 }
711 
712                                 input = fopen(optarg, "r");
713                                 if (!input) {
714                                         cli_error("uci: %s", strerror(errno));
715                                         return 1;
716                                 }
717                                 break;
718                         case 'm':
719                                 flags |= CLI_FLAG_MERGE;
720                                 break;
721                         case 's':
722                                 ctx->flags |= UCI_FLAG_STRICT;
723                                 break;
724                         case 'S':
725                                 ctx->flags &= ~UCI_FLAG_STRICT;
726                                 ctx->flags |= UCI_FLAG_PERROR;
727                                 break;
728                         case 'n':
729                                 ctx->flags |= UCI_FLAG_EXPORT_NAME;
730                                 break;
731                         case 'N':
732                                 ctx->flags &= ~UCI_FLAG_EXPORT_NAME;
733                                 break;
734                         case 'p':
735                                 uci_add_delta_path(ctx, optarg);
736                                 break;
737                         case 'P':
738                                 uci_set_savedir(ctx, optarg);
739                                 flags |= CLI_FLAG_NOCOMMIT;
740                                 break;
741                         case 'q':
742                                 flags |= CLI_FLAG_QUIET;
743                                 break;
744                         case 't':
745                                 uci_set_savedir(ctx, optarg);
746                                 break;
747                         case 'X':
748                                 flags &= ~CLI_FLAG_SHOW_EXT;
749                                 break;
750                         default:
751                                 uci_usage();
752                                 return 0;
753                 }
754         }
755         if (optind > 1)
756                 argv[optind - 1] = argv[0];
757         argv += optind - 1;
758         argc -= optind - 1;
759 
760         if (argc < 2) {
761                 uci_usage();
762                 return 0;
763         }
764 
765         ret = uci_cmd(argc - 1, argv + 1);
766         if (input != stdin)
767                 fclose(input);
768 
769         if (ret == 255)
770                 uci_usage();
771 
772         uci_free_context(ctx);
773 
774         return ret;
775 }
776 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt