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_rdline.h>
47 #include "parse_confnode.h"
48 #include "expression.h"
49 #include "conf_parser.h"
51 #include "conf_htable.h"
52 #include "dotconfig.h"
54 extern struct confnode *conf_cur;
55 extern struct confnode *conf_root;
57 /**********************************************************/
59 /**********************************************************/
61 struct cmd_ls_result {
62 cmdline_fixed_string_t ls;
65 static void do_ls(const struct confnode *n)
67 const struct confnode *c;
69 TAILQ_FOREACH(c, &n->children, next) {
70 if (c->flags & CONFNODE_F_INVISIBLE)
73 confnode_display_short(c);
77 static void cmd_ls_parsed(void *parsed_result,
84 cmdline_parse_token_string_t cmd_ls_ls =
85 TOKEN_STRING_INITIALIZER(struct cmd_ls_result, ls, "ls");
87 cmdline_parse_inst_t cmd_ls = {
88 .f = cmd_ls_parsed, /* function to call */
89 .data = NULL, /* 2nd arg of func */
90 .help_str = "<ls> list all config options in current directory",
91 .tokens = { /* token list, NULL terminated */
97 /**********************************************************/
99 /**********************************************************/
101 struct cmd_ls_node_result {
102 cmdline_fixed_string_t ls;
103 struct confnode *node;
106 static void cmd_ls_node_parsed(void *parsed_result,
110 struct cmd_ls_node_result *res = parsed_result;
111 struct confnode *n = res->node;
114 confnode_display_short(n);
115 n = TAILQ_NEXT(n, user_next);
119 cmdline_parse_token_string_t cmd_ls_node_ls =
120 TOKEN_STRING_INITIALIZER(struct cmd_ls_node_result, ls, "ls");
121 parse_token_conf_node_t cmd_ls_node_node =
122 TOKEN_CONF_NODE_INITIALIZER(struct cmd_ls_node_result, node,
123 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
125 cmdline_parse_inst_t cmd_ls_node = {
126 .f = cmd_ls_node_parsed, /* function to call */
127 .data = NULL, /* 2nd arg of func */
128 .help_str = "<ls NODE> list config node(s) given in argument",
129 .tokens = { /* token list, NULL terminated */
130 (void *)&cmd_ls_node_ls,
131 (void *)&cmd_ls_node_node,
136 /**********************************************************/
138 /**********************************************************/
140 struct cmd_pwd_result {
141 cmdline_fixed_string_t pwd;
144 static void cmd_pwd_parsed(void *parsed_result,
148 conf_display_path(conf_cur);
151 cmdline_parse_token_string_t cmd_pwd_pwd =
152 TOKEN_STRING_INITIALIZER(struct cmd_pwd_result, pwd, "pwd");
154 cmdline_parse_inst_t cmd_pwd = {
155 .f = cmd_pwd_parsed, /* function to call */
156 .data = NULL, /* 2nd arg of func */
157 .help_str = "<pwd> display current directory",
158 .tokens = { /* token list, NULL terminated */
159 (void *)&cmd_pwd_pwd,
164 /**********************************************************/
166 /**********************************************************/
168 struct cmd_cd_prev_result {
169 cmdline_fixed_string_t cd;
170 cmdline_fixed_string_t prev;
173 static void cmd_cd_prev_parsed(void *parsed_result,
177 struct confnode *parent = conf_cur->parent;
178 char prompt[RDLINE_PROMPT_SIZE];
180 if (parent == NULL) {
181 printf("already at top level\n");
184 while ((parent->flags & CONFNODE_F_INVISIBLE) && parent->parent != NULL)
185 parent = parent->parent;
188 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
189 cmdline_set_prompt(cl, prompt);
192 cmdline_parse_token_string_t cmd_cd_prev_cd =
193 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, cd, "cd");
194 cmdline_parse_token_string_t cmd_cd_prev_prev =
195 TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, prev, "..");
197 cmdline_parse_inst_t cmd_cd_prev = {
198 .f = cmd_cd_prev_parsed, /* function to call */
199 .data = NULL, /* 2nd arg of func */
200 .help_str = "<cd ..> go up in configuration tree",
201 .tokens = { /* token list, NULL terminated */
202 (void *)&cmd_cd_prev_cd,
203 (void *)&cmd_cd_prev_prev,
208 /**********************************************************/
210 /**********************************************************/
212 struct cmd_cd_root_result {
213 cmdline_fixed_string_t cd;
214 cmdline_fixed_string_t root;
217 static void cmd_cd_root_parsed(void *parsed_result,
221 char prompt[RDLINE_PROMPT_SIZE];
223 conf_cur = conf_root;
224 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
225 cmdline_set_prompt(cl, prompt);
228 cmdline_parse_token_string_t cmd_cd_root_cd =
229 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, cd, "cd");
230 cmdline_parse_token_string_t cmd_cd_root_root =
231 TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, root, "/");
233 cmdline_parse_inst_t cmd_cd_root = {
234 .f = cmd_cd_root_parsed, /* function to call */
235 .data = NULL, /* 2nd arg of func */
236 .help_str = "<cd /> go to root of configuration",
237 .tokens = { /* token list, NULL terminated */
238 (void *)&cmd_cd_root_cd,
239 (void *)&cmd_cd_root_root,
244 /**********************************************************/
246 /**********************************************************/
248 struct cmd_cd_node_result {
249 cmdline_fixed_string_t cd;
250 struct confnode *node;
253 static void cmd_cd_node_parsed(void *parsed_result,
257 struct cmd_cd_node_result *res = parsed_result;
258 char prompt[RDLINE_PROMPT_SIZE];
260 if (TAILQ_NEXT(res->node, user_next)) {
261 printf("ambiguous directory\n");
264 conf_cur = res->node;
265 snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
266 cmdline_set_prompt(cl, prompt);
269 cmdline_parse_token_string_t cmd_cd_node_cd =
270 TOKEN_STRING_INITIALIZER(struct cmd_cd_node_result, cd, "cd");
271 parse_token_conf_node_t cmd_cd_node_node =
272 TOKEN_CONF_NODE_INITIALIZER(struct cmd_cd_node_result, node,
273 &conf_root, &conf_cur,
275 CONFNODE_F_IS_DIR|CONFNODE_F_INVISIBLE);
277 cmdline_parse_inst_t cmd_cd_node = {
278 .f = cmd_cd_node_parsed, /* function to call */
279 .data = NULL, /* 2nd arg of func */
280 .help_str = "<cd CONFNODE> go down in a configuration sub-tree",
281 .tokens = { /* token list, NULL terminated */
282 (void *)&cmd_cd_node_cd,
283 (void *)&cmd_cd_node_node,
288 /**********************************************************/
290 /**********************************************************/
292 struct cmd_set_bool_result {
293 cmdline_fixed_string_t set;
294 struct confnode *node;
295 cmdline_fixed_string_t val;
298 static void cmd_set_bool_parsed(void *parsed_result,
302 struct cmd_set_bool_result *res = parsed_result;
303 struct confnode *n = res->node;
307 if (confnode_set_user_strvalue(n, res->val) < 0)
308 printf("Error, cannot set value\n");
310 if (strcmp(res->val, "y") == 0)
311 confnode_check_deps(n, 1);
312 if (confnode_get_value(n, value,
314 printf("Error, cannot re-read value\n");
316 printf("<%s> value set to %s\n", n->name, value);
317 n = TAILQ_NEXT(n, user_next);
321 cmdline_parse_token_string_t cmd_set_bool_set =
322 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, set, "set");
323 parse_token_conf_node_t cmd_set_bool_node =
324 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_bool_result, node,
325 &conf_root, &conf_cur,
327 CONFNODE_F_BOOL|CONFNODE_F_INVISIBLE);
328 cmdline_parse_token_string_t cmd_set_bool_val =
329 TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, val, "y#n");
331 cmdline_parse_inst_t cmd_set_bool = {
332 .f = cmd_set_bool_parsed, /* function to call */
333 .data = NULL, /* 2nd arg of func */
334 .help_str = "<set CONFNODE y|n> set boolean value",
335 .tokens = { /* token list, NULL terminated */
336 (void *)&cmd_set_bool_set,
337 (void *)&cmd_set_bool_node,
338 (void *)&cmd_set_bool_val,
343 /**********************************************************/
345 /**********************************************************/
347 struct cmd_set_int_result {
348 cmdline_fixed_string_t set;
349 struct confnode *node;
353 static void cmd_set_int_parsed(void *parsed_result,
357 struct cmd_set_int_result *res = parsed_result;
358 struct confnode *n = res->node;
362 snprintf(value, sizeof(value), "%"PRIi32, res->val);
363 if (confnode_set_user_strvalue(n, value) < 0)
364 printf("Error, cannot set value\n");
367 confnode_check_deps(n, 1);
368 if (confnode_get_value(n, value,
370 printf("Error, cannot re-read value\n");
372 printf("<%s> value set to %s\n", n->name, value);
373 n = TAILQ_NEXT(n, user_next);
377 cmdline_parse_token_string_t cmd_set_int_set =
378 TOKEN_STRING_INITIALIZER(struct cmd_set_int_result, set, "set");
379 parse_token_conf_node_t cmd_set_int_node =
380 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_int_result, node,
381 &conf_root, &conf_cur,
383 CONFNODE_F_INT|CONFNODE_F_INVISIBLE);
384 cmdline_parse_token_num_t cmd_set_int_val =
385 TOKEN_NUM_INITIALIZER(struct cmd_set_int_result, val, INT32);
387 cmdline_parse_inst_t cmd_set_int = {
388 .f = cmd_set_int_parsed, /* function to call */
389 .data = NULL, /* 2nd arg of func */
390 .help_str = "<set CONFNODE INT> set integer value",
391 .tokens = { /* token list, NULL terminated */
392 (void *)&cmd_set_int_set,
393 (void *)&cmd_set_int_node,
394 (void *)&cmd_set_int_val,
399 /**********************************************************/
401 /**********************************************************/
403 struct cmd_set_str_result {
404 cmdline_fixed_string_t set;
405 struct confnode *node;
408 static int get_str(struct cmdline *cl, char *buf, int len)
417 rdline_init(&rl, cl->s_in, cl->s_out, NULL, NULL, NULL);
420 /* XXX use rdline() */
421 rdline_newline(&rl, "edit> ");
423 while (ret == RDLINE_RES_SUCCESS) {
424 read(cl->s_in, &c, 1);
427 ret = rdline_char_in(&rl, c);
428 if (ret == RDLINE_RES_VALIDATED) {
429 snprintf(buf, len, "%s", rdline_get_buffer(&rl));
430 s = strchr(buf, '\n');
440 static void cmd_set_str_parsed(void *parsed_result,
444 struct cmd_set_str_result *res = parsed_result;
445 struct confnode *n = res->node;
448 if (confnode_get_value(res->node, value, sizeof(value)) < 0) {
449 printf("Error, cannot read value\n");
452 printf("Previous value is %s\n", value);
453 printf("type CTRL-d on an empty line to abort\n");
454 if (get_str(cl, value, sizeof(value))) {
459 snprintf(res->node->value, sizeof(res->node->value),
461 if (strcmp(value, ""))
462 confnode_check_deps(n, 1);
463 if (confnode_get_value(n, value,
465 printf("Error, cannot re-read value\n");
466 printf("<%s> value set to %s\n", n->name, value);
467 n = TAILQ_NEXT(n, user_next);
471 cmdline_parse_token_string_t cmd_set_str_set =
472 TOKEN_STRING_INITIALIZER(struct cmd_set_str_result, set, "set");
473 parse_token_conf_node_t cmd_set_str_node =
474 TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_str_result, node,
475 &conf_root, &conf_cur,
477 CONFNODE_F_STR|CONFNODE_F_INVISIBLE);
479 cmdline_parse_inst_t cmd_set_str = {
480 .f = cmd_set_str_parsed, /* function to call */
481 .data = NULL, /* 2nd arg of func */
482 .help_str = "<set CONFNODE> set str value",
483 .tokens = { /* token list, NULL terminated */
484 (void *)&cmd_set_str_set,
485 (void *)&cmd_set_str_node,
490 /**********************************************************/
492 /**********************************************************/
494 struct cmd_show_node_result {
495 cmdline_fixed_string_t show;
496 cmdline_fixed_string_t all;
497 struct confnode *node;
500 static void cmd_show_node_parsed(void *parsed_result,
504 struct cmd_show_node_result *res = parsed_result;
505 struct confnode *n = res->node;
512 confnode_display_long(n);
513 n = TAILQ_NEXT(n, user_next);
517 cmdline_parse_token_string_t cmd_show_node_show =
518 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, show, "show");
519 cmdline_parse_token_string_t cmd_show_node_all =
520 TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, all, "-a");
521 parse_token_conf_node_t cmd_show_node_node =
522 TOKEN_CONF_NODE_INITIALIZER(struct cmd_show_node_result, node,
523 &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
525 cmdline_parse_inst_t cmd_show_node = {
526 .f = cmd_show_node_parsed, /* function to call */
527 .data = NULL, /* 2nd arg of func */
528 .help_str = "<show CONFNODE> display infos on the config option",
529 .tokens = { /* token list, NULL terminated */
530 (void *)&cmd_show_node_show,
531 (void *)&cmd_show_node_node,
536 cmdline_parse_inst_t cmd_show_node_a = {
537 .f = cmd_show_node_parsed, /* function to call */
538 .data = (void *)1, /* 2nd arg of func */
539 .help_str = "<show -a CONFNODE> display detailed infos on the config option",
540 .tokens = { /* token list, NULL terminated */
541 (void *)&cmd_show_node_show,
542 (void *)&cmd_show_node_all,
543 (void *)&cmd_show_node_node,
548 /**********************************************************/
549 /* load / load file */
550 /**********************************************************/
552 struct cmd_load_result {
553 cmdline_fixed_string_t load;
554 cmdline_fixed_string_t file;
557 static void cmd_load_parsed(void *parsed_result,
561 char prompt[RDLINE_PROMPT_SIZE];
562 struct cmd_load_result *res = parsed_result;
563 const char *filename;
568 filename = res->file;
570 conf_cur = conf_reset_and_read(conf_root, filename);
571 if (conf_root == NULL) {
572 printf("error loading <%s>\n", filename);
575 conf_cur = conf_root;
576 snprintf(prompt, sizeof(prompt), "root> ");
578 printf("%s loaded\n", filename);
581 cmdline_parse_token_string_t cmd_load_load =
582 TOKEN_STRING_INITIALIZER(struct cmd_load_result, load, "load");
584 cmdline_parse_inst_t cmd_load = {
585 .f = cmd_load_parsed, /* function to call */
586 .data = ".config", /* 2nd arg of func */
587 .help_str = "<load> reload the .config file",
588 .tokens = { /* token list, NULL terminated */
589 (void *)&cmd_load_load,
594 cmdline_parse_token_string_t cmd_load_file =
595 TOKEN_STRING_INITIALIZER(struct cmd_load_result, file, NULL);
597 cmdline_parse_inst_t cmd_loadfile = {
598 .f = cmd_load_parsed, /* function to call */
599 .data = NULL, /* 2nd arg of func */
600 .help_str = "<load FILE> load another .config file",
601 .tokens = { /* token list, NULL terminated */
602 (void *)&cmd_load_load,
603 (void *)&cmd_load_file,
608 /**********************************************************/
609 /* save / save file */
610 /**********************************************************/
612 struct cmd_save_result {
613 cmdline_fixed_string_t save;
614 cmdline_fixed_string_t file;
617 static void cmd_save_parsed(void *parsed_result,
621 struct cmd_save_result *res = parsed_result;
622 const char *filename;
627 filename = res->file;
629 if (dotconfig_write(filename, conf_root) < 0) {
630 printf("error saving <%s>\n", filename);
633 printf("%s saved\n", filename);
636 cmdline_parse_token_string_t cmd_save_save =
637 TOKEN_STRING_INITIALIZER(struct cmd_save_result, save, "save");
639 cmdline_parse_inst_t cmd_save = {
640 .f = cmd_save_parsed, /* function to call */
641 .data = ".config", /* 2nd arg of func */
642 .help_str = "<save> write the .config file",
643 .tokens = { /* token list, NULL terminated */
644 (void *)&cmd_save_save,
649 cmdline_parse_token_string_t cmd_save_file =
650 TOKEN_STRING_INITIALIZER(struct cmd_save_result, file, NULL);
652 cmdline_parse_inst_t cmd_savefile = {
653 .f = cmd_save_parsed, /* function to call */
654 .data = NULL, /* 2nd arg of func */
655 .help_str = "<save FILE> save in another .config file",
656 .tokens = { /* token list, NULL terminated */
657 (void *)&cmd_save_save,
658 (void *)&cmd_save_file,
663 /**********************************************************/
666 /**********************************************************/
667 /**********************************************************/
668 /****** CONTEXT (list of instruction) */
671 cmdline_parse_ctx_t main_ctx = {