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