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.
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <sys/queue.h>
40 #include <cmdline_parse.h>
41 #include <cmdline_parse_ipaddr.h>
42 #include <cmdline_parse_num.h>
43 #include <cmdline_parse_string.h>
44 #include <cmdline_parse_file.h>
45 #include <cmdline_rdline.h>
48 #include "parse_confnode.h"
49 #include "expression.h"
50 #include "conf_parser.h"
52 #include "conf_htable.h"
53 #include "dotconfig.h"
55 extern struct confnode *conf_cur;
56 extern struct confnode *conf_root;
58 /**********************************************************/
60 /**********************************************************/
62 struct cmd_ls_result {
63 cmdline_fixed_string_t ls;
66 static void do_ls(const struct confnode *n)
68 const struct confnode *c;
70 TAILQ_FOREACH(c, &n->children, next) {
71 if (c->flags & CONFNODE_F_INVISIBLE)
74 confnode_display_short(c);
78 static void cmd_ls_parsed(void *parsed_result,
85 cmdline_parse_token_string_t cmd_ls_ls =
86 TOKEN_STRING_INITIALIZER(struct cmd_ls_result, ls, "ls");
88 cmdline_parse_inst_t cmd_ls = {
89 .f = cmd_ls_parsed, /* function to call */
90 .data = NULL, /* 2nd arg of func */
91 .help_str = "<ls> list all config options in current directory",
92 .tokens = { /* token list, NULL terminated */
98 /**********************************************************/
100 /**********************************************************/
102 struct cmd_ls_node_result {
103 cmdline_fixed_string_t ls;
104 struct confnode *node;
107 static void cmd_ls_node_parsed(void *parsed_result,
111 struct cmd_ls_node_result *res = parsed_result;
112 struct confnode *n = res->node;
115 confnode_display_short(n);
116 n = TAILQ_NEXT(n, user_next);
120 cmdline_parse_token_string_t cmd_ls_node_ls =
121 TOKEN_STRING_INITIALIZER(struct cmd_ls_node_result, ls, "ls");
122 parse_token_conf_node_t cmd_ls_node_node =
123 TOKEN_CONF_NODE_INITIALIZER(struct cmd_ls_node_result, node,
124 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
126 cmdline_parse_inst_t cmd_ls_node = {
127 .f = cmd_ls_node_parsed, /* function to call */
128 .data = NULL, /* 2nd arg of func */
129 .help_str = "<ls NODE> list config node(s) given in argument",
130 .tokens = { /* token list, NULL terminated */
131 (void *)&cmd_ls_node_ls,
132 (void *)&cmd_ls_node_node,
137 /**********************************************************/
139 /**********************************************************/
141 struct cmd_pwd_result {
142 cmdline_fixed_string_t pwd;
145 static void cmd_pwd_parsed(void *parsed_result,
149 conf_display_path(conf_cur);
152 cmdline_parse_token_string_t cmd_pwd_pwd =
153 TOKEN_STRING_INITIALIZER(struct cmd_pwd_result, pwd, "pwd");
155 cmdline_parse_inst_t cmd_pwd = {
156 .f = cmd_pwd_parsed, /* function to call */
157 .data = NULL, /* 2nd arg of func */
158 .help_str = "<pwd> display current directory",
159 .tokens = { /* token list, NULL terminated */
160 (void *)&cmd_pwd_pwd,
165 /**********************************************************/
167 /**********************************************************/
169 struct cmd_cd_prev_result {
170 cmdline_fixed_string_t cd;
171 cmdline_fixed_string_t prev;
174 static void cmd_cd_prev_parsed(void *parsed_result,
178 struct confnode *parent = conf_cur->parent;
179 char prompt[RDLINE_PROMPT_SIZE];
181 if (parent == NULL) {
182 printf("already at top level\n");
185 while ((parent->flags & CONFNODE_F_INVISIBLE) && parent->parent != NULL)
186 parent = parent->parent;
189 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
190 cmdline_set_prompt(cl, prompt);
193 cmdline_parse_token_string_t cmd_cd_prev_cd =
194 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, cd, "cd");
195 cmdline_parse_token_string_t cmd_cd_prev_prev =
196 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, prev, "..");
198 cmdline_parse_inst_t cmd_cd_prev = {
199 .f = cmd_cd_prev_parsed, /* function to call */
200 .data = NULL, /* 2nd arg of func */
201 .help_str = "<cd ..> go up in configuration tree",
202 .tokens = { /* token list, NULL terminated */
203 (void *)&cmd_cd_prev_cd,
204 (void *)&cmd_cd_prev_prev,
209 /**********************************************************/
211 /**********************************************************/
213 struct cmd_cd_root_result {
214 cmdline_fixed_string_t cd;
215 cmdline_fixed_string_t root;
218 static void cmd_cd_root_parsed(void *parsed_result,
222 char prompt[RDLINE_PROMPT_SIZE];
224 conf_cur = conf_root;
225 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
226 cmdline_set_prompt(cl, prompt);
229 cmdline_parse_token_string_t cmd_cd_root_cd =
230 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, cd, "cd");
231 cmdline_parse_token_string_t cmd_cd_root_root =
232 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, root, "/");
234 cmdline_parse_inst_t cmd_cd_root = {
235 .f = cmd_cd_root_parsed, /* function to call */
236 .data = NULL, /* 2nd arg of func */
237 .help_str = "<cd /> go to root of configuration",
238 .tokens = { /* token list, NULL terminated */
239 (void *)&cmd_cd_root_cd,
240 (void *)&cmd_cd_root_root,
245 /**********************************************************/
247 /**********************************************************/
249 struct cmd_cd_node_result {
250 cmdline_fixed_string_t cd;
251 struct confnode *node;
254 static void cmd_cd_node_parsed(void *parsed_result,
258 struct cmd_cd_node_result *res = parsed_result;
259 char prompt[RDLINE_PROMPT_SIZE];
261 if (TAILQ_NEXT(res->node, user_next)) {
262 printf("ambiguous directory\n");
265 conf_cur = res->node;
266 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
267 cmdline_set_prompt(cl, prompt);
270 cmdline_parse_token_string_t cmd_cd_node_cd =
271 TOKEN_STRING_INITIALIZER(struct cmd_cd_node_result, cd, "cd");
272 parse_token_conf_node_t cmd_cd_node_node =
273 TOKEN_CONF_NODE_INITIALIZER(struct cmd_cd_node_result, node,
274 &conf_root, &conf_cur,
276 CONFNODE_F_IS_DIR|CONFNODE_F_INVISIBLE);
278 cmdline_parse_inst_t cmd_cd_node = {
279 .f = cmd_cd_node_parsed, /* function to call */
280 .data = NULL, /* 2nd arg of func */
281 .help_str = "<cd CONFNODE> go down in a configuration sub-tree",
282 .tokens = { /* token list, NULL terminated */
283 (void *)&cmd_cd_node_cd,
284 (void *)&cmd_cd_node_node,
289 /**********************************************************/
291 /**********************************************************/
293 struct cmd_set_bool_result {
294 cmdline_fixed_string_t set;
295 struct confnode *node;
296 cmdline_fixed_string_t val;
299 static void cmd_set_bool_parsed(void *parsed_result,
303 struct cmd_set_bool_result *res = parsed_result;
304 struct confnode *n = res->node;
308 if (confnode_set_user_strvalue(n, res->val) < 0)
309 printf("Error, cannot set value\n");
311 if (strcmp(res->val, "y") == 0)
312 confnode_check_deps(n, 1);
313 if (confnode_get_value(n, value,
315 printf("Error, cannot re-read value\n");
317 printf("<%s> value set to %s\n", n->name, value);
318 n = TAILQ_NEXT(n, user_next);
322 cmdline_parse_token_string_t cmd_set_bool_set =
323 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, set, "set");
324 parse_token_conf_node_t cmd_set_bool_node =
325 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_bool_result, node,
326 &conf_root, &conf_cur,
328 CONFNODE_F_BOOL|CONFNODE_F_INVISIBLE);
329 cmdline_parse_token_string_t cmd_set_bool_val =
330 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, val, "y#n");
332 cmdline_parse_inst_t cmd_set_bool = {
333 .f = cmd_set_bool_parsed, /* function to call */
334 .data = NULL, /* 2nd arg of func */
335 .help_str = "<set CONFNODE y|n> set boolean value",
336 .tokens = { /* token list, NULL terminated */
337 (void *)&cmd_set_bool_set,
338 (void *)&cmd_set_bool_node,
339 (void *)&cmd_set_bool_val,
344 /**********************************************************/
346 /**********************************************************/
348 struct cmd_set_int_result {
349 cmdline_fixed_string_t set;
350 struct confnode *node;
354 static void cmd_set_int_parsed(void *parsed_result,
358 struct cmd_set_int_result *res = parsed_result;
359 struct confnode *n = res->node;
363 snprintf(value, sizeof(value), "%"PRIi32, res->val);
364 if (confnode_set_user_strvalue(n, value) < 0)
365 printf("Error, cannot set value\n");
368 confnode_check_deps(n, 1);
369 if (confnode_get_value(n, value,
371 printf("Error, cannot re-read value\n");
373 printf("<%s> value set to %s\n", n->name, value);
374 n = TAILQ_NEXT(n, user_next);
378 cmdline_parse_token_string_t cmd_set_int_set =
379 TOKEN_STRING_INITIALIZER(struct cmd_set_int_result, set, "set");
380 parse_token_conf_node_t cmd_set_int_node =
381 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_int_result, node,
382 &conf_root, &conf_cur,
384 CONFNODE_F_INT|CONFNODE_F_INVISIBLE);
385 cmdline_parse_token_num_t cmd_set_int_val =
386 TOKEN_NUM_INITIALIZER(struct cmd_set_int_result, val, INT32);
388 cmdline_parse_inst_t cmd_set_int = {
389 .f = cmd_set_int_parsed, /* function to call */
390 .data = NULL, /* 2nd arg of func */
391 .help_str = "<set CONFNODE INT> set integer value",
392 .tokens = { /* token list, NULL terminated */
393 (void *)&cmd_set_int_set,
394 (void *)&cmd_set_int_node,
395 (void *)&cmd_set_int_val,
400 /**********************************************************/
402 /**********************************************************/
404 struct cmd_set_str_result {
405 cmdline_fixed_string_t set;
406 struct confnode *node;
409 static int get_str(struct cmdline *cl, char *buf, int len)
418 rdline_init(&rl, cl->s_in, cl->s_out, NULL, NULL, NULL);
421 /* XXX use rdline() */
422 rdline_newline(&rl, "edit> ");
424 while (ret == RDLINE_RES_SUCCESS) {
425 read(cl->s_in, &c, 1);
428 ret = rdline_char_in(&rl, c);
429 if (ret == RDLINE_RES_VALIDATED) {
430 snprintf(buf, len, "%s", rdline_get_buffer(&rl));
431 s = strchr(buf, '\n');
441 static void cmd_set_str_parsed(void *parsed_result,
445 struct cmd_set_str_result *res = parsed_result;
446 struct confnode *n = res->node;
449 if (confnode_get_value(res->node, value, sizeof(value)) < 0) {
450 printf("Error, cannot read value\n");
453 printf("Previous value is %s\n", value);
454 printf("type CTRL-d on an empty line to abort\n");
455 if (get_str(cl, value, sizeof(value))) {
460 snprintf(res->node->value, sizeof(res->node->value),
462 if (strcmp(value, ""))
463 confnode_check_deps(n, 1);
464 if (confnode_get_value(n, value,
466 printf("Error, cannot re-read value\n");
467 printf("<%s> value set to %s\n", n->name, value);
468 n = TAILQ_NEXT(n, user_next);
472 cmdline_parse_token_string_t cmd_set_str_set =
473 TOKEN_STRING_INITIALIZER(struct cmd_set_str_result, set, "set");
474 parse_token_conf_node_t cmd_set_str_node =
475 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_str_result, node,
476 &conf_root, &conf_cur,
478 CONFNODE_F_STR|CONFNODE_F_INVISIBLE);
480 cmdline_parse_inst_t cmd_set_str = {
481 .f = cmd_set_str_parsed, /* function to call */
482 .data = NULL, /* 2nd arg of func */
483 .help_str = "<set CONFNODE> set str value",
484 .tokens = { /* token list, NULL terminated */
485 (void *)&cmd_set_str_set,
486 (void *)&cmd_set_str_node,
491 /**********************************************************/
493 /**********************************************************/
495 struct cmd_show_node_result {
496 cmdline_fixed_string_t show;
497 cmdline_fixed_string_t all;
498 struct confnode *node;
501 static void cmd_show_node_parsed(void *parsed_result,
505 struct cmd_show_node_result *res = parsed_result;
506 struct confnode *n = res->node;
513 confnode_display_long(n);
514 n = TAILQ_NEXT(n, user_next);
518 cmdline_parse_token_string_t cmd_show_node_show =
519 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, show, "show");
520 cmdline_parse_token_string_t cmd_show_node_all =
521 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, all, "-a");
522 parse_token_conf_node_t cmd_show_node_node =
523 TOKEN_CONF_NODE_INITIALIZER(struct cmd_show_node_result, node,
524 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
526 cmdline_parse_inst_t cmd_show_node = {
527 .f = cmd_show_node_parsed, /* function to call */
528 .data = NULL, /* 2nd arg of func */
529 .help_str = "<show CONFNODE> display infos on the config option",
530 .tokens = { /* token list, NULL terminated */
531 (void *)&cmd_show_node_show,
532 (void *)&cmd_show_node_node,
537 cmdline_parse_inst_t cmd_show_node_a = {
538 .f = cmd_show_node_parsed, /* function to call */
539 .data = (void *)1, /* 2nd arg of func */
540 .help_str = "<show -a CONFNODE> display detailed infos on the config option",
541 .tokens = { /* token list, NULL terminated */
542 (void *)&cmd_show_node_show,
543 (void *)&cmd_show_node_all,
544 (void *)&cmd_show_node_node,
549 /**********************************************************/
550 /* load / load file */
551 /**********************************************************/
553 struct cmd_load_result {
554 cmdline_filename_t load;
555 cmdline_fixed_string_t file;
558 static void cmd_load_parsed(void *parsed_result,
562 char prompt[RDLINE_PROMPT_SIZE];
563 struct cmd_load_result *res = parsed_result;
564 const char *filename;
569 filename = res->file;
571 conf_cur = conf_reset_and_read(conf_root, filename);
572 if (conf_root == NULL) {
573 printf("error loading <%s>\n", filename);
576 conf_cur = conf_root;
577 snprintf(prompt, sizeof(prompt), "root> ");
579 printf("%s loaded\n", filename);
582 cmdline_parse_token_string_t cmd_load_load =
583 TOKEN_STRING_INITIALIZER(struct cmd_load_result, load, "load");
585 cmdline_parse_inst_t cmd_load = {
586 .f = cmd_load_parsed, /* function to call */
587 .data = ".config", /* 2nd arg of func */
588 .help_str = "<load> reload the .config file",
589 .tokens = { /* token list, NULL terminated */
590 (void *)&cmd_load_load,
595 cmdline_parse_token_file_t cmd_load_file =
596 TOKEN_FILE_INITIALIZER(struct cmd_load_result, file, 0);
598 cmdline_parse_inst_t cmd_loadfile = {
599 .f = cmd_load_parsed, /* function to call */
600 .data = NULL, /* 2nd arg of func */
601 .help_str = "<load FILE> load another .config file",
602 .tokens = { /* token list, NULL terminated */
603 (void *)&cmd_load_load,
604 (void *)&cmd_load_file,
609 /**********************************************************/
610 /* save / save file */
611 /**********************************************************/
613 struct cmd_save_result {
614 cmdline_fixed_string_t save;
615 cmdline_filename_t file;
618 static void cmd_save_parsed(void *parsed_result,
622 struct cmd_save_result *res = parsed_result;
623 const char *filename;
628 filename = res->file;
630 if (dotconfig_write(filename, conf_root) < 0) {
631 printf("error saving <%s>\n", filename);
634 printf("%s saved\n", filename);
637 cmdline_parse_token_string_t cmd_save_save =
638 TOKEN_STRING_INITIALIZER(struct cmd_save_result, save, "save");
640 cmdline_parse_inst_t cmd_save = {
641 .f = cmd_save_parsed, /* function to call */
642 .data = ".config", /* 2nd arg of func */
643 .help_str = "<save> write the .config file",
644 .tokens = { /* token list, NULL terminated */
645 (void *)&cmd_save_save,
650 cmdline_parse_token_file_t cmd_save_file =
651 TOKEN_FILE_INITIALIZER(struct cmd_save_result, file,
652 PARSE_FILE_F_CREATE);
654 cmdline_parse_inst_t cmd_savefile = {
655 .f = cmd_save_parsed, /* function to call */
656 .data = NULL, /* 2nd arg of func */
657 .help_str = "<save FILE> save in another .config file",
658 .tokens = { /* token list, NULL terminated */
659 (void *)&cmd_save_save,
660 (void *)&cmd_save_file,
665 /**********************************************************/
668 /**********************************************************/
669 /**********************************************************/
670 /****** CONTEXT (list of instruction) */
673 cmdline_parse_ctx_t main_ctx = {