3188bd19d2925cd8c7d34e985780fb079d45498b
[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 *appname;
23 static enum {
24         CLI_FLAG_MERGE =    (1 << 0),
25         CLI_FLAG_QUIET =    (1 << 1),
26         CLI_FLAG_NOCOMMIT = (1 << 2),
27         CLI_FLAG_BATCH =    (1 << 3),
28 } flags;
29
30 static FILE *input;
31
32 static struct uci_context *ctx;
33 enum {
34         /* section cmds */
35         CMD_GET,
36         CMD_SET,
37         CMD_DEL,
38         CMD_RENAME,
39         CMD_REVERT,
40         /* package cmds */
41         CMD_SHOW,
42         CMD_CHANGES,
43         CMD_EXPORT,
44         CMD_COMMIT,
45         /* other cmds */
46         CMD_IMPORT,
47         CMD_HELP,
48 };
49
50 static int uci_cmd(int argc, char **argv);
51
52 static void uci_usage(void)
53 {
54         fprintf(stderr,
55                 "Usage: %s [<options>] <command> [<arguments>]\n\n"
56                 "Commands:\n"
57                 "\tbatch\n"
58                 "\texport     [<config>]\n"
59                 "\timport     [<config>]\n"
60                 "\tshow       [<config>[.<section>[.<option>]]]\n"
61                 "\tget        <config>.<section>[.<option>]\n"
62                 "\tset        <config>.<section>[.<option>]=<value>\n"
63                 "\trename     <config>.<section>[.<option>]=<name>\n"
64                 "\trevert     <config>[.<section>[.<option>]]\n"
65                 "\n"
66                 "Options:\n"
67                 "\t-f <file>  use <file> as input instead of stdin\n"
68                 "\t-m         when importing, merge data into an existing package\n"
69                 "\t-n         name unnamed sections on export (default)\n"
70                 "\t-N         don't name unnamed sections\n"
71                 "\t-p <path>  add a search path for config change files\n"
72                 "\t-P <path>  add a search path for config change files and use as default\n"
73                 "\t-q         quiet mode (don't print error messages)\n"
74                 "\t-s         force strict mode (stop on parser errors, default)\n"
75                 "\t-S         disable strict mode\n"
76                 "\n",
77                 appname
78         );
79 }
80
81 static void cli_perror(void)
82 {
83         if (flags & CLI_FLAG_QUIET)
84                 return;
85
86         uci_perror(ctx, appname);
87 }
88
89 static void uci_show_section(struct uci_section *p)
90 {
91         struct uci_element *e;
92         const char *cname, *sname;
93
94         cname = p->package->e.name;
95         sname = p->e.name;
96         printf("%s.%s=%s\n", cname, sname, p->type);
97         uci_foreach_element(&p->options, e) {
98                 printf("%s.%s.%s=%s\n", cname, sname, e->name, uci_to_option(e)->value);
99         }
100 }
101
102 static void uci_show_package(struct uci_package *p)
103 {
104         struct uci_element *e;
105
106         uci_foreach_element( &p->sections, e) {
107                 uci_show_section(uci_to_section(e));
108         }
109 }
110
111 static void uci_show_changes(struct uci_package *p)
112 {
113         struct uci_element *e;
114
115         uci_foreach_element(&p->saved_history, e) {
116                 struct uci_history *h = uci_to_history(e);
117
118                 if (h->cmd == UCI_CMD_REMOVE)
119                         printf("-");
120                 printf("%s.%s", p->e.name, h->section);
121                 if (e->name)
122                         printf(".%s", e->name);
123                 if (h->cmd != UCI_CMD_REMOVE)
124                         printf("=%s", h->value);
125                 printf("\n");
126         }
127 }
128
129 static int package_cmd(int cmd, char *package)
130 {
131         struct uci_package *p = NULL;
132         int ret;
133
134         if (cmd == CMD_CHANGES)
135                 ctx->flags |= UCI_FLAG_SAVED_HISTORY;
136         ret = uci_load(ctx, package, &p);
137         if (cmd == CMD_CHANGES)
138                 ctx->flags &= ~UCI_FLAG_SAVED_HISTORY;
139
140         if (ret != UCI_OK) {
141                 cli_perror();
142                 return 1;
143         }
144         if (!p)
145                 return 0;
146         switch(cmd) {
147         case CMD_CHANGES:
148                 uci_show_changes(p);
149                 break;
150         case CMD_COMMIT:
151                 if (flags & CLI_FLAG_NOCOMMIT)
152                         return 0;
153                 if (uci_commit(ctx, &p, false) != UCI_OK)
154                         cli_perror();
155                 break;
156         case CMD_EXPORT:
157                 uci_export(ctx, stdout, p, true);
158                 break;
159         case CMD_SHOW:
160                 uci_show_package(p);
161                 break;
162         }
163
164         uci_unload(ctx, p);
165         return 0;
166 }
167
168 static int uci_do_import(int argc, char **argv)
169 {
170         struct uci_package *package = NULL;
171         char *name = NULL;
172         int ret = UCI_OK;
173
174         if (argc > 2)
175                 return 255;
176
177         if (argc == 2)
178                 name = argv[1];
179         else if (flags & CLI_FLAG_MERGE)
180                 /* need a package to merge */
181                 return 255;
182
183         if (flags & CLI_FLAG_MERGE) {
184                 if (uci_load(ctx, name, &package) != UCI_OK)
185                         package = NULL;
186         }
187         ret = uci_import(ctx, input, name, &package, (name != NULL));
188         if (ret == UCI_OK) {
189                 if (flags & CLI_FLAG_MERGE) {
190                         ret = uci_save(ctx, package);
191                 } else {
192                         struct uci_element *e;
193                         /* loop through all config sections and overwrite existing data */
194                         uci_foreach_element(&ctx->root, e) {
195                                 struct uci_package *p = uci_to_package(e);
196                                 ret = uci_commit(ctx, &p, true);
197                         }
198                 }
199         }
200
201         if (ret != UCI_OK) {
202                 cli_perror();
203                 return 1;
204         }
205
206         return 0;
207 }
208
209 static int uci_do_package_cmd(int cmd, int argc, char **argv)
210 {
211         char **configs = NULL;
212         char **p;
213
214         if (argc > 2)
215                 return 255;
216
217         if (argc == 2)
218                 return package_cmd(cmd, argv[1]);
219
220         if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs) {
221                 cli_perror();
222                 return 1;
223         }
224
225         for (p = configs; *p; p++) {
226                 package_cmd(cmd, *p);
227         }
228
229         return 0;
230 }
231
232
233 static int uci_do_section_cmd(int cmd, int argc, char **argv)
234 {
235         struct uci_package *p = NULL;
236         struct uci_element *e = NULL;
237         char *package = NULL;
238         char *section = NULL;
239         char *option = NULL;
240         char *value = NULL;
241         char **ptr = NULL;
242         int ret = UCI_OK;
243
244         if (argc != 2)
245                 return 255;
246
247         switch(cmd) {
248         case CMD_SET:
249         case CMD_RENAME:
250                 ptr = &value;
251                 break;
252         default:
253                 break;
254         }
255         if (uci_parse_tuple(ctx, argv[1], &package, &section, &option, ptr) != UCI_OK)
256                 return 1;
257
258         if (uci_load(ctx, package, &p) != UCI_OK) {
259                 cli_perror();
260                 return 1;
261         }
262         if (!p)
263                 return 0;
264
265         switch(cmd) {
266         case CMD_GET:
267                 if (uci_lookup(ctx, &e, p, section, option) != UCI_OK)
268                         return 1;
269
270                 switch(e->type) {
271                 case UCI_TYPE_SECTION:
272                         value = uci_to_section(e)->type;
273                         break;
274                 case UCI_TYPE_OPTION:
275                         value = uci_to_option(e)->value;
276                         break;
277                 default:
278                         /* should not happen */
279                         return 1;
280                 }
281                 /* throw the value to stdout */
282                 printf("%s\n", value);
283                 break;
284         case CMD_RENAME:
285                 ret = uci_rename(ctx, p, section, option, value);
286                 break;
287         case CMD_REVERT:
288                 ret = uci_revert(ctx, &p, section, option);
289                 break;
290         case CMD_SET:
291                 ret = uci_set(ctx, p, section, option, value);
292                 break;
293         case CMD_DEL:
294                 ret = uci_delete(ctx, p, section, option);
295                 break;
296         }
297
298         /* no save necessary for get */
299         if ((cmd == CMD_GET) || (cmd == CMD_REVERT))
300                 return 0;
301
302         /* save changes, but don't commit them yet */
303         if (ret == UCI_OK)
304                 ret = uci_save(ctx, p);
305
306         if (ret != UCI_OK) {
307                 cli_perror();
308                 return 1;
309         }
310
311         return 0;
312 }
313
314 static int uci_batch_cmd(void)
315 {
316         char *argv[MAX_ARGS];
317         char *str = NULL;
318         int ret = 0;
319         int i, j;
320
321         for(i = 0; i <= MAX_ARGS; i++) {
322                 if (i == MAX_ARGS) {
323                         fprintf(stderr, "Too many arguments\n");
324                         return 1;
325                 }
326                 argv[i] = NULL;
327                 if ((ret = uci_parse_argument(ctx, input, &str, &argv[i])) != UCI_OK) {
328                         cli_perror();
329                         i = 0;
330                         break;
331                 }
332                 if (!argv[i][0])
333                         break;
334                 argv[i] = strdup(argv[i]);
335                 if (!argv[i]) {
336                         perror("uci");
337                         return 1;
338                 }
339         }
340         argv[i] = NULL;
341
342         if (i > 0) {
343                 if (!strcasecmp(argv[0], "exit"))
344                         return 254;
345                 ret = uci_cmd(i, argv);
346         } else
347                 return 0;
348
349         for (j = 0; j < i; j++) {
350                 if (argv[j])
351                         free(argv[j]);
352         }
353
354         return ret;
355 }
356
357 static int uci_batch(void)
358 {
359         int ret = 0;
360
361         while (!feof(input)) {
362                 struct uci_element *e, *tmp;
363
364                 ret = uci_batch_cmd();
365                 if (ret == 254)
366                         return 0;
367                 else if (ret == 255)
368                         fprintf(stderr, "Unknown command\n");
369
370                 /* clean up */
371                 uci_cleanup(ctx);
372                 uci_foreach_element_safe(&ctx->root, tmp, e) {
373                         uci_unload(ctx, uci_to_package(e));
374                 }
375         }
376         return 0;
377 }
378
379 static int uci_cmd(int argc, char **argv)
380 {
381         int cmd = 0;
382
383         if (!strcasecmp(argv[0], "batch") && !(flags & CLI_FLAG_BATCH))
384                 return uci_batch();
385         else if (!strcasecmp(argv[0], "show"))
386                 cmd = CMD_SHOW;
387         else if (!strcasecmp(argv[0], "changes"))
388                 cmd = CMD_CHANGES;
389         else if (!strcasecmp(argv[0], "export"))
390                 cmd = CMD_EXPORT;
391         else if (!strcasecmp(argv[0], "commit"))
392                 cmd = CMD_COMMIT;
393         else if (!strcasecmp(argv[0], "get"))
394                 cmd = CMD_GET;
395         else if (!strcasecmp(argv[0], "set"))
396                 cmd = CMD_SET;
397         else if (!strcasecmp(argv[0], "ren") ||
398                  !strcasecmp(argv[0], "rename"))
399                 cmd = CMD_RENAME;
400         else if (!strcasecmp(argv[0], "revert"))
401                 cmd = CMD_REVERT;
402         else if (!strcasecmp(argv[0], "del"))
403                 cmd = CMD_DEL;
404         else if (!strcasecmp(argv[0], "import"))
405                 cmd = CMD_IMPORT;
406         else if (!strcasecmp(argv[0], "help"))
407                 cmd = CMD_HELP;
408         else
409                 cmd = -1;
410
411         switch(cmd) {
412                 case CMD_GET:
413                 case CMD_SET:
414                 case CMD_DEL:
415                 case CMD_RENAME:
416                 case CMD_REVERT:
417                         return uci_do_section_cmd(cmd, argc, argv);
418                 case CMD_SHOW:
419                 case CMD_EXPORT:
420                 case CMD_COMMIT:
421                 case CMD_CHANGES:
422                         return uci_do_package_cmd(cmd, argc, argv);
423                 case CMD_IMPORT:
424                         return uci_do_import(argc, argv);
425                 case CMD_HELP:
426                         uci_usage();
427                         return 0;
428                 default:
429                         return 255;
430         }
431 }
432
433 int main(int argc, char **argv)
434 {
435         int ret;
436         int c;
437
438         appname = argv[0];
439         input = stdin;
440         ctx = uci_alloc_context();
441         if (!ctx) {
442                 fprintf(stderr, "Out of memory\n");
443                 return 1;
444         }
445
446         while((c = getopt(argc, argv, "f:mnNp:P:sSq")) != -1) {
447                 switch(c) {
448                         case 'f':
449                                 input = fopen(optarg, "r");
450                                 if (!input) {
451                                         perror("uci");
452                                         return 1;
453                                 }
454                                 break;
455                         case 'm':
456                                 flags |= CLI_FLAG_MERGE;
457                                 break;
458                         case 's':
459                                 ctx->flags |= UCI_FLAG_STRICT;
460                                 break;
461                         case 'S':
462                                 ctx->flags &= ~UCI_FLAG_STRICT;
463                                 ctx->flags |= UCI_FLAG_PERROR;
464                                 break;
465                         case 'n':
466                                 ctx->flags |= UCI_FLAG_EXPORT_NAME;
467                                 break;
468                         case 'N':
469                                 ctx->flags &= ~UCI_FLAG_EXPORT_NAME;
470                                 break;
471                         case 'p':
472                                 uci_add_history_path(ctx, optarg);
473                                 break;
474                         case 'P':
475                                 uci_add_history_path(ctx, ctx->savedir);
476                                 uci_set_savedir(ctx, optarg);
477                                 flags |= CLI_FLAG_NOCOMMIT;
478                                 break;
479                         case 'q':
480                                 flags |= CLI_FLAG_QUIET;
481                                 break;
482                         default:
483                                 uci_usage();
484                                 return 0;
485                 }
486         }
487         if (optind > 1)
488                 argv[optind - 1] = argv[0];
489         argv += optind - 1;
490         argc -= optind - 1;
491
492         if (argc < 2) {
493                 uci_usage();
494                 return 0;
495         }
496         ret = uci_cmd(argc - 1, argv + 1);
497         if (input != stdin)
498                 fclose(input);
499         if (ret == 255) {
500                 uci_usage();
501                 return 0;
502         }
503
504         uci_free_context(ctx);
505
506         return ret;
507 }