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