cli: don't commit, if the savedir was overwritten
[project/uci.git] / cli.c
1 /*
2 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13 #include <strings.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include "uci.h"
17
18 static const char *appname = "uci";
19 static enum {
20 CLI_FLAG_MERGE = (1 << 0),
21 CLI_FLAG_QUIET = (1 << 1),
22 CLI_FLAG_NOCOMMIT = (1 << 2),
23 } flags;
24 static FILE *input;
25
26 static struct uci_context *ctx;
27 enum {
28 /* section cmds */
29 CMD_GET,
30 CMD_SET,
31 CMD_DEL,
32 CMD_RENAME,
33 /* package cmds */
34 CMD_SHOW,
35 CMD_IMPORT,
36 CMD_EXPORT,
37 CMD_COMMIT,
38 };
39
40 static void uci_usage(int argc, char **argv)
41 {
42 fprintf(stderr,
43 "Usage: %s [<options>] <command> [<arguments>]\n\n"
44 "Commands:\n"
45 "\texport [<config>]\n"
46 "\timport [<config>]\n"
47 "\tshow [<config>[.<section>[.<option>]]]\n"
48 "\tget <config>.<section>[.<option>]\n"
49 "\tset <config>.<section>[.<option>]=<value>\n"
50 "\trename <config>.<section>[.<option>]=<name>\n"
51 "\n"
52 "Options:\n"
53 "\t-f <file> use <file> as input instead of stdin\n"
54 "\t-m when importing, merge data into an existing package\n"
55 "\t-n name unnamed sections on export (default)\n"
56 "\t-N don't name unnamed sections\n"
57 "\t-p <path> add a search path for config change files\n"
58 "\t-P <path> add a search path for config change files and use as default\n"
59 "\t-q quiet mode (don't print error messages)\n"
60 "\t-s force strict mode (stop on parser errors, default)\n"
61 "\t-S disable strict mode\n"
62 "\n",
63 argv[0]
64 );
65 exit(255);
66 }
67
68 static void cli_perror(void)
69 {
70 if (flags & CLI_FLAG_QUIET)
71 return;
72
73 uci_perror(ctx, appname);
74 }
75
76 static void uci_show_section(struct uci_section *p)
77 {
78 struct uci_element *e;
79 const char *cname, *sname;
80
81 cname = p->package->e.name;
82 sname = p->e.name;
83 printf("%s.%s=%s\n", cname, sname, p->type);
84 uci_foreach_element(&p->options, e) {
85 printf("%s.%s.%s=%s\n", cname, sname, e->name, uci_to_option(e)->value);
86 }
87 }
88
89 static void uci_show_package(struct uci_package *p)
90 {
91 struct uci_element *e;
92
93 uci_foreach_element( &p->sections, e) {
94 uci_show_section(uci_to_section(e));
95 }
96 }
97
98
99 static int package_cmd(int cmd, char *package)
100 {
101 struct uci_package *p = NULL;
102
103 if (uci_load(ctx, package, &p) != UCI_OK) {
104 cli_perror();
105 return 1;
106 }
107 if (!p)
108 return 0;
109 switch(cmd) {
110 case CMD_COMMIT:
111 if (flags & CLI_FLAG_NOCOMMIT)
112 return 0;
113 if (uci_commit(ctx, &p, false) != UCI_OK)
114 cli_perror();
115 break;
116 case CMD_EXPORT:
117 uci_export(ctx, stdout, p, true);
118 break;
119 case CMD_SHOW:
120 uci_show_package(p);
121 break;
122 }
123
124 uci_unload(ctx, p);
125 return 0;
126 }
127
128 static int uci_do_import(int argc, char **argv)
129 {
130 struct uci_package *package = NULL;
131 char *name = NULL;
132 int ret = UCI_OK;
133
134 if (argc > 2)
135 return 255;
136
137 if (argc == 2)
138 name = argv[1];
139 else if (flags & CLI_FLAG_MERGE)
140 /* need a package to merge */
141 return 255;
142
143 if (flags & CLI_FLAG_MERGE) {
144 if (uci_load(ctx, name, &package) != UCI_OK)
145 package = NULL;
146 }
147 ret = uci_import(ctx, input, name, &package, (name != NULL));
148 if (ret == UCI_OK) {
149 if (flags & CLI_FLAG_MERGE) {
150 ret = uci_save(ctx, package);
151 } else {
152 struct uci_element *e;
153 /* loop through all config sections and overwrite existing data */
154 uci_foreach_element(&ctx->root, e) {
155 struct uci_package *p = uci_to_package(e);
156 ret = uci_commit(ctx, &p, true);
157 }
158 }
159 }
160
161 if (ret != UCI_OK) {
162 cli_perror();
163 return 1;
164 }
165
166 return 0;
167 }
168
169 static int uci_do_package_cmd(int cmd, int argc, char **argv)
170 {
171 char **configs = NULL;
172 char **p;
173
174 if (argc > 2)
175 return 255;
176
177 if (argc == 2)
178 return package_cmd(cmd, argv[1]);
179
180 if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs) {
181 cli_perror();
182 return 1;
183 }
184
185 for (p = configs; *p; p++) {
186 package_cmd(cmd, *p);
187 }
188
189 return 0;
190 }
191
192
193 static int uci_do_section_cmd(int cmd, int argc, char **argv)
194 {
195 struct uci_package *p = NULL;
196 struct uci_element *e = NULL;
197 char *package = NULL;
198 char *section = NULL;
199 char *option = NULL;
200 char *value = NULL;
201 char **ptr = NULL;
202 int ret = UCI_OK;
203
204 if (argc != 2)
205 return 255;
206
207 switch(cmd) {
208 case CMD_SET:
209 case CMD_RENAME:
210 ptr = &value;
211 break;
212 default:
213 break;
214 }
215 if (uci_parse_tuple(ctx, argv[1], &package, &section, &option, ptr) != UCI_OK)
216 return 1;
217
218 if (uci_load(ctx, package, &p) != UCI_OK) {
219 cli_perror();
220 return 1;
221 }
222 if (!p)
223 return 0;
224
225 switch(cmd) {
226 case CMD_GET:
227 if (uci_lookup(ctx, &e, p, section, option) != UCI_OK)
228 return 1;
229
230 switch(e->type) {
231 case UCI_TYPE_SECTION:
232 value = uci_to_section(e)->type;
233 break;
234 case UCI_TYPE_OPTION:
235 value = uci_to_option(e)->value;
236 break;
237 default:
238 /* should not happen */
239 return 1;
240 }
241 /* throw the value to stdout */
242 printf("%s\n", value);
243 break;
244 case CMD_RENAME:
245 ret = uci_rename(ctx, p, section, option, value);
246 break;
247 case CMD_SET:
248 ret = uci_set(ctx, p, section, option, value);
249 break;
250 case CMD_DEL:
251 ret = uci_delete(ctx, p, section, option);
252 break;
253 }
254
255 /* no save necessary for get */
256 if (cmd == CMD_GET)
257 return 0;
258
259 /* save changes, but don't commit them yet */
260 if (ret == UCI_OK)
261 ret = uci_save(ctx, p);
262
263 if (ret != UCI_OK) {
264 cli_perror();
265 return 1;
266 }
267
268 return 0;
269 }
270
271 static int uci_cmd(int argc, char **argv)
272 {
273 int cmd = 0;
274
275 if (!strcasecmp(argv[0], "show"))
276 cmd = CMD_SHOW;
277 else if (!strcasecmp(argv[0], "export"))
278 cmd = CMD_EXPORT;
279 else if (!strcasecmp(argv[0], "commit"))
280 cmd = CMD_COMMIT;
281 else if (!strcasecmp(argv[0], "get"))
282 cmd = CMD_GET;
283 else if (!strcasecmp(argv[0], "set"))
284 cmd = CMD_SET;
285 else if (!strcasecmp(argv[0], "ren") ||
286 !strcasecmp(argv[0], "rename"))
287 cmd = CMD_RENAME;
288 else if (!strcasecmp(argv[0], "del"))
289 cmd = CMD_DEL;
290 else if (!strcasecmp(argv[0], "import"))
291 cmd = CMD_IMPORT;
292 else
293 cmd = -1;
294
295 switch(cmd) {
296 case CMD_GET:
297 case CMD_SET:
298 case CMD_DEL:
299 case CMD_RENAME:
300 return uci_do_section_cmd(cmd, argc, argv);
301 case CMD_SHOW:
302 case CMD_EXPORT:
303 case CMD_COMMIT:
304 return uci_do_package_cmd(cmd, argc, argv);
305 case CMD_IMPORT:
306 return uci_do_import(argc, argv);
307 default:
308 return 255;
309 }
310 }
311
312 int main(int argc, char **argv)
313 {
314 int ret;
315 int c;
316
317 input = stdin;
318 ctx = uci_alloc_context();
319 if (!ctx) {
320 fprintf(stderr, "Out of memory\n");
321 return 1;
322 }
323
324 while((c = getopt(argc, argv, "f:mnNp:P:sSq")) != -1) {
325 switch(c) {
326 case 'f':
327 input = fopen(optarg, "r");
328 if (!input) {
329 perror("uci");
330 return 1;
331 }
332 break;
333 case 'm':
334 flags |= CLI_FLAG_MERGE;
335 break;
336 case 's':
337 ctx->flags |= UCI_FLAG_STRICT;
338 break;
339 case 'S':
340 ctx->flags &= ~UCI_FLAG_STRICT;
341 ctx->flags |= UCI_FLAG_PERROR;
342 break;
343 case 'n':
344 ctx->flags |= UCI_FLAG_EXPORT_NAME;
345 break;
346 case 'N':
347 ctx->flags &= ~UCI_FLAG_EXPORT_NAME;
348 break;
349 case 'p':
350 uci_add_history_path(ctx, optarg);
351 break;
352 case 'P':
353 uci_add_history_path(ctx, ctx->savedir);
354 uci_set_savedir(ctx, optarg);
355 flags |= CLI_FLAG_NOCOMMIT;
356 break;
357 case 'q':
358 flags |= CLI_FLAG_QUIET;
359 break;
360 default:
361 uci_usage(argc, argv);
362 break;
363 }
364 }
365 if (optind > 1)
366 argv[optind - 1] = argv[0];
367 argv += optind - 1;
368 argc -= optind - 1;
369
370 if (argc < 2)
371 uci_usage(argc, argv);
372 ret = uci_cmd(argc - 1, argv + 1);
373 if (input != stdin)
374 fclose(input);
375 if (ret == 255)
376 uci_usage(argc, argv);
377
378 uci_free_context(ctx);
379
380 return ret;
381 }