2 * augrun.c: command interpreter for augeas
4 * Copyright (C) 2011-2016 David Lutterkort
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Author: David Lutterkort <lutter@redhat.com>
30 #include <libxml/tree.h>
34 * Command handling infrastructure
36 enum command_opt_type {
38 CMD_STR, /* String argument */
39 CMD_PATH /* Path expression */
42 struct command_opt_def {
43 bool optional; /* Optional or mandatory */
44 enum command_opt_type type;
49 #define CMD_OPT_DEF_LAST { .type = CMD_NONE, .name = NULL }
52 const struct command_def *def;
53 struct command_opt *opt;
55 struct error *error; /* Same as aug->error */
60 typedef void (*cmd_handler)(struct command*);
65 const struct command_opt_def *opts;
71 static const struct command_def cmd_def_last =
72 { .name = NULL, .opts = NULL, .handler = NULL,
73 .synopsis = NULL, .help = NULL };
76 struct command_opt *next;
77 const struct command_opt_def *def;
81 struct command_grp_def {
83 const struct command_def *commands[];
86 static const struct command_grp_def cmd_grp_def_last =
87 { .name = NULL, .commands = { } };
89 static const struct command_def *lookup_cmd_def(const char *name);
91 static const struct command_opt_def *
92 find_def(const struct command *cmd, const char *name) {
93 const struct command_opt_def *def;
94 for (def = cmd->def->opts; def->name != NULL; def++) {
95 if (STREQ(def->name, name))
101 static struct command_opt *
102 find_opt(const struct command *cmd, const char *name) {
103 const struct command_opt_def *def = find_def(cmd, name);
106 for (struct command_opt *opt = cmd->opt; opt != NULL; opt = opt->next) {
110 assert(def->optional);
114 static const char *arg_value(const struct command *cmd, const char *name) {
115 struct command_opt *opt = find_opt(cmd, name);
117 return (opt == NULL) ? NULL : opt->value;
120 static char *nexttoken(struct command *cmd, char **line, bool path) {
129 while (*s && isblank(*s)) s+= 1;
137 case ']': /* pass both literally */
140 case 't': /* insert tab */
145 case 'n': /* insert newline */
151 case '\t': /* pass both through if quoted, else fall */
153 ATTRIBUTE_FALLTHROUGH;
155 case '"': /* pass both through if opposite quote, else fall */
156 if (quot && quot != *(s+1)) break;
157 ATTRIBUTE_FALLTHROUGH;
158 case '\\': /* pass next character through */
163 ERR_REPORT(cmd, AUG_ECMDRUN, "unknown escape sequence");
169 if (*s == '[') nbracket += 1;
170 if (*s == ']') nbracket -= 1;
172 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
176 if (!path || nbracket == 0) {
177 if (!quot && (*s == '\'' || *s == '"')) {
180 } else if (quot && *s == quot) {
185 if (!quot && isblank(*s))
198 if (*s == '\0' && path && nbracket > 0) {
199 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
202 if (*s == '\0' && quot) {
203 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched %c", quot);
212 static struct command_opt *
213 make_command_opt(struct command *cmd, const struct command_opt_def *def) {
214 struct command_opt *copt = NULL;
218 ERR_NOMEM(r < 0, cmd->aug);
220 list_append(cmd->opt, copt);
225 static void free_command_opts(struct command *cmd) {
226 struct command_opt *next;
229 while (next != NULL) {
230 struct command_opt *del = next;
237 static int parseline(struct command *cmd, char *line) {
239 int narg = 0, nopt = 0;
240 const struct command_opt_def *def;
242 tok = nexttoken(cmd, &line, false);
245 cmd->def = lookup_cmd_def(tok);
246 if (cmd->def == NULL) {
247 ERR_REPORT(cmd, AUG_ECMDRUN, "Unknown command '%s'", tok);
251 for (def = cmd->def->opts; def->name != NULL; def++) {
258 def = cmd->def->opts;
259 while (*line != '\0') {
260 while (*line && isblank(*line)) line += 1;
262 if (curarg >= narg) {
263 ERR_REPORT(cmd, AUG_ECMDRUN,
264 "Too many arguments. Command %s takes only %d arguments",
265 cmd->def->name, narg);
269 struct command_opt *opt = make_command_opt(cmd, def);
273 if (def->type == CMD_PATH) {
274 tok = nexttoken(cmd, &line, true);
277 tok = nexttoken(cmd, &line, false);
284 while (*line && isblank(*line)) line += 1;
287 if (curarg < narg - nopt) {
288 ERR_REPORT(cmd, AUG_ECMDRUN, "Not enough arguments for %s", cmd->def->name);
298 static void format_desc(const char *d) {
300 for (const char *s = d; *s; s++) {
309 static void format_defname(char *buf, const struct command_opt_def *def,
310 bool mark_optional) {
312 if (mark_optional && def->optional)
313 p = stpcpy(buf, " [<");
315 p = stpcpy(buf, " <");
316 for (int i=0; i < strlen(def->name); i++)
317 *p++ = toupper(def->name[i]);
319 if (mark_optional && def->optional)
324 static void cmd_help(struct command *cmd);
326 static const struct command_opt_def cmd_help_opts[] = {
327 { .type = CMD_STR, .name = "command", .optional = true,
328 .help = "print help for this command only" },
332 static const struct command_def cmd_help_def = {
334 .opts = cmd_help_opts,
336 .synopsis = "print help",
337 .help = "list all commands or print details about one command"
340 static void cmd_quit(ATTRIBUTE_UNUSED struct command *cmd) {
344 static const struct command_opt_def cmd_quit_opts[] = {
348 static const struct command_def cmd_quit_def = {
350 .opts = cmd_quit_opts,
352 .synopsis = "exit the program",
353 .help = "Exit the program"
356 static char *ls_pattern(struct command *cmd, const char *path) {
360 if (path[strlen(path)-1] == SEP)
361 r = xasprintf(&q, "%s*", path);
363 r = xasprintf(&q, "%s/*", path);
364 ERR_NOMEM(r < 0, cmd->aug);
369 static int child_count(struct command *cmd, const char *path) {
370 char *q = ls_pattern(cmd, path);
375 cnt = aug_match(cmd->aug, q, NULL);
382 static void cmd_ls(struct command *cmd) {
387 path = ls_pattern(cmd, arg_value(cmd, "path"));
390 cnt = aug_match(cmd->aug, path, &paths);
392 for (int i=0; i < cnt; i++) {
394 const char *basnam = strrchr(paths[i], SEP);
395 int dir = child_count(cmd, paths[i]);
396 aug_get(cmd->aug, paths[i], &val);
398 basnam = (basnam == NULL) ? paths[i] : basnam + 1;
401 fprintf(cmd->out, "%s%s= %s\n", basnam, dir ? "/ " : " ", val);
406 for (int i=0; i < cnt; i++)
411 static const struct command_opt_def cmd_ls_opts[] = {
412 { .type = CMD_PATH, .name = "path", .optional = false,
413 .help = "the node whose children to list" },
417 static const struct command_def cmd_ls_def = {
421 .synopsis = "list children of a node",
422 .help = "list the direct children of a node"
425 static void cmd_match(struct command *cmd) {
427 const char *pattern = arg_value(cmd, "path");
428 const char *value = arg_value(cmd, "value");
429 char **matches = NULL;
430 bool filter = (value != NULL) && (strlen(value) > 0);
432 cnt = aug_match(cmd->aug, pattern, &matches);
434 ERR_THROW(cnt < 0, cmd->aug, AUG_ECMDRUN,
435 " (error matching %s)\n", pattern);
437 fprintf(cmd->out, " (no matches)\n");
441 for (int i=0; i < cnt; i++) {
443 aug_get(cmd->aug, matches[i], &val);
448 if (STREQ(value, val))
449 fprintf(cmd->out, "%s\n", matches[i]);
451 fprintf(cmd->out, "%s = %s\n", matches[i], val);
456 for (int i=0; i < cnt; i++)
461 static const struct command_opt_def cmd_match_opts[] = {
462 { .type = CMD_PATH, .name = "path", .optional = false,
463 .help = "the path expression to match" },
464 { .type = CMD_STR, .name = "value", .optional = true,
465 .help = "only show matches with this value" },
469 static const struct command_def cmd_match_def = {
471 .opts = cmd_match_opts,
472 .handler = cmd_match,
473 .synopsis = "print matches for a path expression",
474 .help = "Find all paths that match the path expression PATH. "
475 "If VALUE is given,\n only the matching paths whose value equals "
479 static void cmd_rm(struct command *cmd) {
481 const char *path = arg_value(cmd, "path");
482 cnt = aug_rm(cmd->aug, path);
484 fprintf(cmd->out, "rm : %s %d\n", path, cnt);
487 static const struct command_opt_def cmd_rm_opts[] = {
488 { .type = CMD_PATH, .name = "path", .optional = false,
489 .help = "remove all nodes matching this path expression" },
493 static const struct command_def cmd_rm_def = {
497 .synopsis = "delete nodes and subtrees",
498 .help = "Delete PATH and all its children from the tree"
501 static void cmd_mv(struct command *cmd) {
502 const char *src = arg_value(cmd, "src");
503 const char *dst = arg_value(cmd, "dst");
506 r = aug_mv(cmd->aug, src, dst);
508 ERR_REPORT(cmd, AUG_ECMDRUN,
509 "Moving %s to %s failed", src, dst);
512 static const struct command_opt_def cmd_mv_opts[] = {
513 { .type = CMD_PATH, .name = "src", .optional = false,
514 .help = "the tree to move" },
515 { .type = CMD_PATH, .name = "dst", .optional = false,
516 .help = "where to put the source tree" },
520 static const char cmd_mv_help[] =
521 "Move node SRC to DST. SRC must match exactly one node in "
522 "the tree.\n DST must either match exactly one node in the tree, "
523 "or may not\n exist yet. If DST exists already, it and all its "
524 "descendants are\n deleted. If DST does not exist yet, it and "
525 "all its missing\n ancestors are created.";
527 static const struct command_def cmd_mv_def = {
531 .synopsis = "move a subtree",
535 static const struct command_def cmd_move_def = {
539 .synopsis = "move a subtree (alias of 'mv')",
543 static void cmd_cp(struct command *cmd) {
544 const char *src = arg_value(cmd, "src");
545 const char *dst = arg_value(cmd, "dst");
548 r = aug_cp(cmd->aug, src, dst);
550 ERR_REPORT(cmd, AUG_ECMDRUN,
551 "Copying %s to %s failed", src, dst);
554 static const struct command_opt_def cmd_cp_opts[] = {
555 { .type = CMD_PATH, .name = "src", .optional = false,
556 .help = "the tree to copy" },
557 { .type = CMD_PATH, .name = "dst", .optional = false,
558 .help = "where to copy the source tree" },
562 static const char cmd_cp_help[] =
563 "Copy node SRC to DST. SRC must match exactly one node in "
564 "the tree.\n DST must either match exactly one node in the tree, "
565 "or may not\n exist yet. If DST exists already, it and all its "
566 "descendants are\n deleted. If DST does not exist yet, it and "
567 "all its missing\n ancestors are created.";
569 static const struct command_def cmd_cp_def = {
573 .synopsis = "copy a subtree",
577 static const struct command_def cmd_copy_def = {
581 .synopsis = "copy a subtree (alias of 'cp')",
585 static void cmd_rename(struct command *cmd) {
586 const char *src = arg_value(cmd, "src");
587 const char *lbl = arg_value(cmd, "lbl");
590 cnt = aug_rename(cmd->aug, src, lbl);
592 ERR_REPORT(cmd, AUG_ECMDRUN,
593 "Renaming %s to %s failed", src, lbl);
595 fprintf(cmd->out, "rename : %s to %s %d\n", src, lbl, cnt);
598 static const struct command_opt_def cmd_rename_opts[] = {
599 { .type = CMD_PATH, .name = "src", .optional = false,
600 .help = "the tree to rename" },
601 { .type = CMD_STR, .name = "lbl", .optional = false,
602 .help = "the new label" },
606 static const char cmd_rename_help[] =
607 "Rename the label of all nodes matching SRC to LBL.";
609 static const struct command_def cmd_rename_def = {
611 .opts = cmd_rename_opts,
612 .handler = cmd_rename,
613 .synopsis = "rename a subtree label",
614 .help = cmd_rename_help
617 static void cmd_set(struct command *cmd) {
618 const char *path = arg_value(cmd, "path");
619 const char *val = arg_value(cmd, "value");
622 r = aug_set(cmd->aug, path, val);
624 ERR_REPORT(cmd, AUG_ECMDRUN, "Setting %s failed", path);
627 static const struct command_opt_def cmd_set_opts[] = {
628 { .type = CMD_PATH, .name = "path", .optional = false,
629 .help = "set the value of this node" },
630 { .type = CMD_STR, .name = "value", .optional = true,
631 .help = "the new value for the node" },
635 static const struct command_def cmd_set_def = {
637 .opts = cmd_set_opts,
639 .synopsis = "set the value of a node",
640 .help = "Associate VALUE with PATH. If PATH is not in the tree yet, "
641 "it and all\n its ancestors will be created. These new tree entries "
642 "will appear last\n amongst their siblings"
645 static void cmd_setm(struct command *cmd) {
646 const char *base = arg_value(cmd, "base");
647 const char *sub = arg_value(cmd, "sub");
648 const char *val = arg_value(cmd, "value");
650 aug_setm(cmd->aug, base, sub, val);
653 static const struct command_opt_def cmd_setm_opts[] = {
654 { .type = CMD_PATH, .name = "base", .optional = false,
655 .help = "the base node" },
656 { .type = CMD_PATH, .name = "sub", .optional = false,
657 .help = "the subtree relative to the base" },
658 { .type = CMD_STR, .name = "value", .optional = true,
659 .help = "the value for the nodes" },
663 static const struct command_def cmd_setm_def = {
665 .opts = cmd_setm_opts,
667 .synopsis = "set the value of multiple nodes",
668 .help = "Set multiple nodes in one operation. Find or create a node"
669 " matching SUB\n by interpreting SUB as a path expression relative"
670 " to each node matching\n BASE. If SUB is '.', the nodes matching "
671 "BASE will be modified."
674 static void cmd_clearm(struct command *cmd) {
675 const char *base = arg_value(cmd, "base");
676 const char *sub = arg_value(cmd, "sub");
678 aug_setm(cmd->aug, base, sub, NULL);
681 static const struct command_opt_def cmd_clearm_opts[] = {
682 { .type = CMD_PATH, .name = "base", .optional = false,
683 .help = "the base node" },
684 { .type = CMD_PATH, .name = "sub", .optional = false,
685 .help = "the subtree relative to the base" },
689 static const struct command_def cmd_clearm_def = {
691 .opts = cmd_clearm_opts,
692 .handler = cmd_clearm,
693 .synopsis = "clear the value of multiple nodes",
694 .help = "Clear multiple nodes values in one operation. Find or create a"
695 " node matching SUB\n by interpreting SUB as a path expression relative"
696 " to each node matching\n BASE. If SUB is '.', the nodes matching "
697 "BASE will be modified."
700 static void cmd_span(struct command *cmd) {
701 const char *path = arg_value(cmd, "path");
703 uint label_start, label_end, value_start, value_end, span_start, span_end;
704 char *filename = NULL;
705 const char *option = NULL;
707 if (aug_get(cmd->aug, AUGEAS_SPAN_OPTION, &option) != 1) {
708 printf("Error: option " AUGEAS_SPAN_OPTION " not found\n");
711 if (streqv(AUG_DISABLE, option)) {
712 ERR_REPORT(cmd, AUG_ECMDRUN,
713 "Span is not enabled. To enable, run the commands:\n"
714 " set %s %s\n rm %s\n load\n",
715 AUGEAS_SPAN_OPTION, AUG_ENABLE, AUGEAS_FILES_TREE);
717 } else if (! streqv(AUG_ENABLE, option)) {
718 ERR_REPORT(cmd, AUG_ECMDRUN,
719 "option %s must be %s or %s\n", AUGEAS_SPAN_OPTION,
720 AUG_ENABLE, AUG_DISABLE);
723 r = aug_span(cmd->aug, path, &filename, &label_start, &label_end,
724 &value_start, &value_end, &span_start, &span_end);
725 ERR_THROW(r == -1, cmd, AUG_ECMDRUN, "failed to retrieve span");
727 fprintf(cmd->out, "%s label=(%i:%i) value=(%i:%i) span=(%i,%i)\n",
728 filename, label_start, label_end,
729 value_start, value_end, span_start, span_end);
734 static const struct command_opt_def cmd_span_opts[] = {
735 { .type = CMD_PATH, .name = "path", .optional = false,
736 .help = "path matching exactly one node" },
740 static const struct command_def cmd_span_def = {
742 .opts = cmd_span_opts,
744 .synopsis = "print position in input file corresponding to tree",
745 .help = "Print the name of the file from which the node PATH was generated, as\n well as information about the positions in the file corresponding to\n the label, the value, and the entire node. PATH must match exactly\n one node.\n\n You need to run 'set /augeas/span enable' prior to loading files to\n enable recording of span information. It is disabled by default."
748 static void cmd_defvar(struct command *cmd) {
749 const char *name = arg_value(cmd, "name");
750 const char *path = arg_value(cmd, "expr");
752 aug_defvar(cmd->aug, name, path);
755 static const struct command_opt_def cmd_defvar_opts[] = {
756 { .type = CMD_STR, .name = "name", .optional = false,
757 .help = "the name of the variable" },
758 { .type = CMD_PATH, .name = "expr", .optional = false,
759 .help = "the path expression" },
763 static const struct command_def cmd_defvar_def = {
765 .opts = cmd_defvar_opts,
766 .handler = cmd_defvar,
767 .synopsis = "set a variable",
768 .help = "Evaluate EXPR and set the variable NAME to the resulting "
769 "nodeset. The\n variable can be used in path expressions as $NAME. "
770 "Note that EXPR is\n evaluated when the variable is defined, not when "
774 static void cmd_defnode(struct command *cmd) {
775 const char *name = arg_value(cmd, "name");
776 const char *path = arg_value(cmd, "expr");
777 const char *value = arg_value(cmd, "value");
779 /* Make 'defnode foo ""' mean the same as 'defnode foo' */
780 if (value != NULL && strlen(value) == 0)
782 aug_defnode(cmd->aug, name, path, value, NULL);
785 static const struct command_opt_def cmd_defnode_opts[] = {
786 { .type = CMD_STR, .name = "name", .optional = false,
787 .help = "the name of the variable" },
788 { .type = CMD_PATH, .name = "expr", .optional = false,
789 .help = "the path expression" },
790 { .type = CMD_STR, .name = "value", .optional = true,
791 .help = "the value for the new node" },
795 static const struct command_def cmd_defnode_def = {
797 .opts = cmd_defnode_opts,
798 .handler = cmd_defnode,
799 .synopsis = "set a variable, possibly creating a new node",
800 .help = "Define the variable NAME to the result of evaluating EXPR, "
801 " which must\n be a nodeset. If no node matching EXPR exists yet, one "
802 "is created and\n NAME will refer to it. When a node is created and "
803 "VALUE is given, the\n new node's value is set to VALUE."
806 static void cmd_clear(struct command *cmd) {
807 const char *path = arg_value(cmd, "path");
810 r = aug_set(cmd->aug, path, NULL);
812 ERR_REPORT(cmd, AUG_ECMDRUN, "Clearing %s failed", path);
815 static const struct command_opt_def cmd_clear_opts[] = {
816 { .type = CMD_PATH, .name = "path", .optional = false,
817 .help = "clear the value of this node" },
821 static const struct command_def cmd_clear_def = {
823 .opts = cmd_clear_opts,
824 .handler = cmd_clear,
825 .synopsis = "clear the value of a node",
826 .help = "Set the value for PATH to NULL. If PATH is not in the tree yet, "
827 "it and\n all its ancestors will be created. These new tree entries "
828 "will appear\n last amongst their siblings"
831 static void cmd_touch(struct command *cmd) {
832 const char *path = arg_value(cmd, "path");
835 r = aug_match(cmd->aug, path, NULL);
837 r = aug_set(cmd->aug, path, NULL);
839 ERR_REPORT(cmd, AUG_ECMDRUN, "Touching %s failed", path);
843 static const struct command_opt_def cmd_touch_opts[] = {
844 { .type = CMD_PATH, .name = "path", .optional = false,
845 .help = "touch this node" },
849 static const struct command_def cmd_touch_def = {
851 .opts = cmd_touch_opts,
852 .handler = cmd_touch,
853 .synopsis = "create a new node",
854 .help = "Create PATH with the value NULL if it is not in the tree yet. "
855 "All its\n ancestors will also be created. These new tree entries will "
856 "appear\n last amongst their siblings."
859 static void cmd_get(struct command *cmd) {
860 const char *path = arg_value(cmd, "path");
864 r = aug_get(cmd->aug, path, &val);
866 fprintf(cmd->out, "%s", path);
868 fprintf(cmd->out, " (o)\n");
869 } else if (val == NULL) {
870 fprintf(cmd->out, " (none)\n");
872 fprintf(cmd->out, " = %s\n", val);
876 static const struct command_opt_def cmd_get_opts[] = {
877 { .type = CMD_PATH, .name = "path", .optional = false,
878 .help = "get the value of this node" },
882 static const struct command_def cmd_get_def = {
884 .opts = cmd_get_opts,
886 .synopsis = "get the value of a node",
887 .help = "Get and print the value associated with PATH"
890 static void cmd_label(struct command *cmd) {
891 const char *path = arg_value(cmd, "path");
895 r = aug_label(cmd->aug, path, &lbl);
897 fprintf(cmd->out, "%s", path);
899 fprintf(cmd->out, " (o)\n");
900 } else if (lbl == NULL) {
901 fprintf(cmd->out, " (none)\n");
903 fprintf(cmd->out, " = %s\n", lbl);
907 static const struct command_opt_def cmd_label_opts[] = {
908 { .type = CMD_PATH, .name = "path", .optional = false,
909 .help = "get the label of this node" },
913 static const struct command_def cmd_label_def = {
915 .opts = cmd_label_opts,
916 .handler = cmd_label,
917 .synopsis = "get the label of a node",
918 .help = "Get and print the label associated with PATH"
921 static void cmd_print(struct command *cmd) {
922 const char *path = arg_value(cmd, "path");
924 aug_print(cmd->aug, cmd->out, path);
927 static const struct command_opt_def cmd_print_opts[] = {
928 { .type = CMD_PATH, .name = "path", .optional = true,
929 .help = "print this subtree" },
933 static const struct command_def cmd_print_def = {
935 .opts = cmd_print_opts,
936 .handler = cmd_print,
937 .synopsis = "print a subtree",
938 .help = "Print entries in the tree. If PATH is given, printing starts there,\n otherwise the whole tree is printed"
941 static void cmd_source(struct command *cmd) {
942 const char *path = arg_value(cmd, "path");
943 char *file_path = NULL;
945 aug_source(cmd->aug, path, &file_path);
947 if (file_path != NULL) {
948 fprintf(cmd->out, "%s\n", file_path);
953 static const struct command_opt_def cmd_source_opts[] = {
954 { .type = CMD_PATH, .name = "path", .optional = false,
955 .help = "path to a single node" },
959 static const struct command_def cmd_source_def = {
961 .opts = cmd_source_opts,
962 .handler = cmd_source,
963 .synopsis = "print the file to which a node belongs",
964 .help = "Print the file to which the node for PATH belongs. PATH must match\n a single node coming from some file. In particular, that means\n it must be underneath /files."
967 static void cmd_context(struct command *cmd) {
968 const char *path = arg_value(cmd, "path");
971 aug_get(cmd->aug, "/augeas/context", &path);
974 fprintf(cmd->out, "/\n");
976 fprintf(cmd->out, "%s\n", path);
979 aug_set(cmd->aug, "/augeas/context", path);
984 static const struct command_opt_def cmd_context_opts[] = {
985 { .type = CMD_PATH, .name = "path", .optional = true,
986 .help = "new context for relative paths" },
990 static const struct command_def cmd_context_def = {
992 .opts = cmd_context_opts,
993 .handler = cmd_context,
994 .synopsis = "change how relative paths are interpreted",
995 .help = "Relative paths are interpreted relative to a context path which\n is stored in /augeas/context.\n\n When no PATH is given, this command prints the current context path\n and is equivalent to 'get /augeas/context'\n\n When PATH is given, this command changes that context, and has a\n similar effect to 'cd' in a shell and and is the same as running\n the command 'set /augeas/context PATH'."
998 static void cmd_dump_xml(struct command *cmd) {
999 const char *path = arg_value(cmd, "path");
1003 r = aug_to_xml(cmd->aug, path, &xmldoc, 0);
1005 ERR_REPORT(cmd, AUG_ECMDRUN,
1006 "XML export of path %s failed", path);
1008 xmlElemDump(stdout, NULL, xmldoc);
1011 xmlFreeNode(xmldoc);
1014 static const struct command_opt_def cmd_dump_xml_opts[] = {
1015 { .type = CMD_PATH, .name = "path", .optional = true,
1016 .help = "print this subtree" },
1020 static const struct command_def cmd_dump_xml_def = {
1022 .opts = cmd_dump_xml_opts,
1023 .handler = cmd_dump_xml,
1024 .synopsis = "print a subtree as XML",
1025 .help = "Export entries in the tree as XML. If PATH is given, printing starts there,\n otherwise the whole tree is printed."
1028 static void cmd_transform(struct command *cmd) {
1029 const char *lens = arg_value(cmd, "lens");
1030 const char *filter = arg_value(cmd, "filter");
1031 const char *file = arg_value(cmd, "file");
1034 if (STREQ("excl", filter))
1036 else if (STREQ("incl", filter))
1039 ERR_REPORT(cmd, AUG_ECMDRUN,
1040 "FILTER must be \"incl\" or \"excl\"");
1042 r = aug_transform(cmd->aug, lens, file, excl);
1044 ERR_REPORT(cmd, AUG_ECMDRUN,
1045 "Adding transform for %s on lens %s failed", lens, file);
1048 static const struct command_opt_def cmd_transform_opts[] = {
1049 { .type = CMD_PATH, .name = "lens", .optional = false,
1050 .help = "the lens to use" },
1051 { .type = CMD_PATH, .name = "filter", .optional = false,
1052 .help = "the type of filter, either \"incl\" or \"excl\"" },
1053 { .type = CMD_PATH, .name = "file", .optional = false,
1054 .help = "the file to associate to the lens" },
1058 static const char cmd_transform_help[] =
1059 "Add a transform for FILE using LENS. The LENS may be a module name or a\n"
1060 " full lens name. If a module name is given, then \"lns\" will be the lens\n"
1061 " assumed. The FILTER must be either \"incl\" or \"excl\". If the filter is\n"
1062 " \"incl\", the FILE will be parsed by the LENS. If the filter is \"excl\",\n"
1063 " the FILE will be excluded from the LENS. FILE may contain wildcards." ;
1065 static const struct command_def cmd_transform_def = {
1066 .name = "transform",
1067 .opts = cmd_transform_opts,
1068 .handler = cmd_transform,
1069 .synopsis = "add a file transform",
1070 .help = cmd_transform_help
1073 static void cmd_load_file(struct command *cmd) {
1074 const char *file = arg_value(cmd, "file");
1077 r = aug_load_file(cmd->aug, file);
1079 ERR_REPORT(cmd, AUG_ECMDRUN,
1080 "Failed to load file %s", file);
1083 static const struct command_opt_def cmd_load_file_opts[] = {
1084 { .type = CMD_PATH, .name = "file", .optional = false,
1085 .help = "the file to load" },
1089 static const char cmd_load_file_help[] =
1090 "Load a specific FILE, using autoload statements.\n";
1092 static const struct command_def cmd_load_file_def = {
1093 .name = "load-file",
1094 .opts = cmd_load_file_opts,
1095 .handler = cmd_load_file,
1096 .synopsis = "load a specific file",
1097 .help = cmd_load_file_help
1100 static void cmd_save(struct command *cmd) {
1102 r = aug_save(cmd->aug);
1104 ERR_REPORT(cmd, AUG_ECMDRUN,
1105 "saving failed (run 'errors' for details)");
1107 r = aug_match(cmd->aug, "/augeas/events/saved", NULL);
1109 fprintf(cmd->out, "Saved %d file(s)\n", r);
1114 static const struct command_opt_def cmd_save_opts[] = {
1118 static const struct command_def cmd_save_def = {
1120 .opts = cmd_save_opts,
1121 .handler = cmd_save,
1122 .synopsis = "save all pending changes",
1123 .help = "Save all pending changes to disk. How exactly that is done depends on\n the value of the node /augeas/save, which can be changed by the user.\n The possible values for it are\n \n noop - do not write files; useful for finding errors that\n might happen during a save\n backup - save the original file in a file by appending the extension\n '.augsave' and overwrite the original with new content\n newfile - leave the original file untouched and write new content to\n a file with extension '.augnew' next to the original file\n overwrite - overwrite the original file with new content\n \n Save always tries to save all files for which entries in the tree have\n changed. When saving fails, some files will be written. Details about\n why a save failed can by found by running the 'errors' command"
1126 static void cmd_load(struct command *cmd) {
1128 r = aug_load(cmd->aug);
1130 ERR_REPORT(cmd, AUG_ECMDRUN,
1131 "loading failed (run 'errors' for details)");
1135 static const struct command_opt_def cmd_load_opts[] = {
1139 static const struct command_def cmd_load_def = {
1141 .opts = cmd_load_opts,
1142 .handler = cmd_load,
1143 .synopsis = "(re)load files under /files",
1144 .help = "Load files according to the transforms in /augeas/load. "
1145 "A transform\n Foo is represented with a subtree /augeas/load/Foo."
1146 " Underneath\n /augeas/load/Foo, one node labelled 'lens' must exist,"
1147 " whose value is\n the fully qualified name of a lens, for example "
1148 "'Foo.lns', and\n multiple nodes 'incl' and 'excl' whose values are "
1149 "globs that determine\n which files are transformed by that lens. It "
1150 "is an error if one file\n can be processed by multiple transforms."
1153 static void cmd_info(struct command *cmd) {
1157 aug_get(cmd->aug, "/augeas/version", &v);
1160 fprintf(cmd->out, "version = %s\n", v);
1163 aug_get(cmd->aug, "/augeas/root", &v);
1166 fprintf(cmd->out, "root = %s\n", v);
1169 fprintf(cmd->out, "loadpath = ");
1170 for (char *entry = cmd->aug->modpathz;
1172 entry = argz_next(cmd->aug->modpathz, cmd->aug->nmodpath, entry)) {
1173 if (entry != cmd->aug->modpathz) {
1174 fprintf(cmd->out, ":");
1176 fprintf(cmd->out, "%s", entry);
1178 fprintf(cmd->out, "\n");
1180 aug_get(cmd->aug, "/augeas/context", &v);
1185 fprintf(cmd->out, "context = %s\n", v);
1187 n = aug_match(cmd->aug, "/augeas/files//path", NULL);
1188 fprintf(cmd->out, "num_files = %d\n", n);
1191 static const struct command_opt_def cmd_info_opts[] = {
1195 static const struct command_def cmd_info_def = {
1197 .opts = cmd_info_opts,
1198 .handler = cmd_info,
1199 .synopsis = "print runtime information",
1200 .help = "Print information about Augeas. The output contains:\n"
1201 " version : the version number from /augeas/version\n"
1202 " root : what Augeas considers the filesystem root\n"
1203 " from /augeas/root\n"
1204 " loadpath : the paths from which Augeas loads modules\n"
1205 " context : the context path (see context command)\n"
1206 " num_files : the number of files currently loaded (based on\n"
1207 " the number of /augeas/files//path nodes)"
1210 static void cmd_ins(struct command *cmd) {
1211 const char *label = arg_value(cmd, "label");
1212 const char *where = arg_value(cmd, "where");
1213 const char *path = arg_value(cmd, "path");
1216 if (STREQ(where, "after"))
1218 else if (STREQ(where, "before"))
1221 ERR_REPORT(cmd, AUG_ECMDRUN,
1222 "the <WHERE> argument for ins must be either 'before' or 'after'.");
1226 aug_insert(cmd->aug, path, label, before);
1229 static const struct command_opt_def cmd_ins_opts[] = {
1230 { .type = CMD_STR, .name = "label", .optional = false,
1231 .help = "the label for the new node" },
1232 { .type = CMD_STR, .name = "where", .optional = false,
1233 .help = "either 'before' or 'after'" },
1234 { .type = CMD_PATH, .name = "path", .optional = false,
1235 .help = "the node before/after which to insert" },
1239 static const char cmd_ins_help[] =
1240 "Insert a new node with label LABEL right before or after "
1241 "PATH into the\n tree. WHERE must be either 'before' or 'after'.";
1243 static const struct command_def cmd_ins_def = {
1245 .opts = cmd_ins_opts,
1247 .synopsis = "insert new node",
1248 .help = cmd_ins_help
1251 static const struct command_def cmd_insert_def = {
1253 .opts = cmd_ins_opts,
1255 .synopsis = "insert new node (alias of 'ins')",
1256 .help = cmd_ins_help
1259 static void cmd_store(struct command *cmd) {
1260 const char *lens = arg_value(cmd, "lens");
1261 const char *path = arg_value(cmd, "path");
1262 const char *node = arg_value(cmd, "node");
1264 aug_text_store(cmd->aug, lens, node, path);
1267 static const struct command_opt_def cmd_store_opts[] = {
1268 { .type = CMD_STR, .name = "lens", .optional = false,
1269 .help = "the name of the lens" },
1270 { .type = CMD_PATH, .name = "node", .optional = false,
1271 .help = "where to find the input text" },
1272 { .type = CMD_PATH, .name = "path", .optional = false,
1273 .help = "where to store parsed text" },
1277 static const char cmd_store_help[] =
1278 "Parse NODE using LENS and store the resulting tree at PATH.";
1280 static const struct command_def cmd_store_def = {
1282 .opts = cmd_store_opts,
1283 .handler = cmd_store,
1284 .synopsis = "parse text into tree",
1285 .help = cmd_store_help
1288 static void cmd_retrieve(struct command *cmd) {
1289 const char *lens = arg_value(cmd, "lens");
1290 const char *node_in = arg_value(cmd, "node_in");
1291 const char *path = arg_value(cmd, "path");
1292 const char *node_out = arg_value(cmd, "node_out");
1294 aug_text_retrieve(cmd->aug, lens, node_in, path, node_out);
1297 static const struct command_opt_def cmd_retrieve_opts[] = {
1298 { .type = CMD_STR, .name = "lens", .optional = false,
1299 .help = "the name of the lens" },
1300 { .type = CMD_PATH, .name = "node_in", .optional = false,
1301 .help = "the node containing the initial text (path expression)" },
1302 { .type = CMD_PATH, .name = "path", .optional = false,
1303 .help = "the tree to transform (path expression)" },
1304 { .type = CMD_PATH, .name = "node_out", .optional = false,
1305 .help = "where to store the resulting text (path expression)" },
1309 static const char cmd_retrieve_help[] =
1310 "Transform tree at PATH back into text using lens LENS and store the\n"
1311 " resulting string at NODE_OUT. Assume that the tree was initially read in\n"
1312 " with the same lens and the string stored at NODE_IN as input.";
1314 static const struct command_def cmd_retrieve_def = {
1316 .opts = cmd_retrieve_opts,
1317 .handler = cmd_retrieve,
1318 .synopsis = "transform tree into text",
1319 .help = cmd_retrieve_help
1322 /* Given a path "/augeas/files/FILENAME/error", return FILENAME */
1323 static char *err_filename(const char *match) {
1324 int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
1325 if (strlen(match) < noise + 1)
1327 return strndup(match + strlen(AUGEAS_META_FILES), strlen(match) - noise);
1329 return strdup("(no filename)");
1332 static const char *err_get(struct augeas *aug,
1333 const char *match, const char *child) {
1335 const char *value = "";
1338 r = pathjoin(&path, 2, match, child);
1339 ERR_NOMEM(r < 0, aug);
1341 aug_get(aug, path, &value);
1349 static void cmd_errors(struct command *cmd) {
1350 char **matches = NULL;
1352 struct augeas *aug = cmd->aug;
1354 cnt = aug_match(aug, "/augeas//error", &matches);
1356 ERR_THROW(cnt < 0, aug, AUG_ECMDRUN,
1357 " (problem retrieving error messages)\n");
1359 fprintf(cmd->out, " (no errors)\n");
1363 for (int i=0; i < cnt; i++) {
1364 const char *match = matches[i];
1365 const char *line = err_get(aug, match, "line");
1366 const char *char_pos = err_get(aug, match, "char");
1367 const char *lens = err_get(aug, match, "lens");
1368 const char *last = err_get(aug, match, "lens/last_matched");
1369 const char *next = err_get(aug, match, "lens/next_not_matched");
1370 const char *msg = err_get(aug, match, "message");
1371 const char *path = err_get(aug, match, "path");
1372 const char *kind = NULL;
1374 aug_get(aug, match, &kind);
1377 char *filename = err_filename(match);
1378 ERR_NOMEM(filename == NULL, aug);
1381 fprintf(cmd->out, "\n");
1384 fprintf(cmd->out, "Error in %s:%s.%s (%s)\n",
1385 filename, line, char_pos, kind);
1386 } else if (path != NULL) {
1387 fprintf(cmd->out, "Error in %s at node %s (%s)\n", filename, path, kind);
1389 fprintf(cmd->out, "Error in %s (%s)\n", filename, kind);
1394 fprintf(cmd->out, " %s\n", msg);
1396 fprintf(cmd->out, " Lens: %s\n", lens);
1398 fprintf(cmd->out, " Last matched: %s\n", last);
1400 fprintf(cmd->out, " Next (no match): %s\n", next);
1405 for (int i=0; i < cnt; i++)
1410 static const struct command_opt_def cmd_errors_opts[] = {
1414 static const char cmd_errors_help[] =
1415 "Show all the errors encountered in processing files. For each error,\n"
1416 " print detailed information about where it happened and how. The same\n"
1417 " information can be retrieved by running 'print /augeas//error'\n\n"
1418 " For each error, the file in which the error occurred together with the\n"
1419 " line number and position in that line is shown, as well as information\n"
1420 " about the lens that encountered the error. For some errors, the last\n"
1421 " lens that matched successfully and the next lens that should have\n"
1422 " matched but didn't are also shown\n";
1424 static const struct command_def cmd_errors_def = {
1426 .opts = cmd_errors_opts,
1427 .handler = cmd_errors,
1428 .synopsis = "show all errors encountered in processing files",
1429 .help = cmd_errors_help
1432 /* Groups of commands */
1433 static const struct command_grp_def cmd_grp_admin_def = {
1448 static const struct command_grp_def cmd_grp_info_def = {
1449 .name = "Informational",
1459 static const struct command_grp_def cmd_grp_read_def = {
1473 static const struct command_grp_def cmd_grp_write_def = {
1493 static const struct command_grp_def cmd_grp_pathx_def = {
1494 .name = "Path expression",
1502 static const struct command_grp_def *const cmd_groups[] = {
1511 static const struct command_def *lookup_cmd_def(const char *name) {
1512 for (int i = 0; cmd_groups[i]->name != NULL; i++) {
1513 for (int j = 0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1514 if (STREQ(name, cmd_groups[i]->commands[j]->name))
1515 return cmd_groups[i]->commands[j];
1521 static void cmd_help(struct command *cmd) {
1522 const char *name = arg_value(cmd, "command");
1526 //fprintf(cmd->out, "Commands:\n\n");
1527 fprintf(cmd->out, "\n");
1528 for (int i=0; cmd_groups[i]->name != NULL; i++) {
1529 fprintf(cmd->out, "%s commands:\n", cmd_groups[i]->name);
1530 for (int j=0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1531 const struct command_def *def = cmd_groups[i]->commands[j];
1532 fprintf(cmd->out, " %-10s - %s\n", def->name, def->synopsis);
1534 fprintf(cmd->out, "\n");
1537 "Type 'help <command>' for more information on a command\n\n");
1539 const struct command_def *def = lookup_cmd_def(name);
1540 const struct command_opt_def *odef = NULL;
1542 ERR_THROW(def == NULL, cmd->aug, AUG_ECMDRUN,
1543 "unknown command %s\n", name);
1544 fprintf(cmd->out, " COMMAND\n");
1545 fprintf(cmd->out, " %s - %s\n\n", name, def->synopsis);
1546 fprintf(cmd->out, " SYNOPSIS\n");
1547 fprintf(cmd->out, " %s", name);
1549 for (odef = def->opts; odef->name != NULL; odef++) {
1550 format_defname(buf, odef, true);
1551 fprintf(cmd->out, "%s", buf);
1553 fprintf(cmd->out, "\n\n");
1554 fprintf(cmd->out, " DESCRIPTION\n");
1555 format_desc(def->help);
1556 if (def->opts->name != NULL) {
1557 fprintf(cmd->out, " OPTIONS\n");
1558 for (odef = def->opts; odef->name != NULL; odef++) {
1559 const char *help = odef->help;
1562 format_defname(buf, odef, false);
1563 fprintf(cmd->out, " %-10s %s\n", buf, help);
1566 fprintf(cmd->out, "\n");
1572 int aug_srun(augeas *aug, FILE *out, const char *text) {
1582 cmd.error = aug->error;
1588 while (*text != '\0' && result >= 0) {
1589 eol = strchrnul(text, '\n');
1590 while (isspace(*text) && text < eol) text++;
1593 if (*text == '#' || text == eol) {
1594 text = (*eol == '\0') ? eol : eol + 1;
1598 line = strndup(text, eol - text);
1599 ERR_NOMEM(line == NULL, aug);
1601 if (parseline(&cmd, line) == 0) {
1602 cmd.def->handler(&cmd);
1609 if (result >= 0 && cmd.quit) {
1614 free_command_opts(&cmd);
1616 text = (*eol == '\0') ? eol : eol + 1;
1619 free_command_opts(&cmd);
1631 * indent-tabs-mode: nil