2 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <sys/queue.h>
39 #include <cmdline_parse.h>
40 #include <cmdline_parse_ipaddr.h>
41 #include <cmdline_parse_num.h>
42 #include <cmdline_parse_string.h>
43 #include <cmdline_rdline.h>
46 #include "parse_confnode.h"
47 #include "expression.h"
48 #include "conf_parser.h"
50 #include "conf_htable.h"
51 #include "dotconfig.h"
53 extern struct confnode *conf_cur;
54 extern struct confnode *conf_root;
56 /**********************************************************/
58 /**********************************************************/
60 struct cmd_ls_result {
61 cmdline_fixed_string_t ls;
64 static void do_ls(const struct confnode *n)
66 const struct confnode *c;
68 TAILQ_FOREACH(c, &n->children, next) {
69 if (c->flags & CONFNODE_F_INVISIBLE)
72 confnode_display_short(c);
76 static void cmd_ls_parsed(void *parsed_result,
83 cmdline_parse_token_string_t cmd_ls_ls =
84 TOKEN_STRING_INITIALIZER(struct cmd_ls_result, ls, "ls");
86 cmdline_parse_inst_t cmd_ls = {
87 .f = cmd_ls_parsed, /* function to call */
88 .data = NULL, /* 2nd arg of func */
89 .help_str = "<ls> list all config options in current directory",
90 .tokens = { /* token list, NULL terminated */
96 /**********************************************************/
98 /**********************************************************/
100 struct cmd_ls_node_result {
101 cmdline_fixed_string_t ls;
102 struct confnode *node;
105 static void cmd_ls_node_parsed(void *parsed_result,
109 struct cmd_ls_node_result *res = parsed_result;
110 struct confnode *n = res->node;
113 confnode_display_short(n);
114 n = TAILQ_NEXT(n, user_next);
118 cmdline_parse_token_string_t cmd_ls_node_ls =
119 TOKEN_STRING_INITIALIZER(struct cmd_ls_node_result, ls, "ls");
120 parse_token_conf_node_t cmd_ls_node_node =
121 TOKEN_CONF_NODE_INITIALIZER(struct cmd_ls_node_result, node,
122 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
124 cmdline_parse_inst_t cmd_ls_node = {
125 .f = cmd_ls_node_parsed, /* function to call */
126 .data = NULL, /* 2nd arg of func */
127 .help_str = "<ls NODE> list config node(s) given in argument",
128 .tokens = { /* token list, NULL terminated */
129 (void *)&cmd_ls_node_ls,
130 (void *)&cmd_ls_node_node,
135 /**********************************************************/
137 /**********************************************************/
139 struct cmd_pwd_result {
140 cmdline_fixed_string_t pwd;
143 static void cmd_pwd_parsed(void *parsed_result,
147 conf_display_path(conf_cur);
150 cmdline_parse_token_string_t cmd_pwd_pwd =
151 TOKEN_STRING_INITIALIZER(struct cmd_pwd_result, pwd, "pwd");
153 cmdline_parse_inst_t cmd_pwd = {
154 .f = cmd_pwd_parsed, /* function to call */
155 .data = NULL, /* 2nd arg of func */
156 .help_str = "<pwd> display current directory",
157 .tokens = { /* token list, NULL terminated */
158 (void *)&cmd_pwd_pwd,
163 /**********************************************************/
165 /**********************************************************/
167 struct cmd_cd_prev_result {
168 cmdline_fixed_string_t cd;
169 cmdline_fixed_string_t prev;
172 static void cmd_cd_prev_parsed(void *parsed_result,
176 struct confnode *parent = conf_cur->parent;
177 char prompt[RDLINE_PROMPT_SIZE];
179 if (parent == NULL) {
180 printf("already at top level\n");
183 while ((parent->flags & CONFNODE_F_INVISIBLE) && parent->parent != NULL)
184 parent = parent->parent;
187 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
188 cmdline_set_prompt(cl, prompt);
191 cmdline_parse_token_string_t cmd_cd_prev_cd =
192 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, cd, "cd");
193 cmdline_parse_token_string_t cmd_cd_prev_prev =
194 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, prev, "..");
196 cmdline_parse_inst_t cmd_cd_prev = {
197 .f = cmd_cd_prev_parsed, /* function to call */
198 .data = NULL, /* 2nd arg of func */
199 .help_str = "<cd ..> go up in configuration tree",
200 .tokens = { /* token list, NULL terminated */
201 (void *)&cmd_cd_prev_cd,
202 (void *)&cmd_cd_prev_prev,
207 /**********************************************************/
209 /**********************************************************/
211 struct cmd_cd_root_result {
212 cmdline_fixed_string_t cd;
213 cmdline_fixed_string_t root;
216 static void cmd_cd_root_parsed(void *parsed_result,
220 char prompt[RDLINE_PROMPT_SIZE];
222 conf_cur = conf_root;
223 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
224 cmdline_set_prompt(cl, prompt);
227 cmdline_parse_token_string_t cmd_cd_root_cd =
228 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, cd, "cd");
229 cmdline_parse_token_string_t cmd_cd_root_root =
230 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, root, "/");
232 cmdline_parse_inst_t cmd_cd_root = {
233 .f = cmd_cd_root_parsed, /* function to call */
234 .data = NULL, /* 2nd arg of func */
235 .help_str = "<cd /> go to root of configuration",
236 .tokens = { /* token list, NULL terminated */
237 (void *)&cmd_cd_root_cd,
238 (void *)&cmd_cd_root_root,
243 /**********************************************************/
245 /**********************************************************/
247 struct cmd_cd_node_result {
248 cmdline_fixed_string_t cd;
249 struct confnode *node;
252 static void cmd_cd_node_parsed(void *parsed_result,
256 struct cmd_cd_node_result *res = parsed_result;
257 char prompt[RDLINE_PROMPT_SIZE];
259 if (TAILQ_NEXT(res->node, user_next)) {
260 printf("ambiguous directory\n");
263 conf_cur = res->node;
264 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
265 cmdline_set_prompt(cl, prompt);
268 cmdline_parse_token_string_t cmd_cd_node_cd =
269 TOKEN_STRING_INITIALIZER(struct cmd_cd_node_result, cd, "cd");
270 parse_token_conf_node_t cmd_cd_node_node =
271 TOKEN_CONF_NODE_INITIALIZER(struct cmd_cd_node_result, node,
272 &conf_root, &conf_cur,
274 CONFNODE_F_IS_DIR|CONFNODE_F_INVISIBLE);
276 cmdline_parse_inst_t cmd_cd_node = {
277 .f = cmd_cd_node_parsed, /* function to call */
278 .data = NULL, /* 2nd arg of func */
279 .help_str = "<cd CONFNODE> go down in a configuration sub-tree",
280 .tokens = { /* token list, NULL terminated */
281 (void *)&cmd_cd_node_cd,
282 (void *)&cmd_cd_node_node,
287 /**********************************************************/
289 /**********************************************************/
291 struct cmd_set_bool_result {
292 cmdline_fixed_string_t set;
293 struct confnode *node;
294 cmdline_fixed_string_t val;
297 static void cmd_set_bool_parsed(void *parsed_result,
301 struct cmd_set_bool_result *res = parsed_result;
302 struct confnode *n = res->node;
306 if (confnode_set_user_strvalue(n, res->val) < 0)
307 printf("Error, cannot set value\n");
309 if (strcmp(res->val, "y") == 0)
310 confnode_check_deps(n, 1);
311 if (confnode_get_value(n, value,
313 printf("Error, cannot re-read value\n");
315 printf("<%s> value set to %s\n", n->name, value);
316 n = TAILQ_NEXT(n, user_next);
320 cmdline_parse_token_string_t cmd_set_bool_set =
321 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, set, "set");
322 parse_token_conf_node_t cmd_set_bool_node =
323 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_bool_result, node,
324 &conf_root, &conf_cur,
326 CONFNODE_F_BOOL|CONFNODE_F_INVISIBLE);
327 cmdline_parse_token_string_t cmd_set_bool_val =
328 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, val, "y#n");
330 cmdline_parse_inst_t cmd_set_bool = {
331 .f = cmd_set_bool_parsed, /* function to call */
332 .data = NULL, /* 2nd arg of func */
333 .help_str = "<set CONFNODE y|n> set boolean value",
334 .tokens = { /* token list, NULL terminated */
335 (void *)&cmd_set_bool_set,
336 (void *)&cmd_set_bool_node,
337 (void *)&cmd_set_bool_val,
342 /**********************************************************/
344 /**********************************************************/
346 struct cmd_set_int_result {
347 cmdline_fixed_string_t set;
348 struct confnode *node;
352 static void cmd_set_int_parsed(void *parsed_result,
356 struct cmd_set_int_result *res = parsed_result;
357 struct confnode *n = res->node;
361 snprintf(value, sizeof(value), "%"PRIi32, res->val);
362 if (confnode_set_user_strvalue(n, value) < 0)
363 printf("Error, cannot set value\n");
366 confnode_check_deps(n, 1);
367 if (confnode_get_value(n, value,
369 printf("Error, cannot re-read value\n");
371 printf("<%s> value set to %s\n", n->name, value);
372 n = TAILQ_NEXT(n, user_next);
376 cmdline_parse_token_string_t cmd_set_int_set =
377 TOKEN_STRING_INITIALIZER(struct cmd_set_int_result, set, "set");
378 parse_token_conf_node_t cmd_set_int_node =
379 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_int_result, node,
380 &conf_root, &conf_cur,
382 CONFNODE_F_INT|CONFNODE_F_INVISIBLE);
383 cmdline_parse_token_num_t cmd_set_int_val =
384 TOKEN_NUM_INITIALIZER(struct cmd_set_int_result, val, INT32);
386 cmdline_parse_inst_t cmd_set_int = {
387 .f = cmd_set_int_parsed, /* function to call */
388 .data = NULL, /* 2nd arg of func */
389 .help_str = "<set CONFNODE INT> set integer value",
390 .tokens = { /* token list, NULL terminated */
391 (void *)&cmd_set_int_set,
392 (void *)&cmd_set_int_node,
393 (void *)&cmd_set_int_val,
398 /**********************************************************/
400 /**********************************************************/
402 struct cmd_set_str_result {
403 cmdline_fixed_string_t set;
404 struct confnode *node;
407 static int get_str(struct cmdline *cl, char *buf, int len)
416 rdline_init(&rl, cmdline_write_char, NULL, NULL);
418 rdline_newline(&rl, "edit> ");
420 while (ret == 0 || ret == 2) {
421 n = read(cl->s_in, &c, 1);
424 ret = rdline_char_in(&rl, c);
426 snprintf(buf, len, "%s", rdline_get_buffer(&rl));
427 s = strchr(buf, '\n');
437 static void cmd_set_str_parsed(void *parsed_result,
441 struct cmd_set_str_result *res = parsed_result;
442 struct confnode *n = res->node;
445 if (confnode_get_value(res->node, value, sizeof(value)) < 0) {
446 printf("Error, cannot read value\n");
449 printf("Previous value is %s\n", value);
450 printf("type CTRL-d on an empty line to abort\n");
451 if (get_str(cl, value, sizeof(value))) {
456 snprintf(res->node->value, sizeof(res->node->value),
458 if (strcmp(value, ""))
459 confnode_check_deps(n, 1);
460 if (confnode_get_value(n, value,
462 printf("Error, cannot re-read value\n");
463 printf("<%s> value set to %s\n", n->name, value);
464 n = TAILQ_NEXT(n, user_next);
468 cmdline_parse_token_string_t cmd_set_str_set =
469 TOKEN_STRING_INITIALIZER(struct cmd_set_str_result, set, "set");
470 parse_token_conf_node_t cmd_set_str_node =
471 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_str_result, node,
472 &conf_root, &conf_cur,
474 CONFNODE_F_STR|CONFNODE_F_INVISIBLE);
476 cmdline_parse_inst_t cmd_set_str = {
477 .f = cmd_set_str_parsed, /* function to call */
478 .data = NULL, /* 2nd arg of func */
479 .help_str = "<set CONFNODE> set str value",
480 .tokens = { /* token list, NULL terminated */
481 (void *)&cmd_set_str_set,
482 (void *)&cmd_set_str_node,
487 /**********************************************************/
489 /**********************************************************/
491 struct cmd_show_node_result {
492 cmdline_fixed_string_t show;
493 cmdline_fixed_string_t all;
494 struct confnode *node;
497 static void cmd_show_node_parsed(void *parsed_result,
501 struct cmd_show_node_result *res = parsed_result;
502 struct confnode *n = res->node;
509 confnode_display_long(n);
510 n = TAILQ_NEXT(n, user_next);
514 cmdline_parse_token_string_t cmd_show_node_show =
515 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, show, "show");
516 cmdline_parse_token_string_t cmd_show_node_all =
517 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, all, "-a");
518 parse_token_conf_node_t cmd_show_node_node =
519 TOKEN_CONF_NODE_INITIALIZER(struct cmd_show_node_result, node,
520 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
522 cmdline_parse_inst_t cmd_show_node = {
523 .f = cmd_show_node_parsed, /* function to call */
524 .data = NULL, /* 2nd arg of func */
525 .help_str = "<show CONFNODE> display infos on the config option",
526 .tokens = { /* token list, NULL terminated */
527 (void *)&cmd_show_node_show,
528 (void *)&cmd_show_node_node,
533 cmdline_parse_inst_t cmd_show_node_a = {
534 .f = cmd_show_node_parsed, /* function to call */
535 .data = (void *)1, /* 2nd arg of func */
536 .help_str = "<show -a CONFNODE> display detailed infos on the config option",
537 .tokens = { /* token list, NULL terminated */
538 (void *)&cmd_show_node_show,
539 (void *)&cmd_show_node_all,
540 (void *)&cmd_show_node_node,
545 /**********************************************************/
546 /* load / load file */
547 /**********************************************************/
549 struct cmd_load_result {
550 cmdline_fixed_string_t load;
551 cmdline_fixed_string_t file;
554 static void cmd_load_parsed(void *parsed_result,
558 char prompt[RDLINE_PROMPT_SIZE];
559 struct cmd_load_result *res = parsed_result;
560 const char *filename;
565 filename = res->file;
567 conf_cur = conf_reset_and_read(conf_root, filename);
568 if (conf_root == NULL) {
569 printf("error loading <%s>\n", filename);
572 conf_cur = conf_root;
573 snprintf(prompt, sizeof(prompt), "root> ");
575 printf("%s loaded\n", filename);
578 cmdline_parse_token_string_t cmd_load_load =
579 TOKEN_STRING_INITIALIZER(struct cmd_load_result, load, "load");
581 cmdline_parse_inst_t cmd_load = {
582 .f = cmd_load_parsed, /* function to call */
583 .data = ".config", /* 2nd arg of func */
584 .help_str = "<load> reload the .config file",
585 .tokens = { /* token list, NULL terminated */
586 (void *)&cmd_load_load,
591 cmdline_parse_token_string_t cmd_load_file =
592 TOKEN_STRING_INITIALIZER(struct cmd_load_result, file, NULL);
594 cmdline_parse_inst_t cmd_loadfile = {
595 .f = cmd_load_parsed, /* function to call */
596 .data = NULL, /* 2nd arg of func */
597 .help_str = "<load FILE> load another .config file",
598 .tokens = { /* token list, NULL terminated */
599 (void *)&cmd_load_load,
600 (void *)&cmd_load_file,
605 /**********************************************************/
606 /* save / save file */
607 /**********************************************************/
609 struct cmd_save_result {
610 cmdline_fixed_string_t save;
611 cmdline_fixed_string_t file;
614 static void cmd_save_parsed(void *parsed_result,
618 struct cmd_save_result *res = parsed_result;
619 const char *filename;
624 filename = res->file;
626 if (dotconfig_write(filename, conf_root) < 0) {
627 printf("error saving <%s>\n", filename);
630 printf("%s saved\n", filename);
633 cmdline_parse_token_string_t cmd_save_save =
634 TOKEN_STRING_INITIALIZER(struct cmd_save_result, save, "save");
636 cmdline_parse_inst_t cmd_save = {
637 .f = cmd_save_parsed, /* function to call */
638 .data = ".config", /* 2nd arg of func */
639 .help_str = "<save> write the .config file",
640 .tokens = { /* token list, NULL terminated */
641 (void *)&cmd_save_save,
646 cmdline_parse_token_string_t cmd_save_file =
647 TOKEN_STRING_INITIALIZER(struct cmd_save_result, file, NULL);
649 cmdline_parse_inst_t cmd_savefile = {
650 .f = cmd_save_parsed, /* function to call */
651 .data = NULL, /* 2nd arg of func */
652 .help_str = "<save FILE> save in another .config file",
653 .tokens = { /* token list, NULL terminated */
654 (void *)&cmd_save_save,
655 (void *)&cmd_save_file,
660 /**********************************************************/
663 /**********************************************************/
664 /**********************************************************/
665 /****** CONTEXT (list of instruction) */
668 cmdline_parse_ctx_t main_ctx[] = {
669 (cmdline_parse_inst_t *)&cmd_ls,
670 (cmdline_parse_inst_t *)&cmd_ls_node,
671 (cmdline_parse_inst_t *)&cmd_pwd,
672 (cmdline_parse_inst_t *)&cmd_cd_prev,
673 (cmdline_parse_inst_t *)&cmd_cd_root,
674 (cmdline_parse_inst_t *)&cmd_cd_node,
675 (cmdline_parse_inst_t *)&cmd_set_bool,
676 (cmdline_parse_inst_t *)&cmd_set_int,
677 (cmdline_parse_inst_t *)&cmd_set_str,
678 (cmdline_parse_inst_t *)&cmd_show_node,
679 (cmdline_parse_inst_t *)&cmd_show_node_a,
680 (cmdline_parse_inst_t *)&cmd_load,
681 (cmdline_parse_inst_t *)&cmd_loadfile,
682 (cmdline_parse_inst_t *)&cmd_save,
683 (cmdline_parse_inst_t *)&cmd_savefile,