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_count(struct command *cmd) {
481 const char *pattern = arg_value(cmd, "path");
483 cnt = aug_match(cmd->aug, pattern, NULL);
485 ERR_THROW(cnt < 0, cmd->aug, AUG_ECMDRUN,
486 " (error matching %s)\n", pattern);
488 fprintf(cmd->out, " no matches\n");
489 } else if (cnt == 1) {
490 fprintf(cmd->out, " 1 match\n");
492 fprintf(cmd->out, " %d matches\n", cnt);
499 static const struct command_opt_def cmd_count_opts[] = {
500 { .type = CMD_PATH, .name = "path", .optional = false,
501 .help = "the path expression to match" },
505 static const struct command_def cmd_count_def = {
507 .opts = cmd_count_opts,
508 .handler = cmd_count,
509 .synopsis = "print the number of matches for a path expression",
510 .help = "Print how many paths match the the path expression PATH"
513 static void cmd_rm(struct command *cmd) {
515 const char *path = arg_value(cmd, "path");
516 cnt = aug_rm(cmd->aug, path);
518 fprintf(cmd->out, "rm : %s %d\n", path, cnt);
521 static const struct command_opt_def cmd_rm_opts[] = {
522 { .type = CMD_PATH, .name = "path", .optional = false,
523 .help = "remove all nodes matching this path expression" },
527 static const struct command_def cmd_rm_def = {
531 .synopsis = "delete nodes and subtrees",
532 .help = "Delete PATH and all its children from the tree"
535 static void cmd_mv(struct command *cmd) {
536 const char *src = arg_value(cmd, "src");
537 const char *dst = arg_value(cmd, "dst");
540 r = aug_mv(cmd->aug, src, dst);
542 ERR_REPORT(cmd, AUG_ECMDRUN,
543 "Moving %s to %s failed", src, dst);
546 static const struct command_opt_def cmd_mv_opts[] = {
547 { .type = CMD_PATH, .name = "src", .optional = false,
548 .help = "the tree to move" },
549 { .type = CMD_PATH, .name = "dst", .optional = false,
550 .help = "where to put the source tree" },
554 static const char cmd_mv_help[] =
555 "Move node SRC to DST. SRC must match exactly one node in "
556 "the tree.\n DST must either match exactly one node in the tree, "
557 "or may not\n exist yet. If DST exists already, it and all its "
558 "descendants are\n deleted. If DST does not exist yet, it and "
559 "all its missing\n ancestors are created.";
561 static const struct command_def cmd_mv_def = {
565 .synopsis = "move a subtree",
569 static const struct command_def cmd_move_def = {
573 .synopsis = "move a subtree (alias of 'mv')",
577 static void cmd_cp(struct command *cmd) {
578 const char *src = arg_value(cmd, "src");
579 const char *dst = arg_value(cmd, "dst");
582 r = aug_cp(cmd->aug, src, dst);
584 ERR_REPORT(cmd, AUG_ECMDRUN,
585 "Copying %s to %s failed", src, dst);
588 static const struct command_opt_def cmd_cp_opts[] = {
589 { .type = CMD_PATH, .name = "src", .optional = false,
590 .help = "the tree to copy" },
591 { .type = CMD_PATH, .name = "dst", .optional = false,
592 .help = "where to copy the source tree" },
596 static const char cmd_cp_help[] =
597 "Copy node SRC to DST. SRC must match exactly one node in "
598 "the tree.\n DST must either match exactly one node in the tree, "
599 "or may not\n exist yet. If DST exists already, it and all its "
600 "descendants are\n deleted. If DST does not exist yet, it and "
601 "all its missing\n ancestors are created.";
603 static const struct command_def cmd_cp_def = {
607 .synopsis = "copy a subtree",
611 static const struct command_def cmd_copy_def = {
615 .synopsis = "copy a subtree (alias of 'cp')",
619 static void cmd_rename(struct command *cmd) {
620 const char *src = arg_value(cmd, "src");
621 const char *lbl = arg_value(cmd, "lbl");
624 cnt = aug_rename(cmd->aug, src, lbl);
626 ERR_REPORT(cmd, AUG_ECMDRUN,
627 "Renaming %s to %s failed", src, lbl);
629 fprintf(cmd->out, "rename : %s to %s %d\n", src, lbl, cnt);
632 static const struct command_opt_def cmd_rename_opts[] = {
633 { .type = CMD_PATH, .name = "src", .optional = false,
634 .help = "the tree to rename" },
635 { .type = CMD_STR, .name = "lbl", .optional = false,
636 .help = "the new label" },
640 static const char cmd_rename_help[] =
641 "Rename the label of all nodes matching SRC to LBL.";
643 static const struct command_def cmd_rename_def = {
645 .opts = cmd_rename_opts,
646 .handler = cmd_rename,
647 .synopsis = "rename a subtree label",
648 .help = cmd_rename_help
651 static void cmd_set(struct command *cmd) {
652 const char *path = arg_value(cmd, "path");
653 const char *val = arg_value(cmd, "value");
656 r = aug_set(cmd->aug, path, val);
658 ERR_REPORT(cmd, AUG_ECMDRUN, "Setting %s failed", path);
661 static const struct command_opt_def cmd_set_opts[] = {
662 { .type = CMD_PATH, .name = "path", .optional = false,
663 .help = "set the value of this node" },
664 { .type = CMD_STR, .name = "value", .optional = true,
665 .help = "the new value for the node" },
669 static const struct command_def cmd_set_def = {
671 .opts = cmd_set_opts,
673 .synopsis = "set the value of a node",
674 .help = "Associate VALUE with PATH. If PATH is not in the tree yet, "
675 "it and all\n its ancestors will be created. These new tree entries "
676 "will appear last\n amongst their siblings"
679 static void cmd_setm(struct command *cmd) {
680 const char *base = arg_value(cmd, "base");
681 const char *sub = arg_value(cmd, "sub");
682 const char *val = arg_value(cmd, "value");
684 aug_setm(cmd->aug, base, sub, val);
687 static const struct command_opt_def cmd_setm_opts[] = {
688 { .type = CMD_PATH, .name = "base", .optional = false,
689 .help = "the base node" },
690 { .type = CMD_PATH, .name = "sub", .optional = false,
691 .help = "the subtree relative to the base" },
692 { .type = CMD_STR, .name = "value", .optional = true,
693 .help = "the value for the nodes" },
697 static const struct command_def cmd_setm_def = {
699 .opts = cmd_setm_opts,
701 .synopsis = "set the value of multiple nodes",
702 .help = "Set multiple nodes in one operation. Find or create a node"
703 " matching SUB\n by interpreting SUB as a path expression relative"
704 " to each node matching\n BASE. If SUB is '.', the nodes matching "
705 "BASE will be modified."
708 static void cmd_clearm(struct command *cmd) {
709 const char *base = arg_value(cmd, "base");
710 const char *sub = arg_value(cmd, "sub");
712 aug_setm(cmd->aug, base, sub, NULL);
715 static const struct command_opt_def cmd_clearm_opts[] = {
716 { .type = CMD_PATH, .name = "base", .optional = false,
717 .help = "the base node" },
718 { .type = CMD_PATH, .name = "sub", .optional = false,
719 .help = "the subtree relative to the base" },
723 static const struct command_def cmd_clearm_def = {
725 .opts = cmd_clearm_opts,
726 .handler = cmd_clearm,
727 .synopsis = "clear the value of multiple nodes",
728 .help = "Clear multiple nodes values in one operation. Find or create a"
729 " node matching SUB\n by interpreting SUB as a path expression relative"
730 " to each node matching\n BASE. If SUB is '.', the nodes matching "
731 "BASE will be modified."
734 static void cmd_span(struct command *cmd) {
735 const char *path = arg_value(cmd, "path");
737 uint label_start, label_end, value_start, value_end, span_start, span_end;
738 char *filename = NULL;
739 const char *option = NULL;
741 if (aug_get(cmd->aug, AUGEAS_SPAN_OPTION, &option) != 1) {
742 printf("Error: option " AUGEAS_SPAN_OPTION " not found\n");
745 if (streqv(AUG_DISABLE, option)) {
746 ERR_REPORT(cmd, AUG_ECMDRUN,
747 "Span is not enabled. To enable, run the commands:\n"
748 " set %s %s\n rm %s\n load\n",
749 AUGEAS_SPAN_OPTION, AUG_ENABLE, AUGEAS_FILES_TREE);
751 } else if (! streqv(AUG_ENABLE, option)) {
752 ERR_REPORT(cmd, AUG_ECMDRUN,
753 "option %s must be %s or %s\n", AUGEAS_SPAN_OPTION,
754 AUG_ENABLE, AUG_DISABLE);
757 r = aug_span(cmd->aug, path, &filename, &label_start, &label_end,
758 &value_start, &value_end, &span_start, &span_end);
759 ERR_THROW(r == -1, cmd, AUG_ECMDRUN, "failed to retrieve span");
761 fprintf(cmd->out, "%s label=(%i:%i) value=(%i:%i) span=(%i,%i)\n",
762 filename, label_start, label_end,
763 value_start, value_end, span_start, span_end);
768 static const struct command_opt_def cmd_span_opts[] = {
769 { .type = CMD_PATH, .name = "path", .optional = false,
770 .help = "path matching exactly one node" },
774 static const struct command_def cmd_span_def = {
776 .opts = cmd_span_opts,
778 .synopsis = "print position in input file corresponding to tree",
779 .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."
782 static void cmd_defvar(struct command *cmd) {
783 const char *name = arg_value(cmd, "name");
784 const char *path = arg_value(cmd, "expr");
786 aug_defvar(cmd->aug, name, path);
789 static const struct command_opt_def cmd_defvar_opts[] = {
790 { .type = CMD_STR, .name = "name", .optional = false,
791 .help = "the name of the variable" },
792 { .type = CMD_PATH, .name = "expr", .optional = false,
793 .help = "the path expression" },
797 static const struct command_def cmd_defvar_def = {
799 .opts = cmd_defvar_opts,
800 .handler = cmd_defvar,
801 .synopsis = "set a variable",
802 .help = "Evaluate EXPR and set the variable NAME to the resulting "
803 "nodeset. The\n variable can be used in path expressions as $NAME. "
804 "Note that EXPR is\n evaluated when the variable is defined, not when "
808 static void cmd_defnode(struct command *cmd) {
809 const char *name = arg_value(cmd, "name");
810 const char *path = arg_value(cmd, "expr");
811 const char *value = arg_value(cmd, "value");
813 /* Make 'defnode foo ""' mean the same as 'defnode foo' */
814 if (value != NULL && strlen(value) == 0)
816 aug_defnode(cmd->aug, name, path, value, NULL);
819 static const struct command_opt_def cmd_defnode_opts[] = {
820 { .type = CMD_STR, .name = "name", .optional = false,
821 .help = "the name of the variable" },
822 { .type = CMD_PATH, .name = "expr", .optional = false,
823 .help = "the path expression" },
824 { .type = CMD_STR, .name = "value", .optional = true,
825 .help = "the value for the new node" },
829 static const struct command_def cmd_defnode_def = {
831 .opts = cmd_defnode_opts,
832 .handler = cmd_defnode,
833 .synopsis = "set a variable, possibly creating a new node",
834 .help = "Define the variable NAME to the result of evaluating EXPR, "
835 " which must\n be a nodeset. If no node matching EXPR exists yet, one "
836 "is created and\n NAME will refer to it. When a node is created and "
837 "VALUE is given, the\n new node's value is set to VALUE."
840 static void cmd_clear(struct command *cmd) {
841 const char *path = arg_value(cmd, "path");
844 r = aug_set(cmd->aug, path, NULL);
846 ERR_REPORT(cmd, AUG_ECMDRUN, "Clearing %s failed", path);
849 static const struct command_opt_def cmd_clear_opts[] = {
850 { .type = CMD_PATH, .name = "path", .optional = false,
851 .help = "clear the value of this node" },
855 static const struct command_def cmd_clear_def = {
857 .opts = cmd_clear_opts,
858 .handler = cmd_clear,
859 .synopsis = "clear the value of a node",
860 .help = "Set the value for PATH to NULL. If PATH is not in the tree yet, "
861 "it and\n all its ancestors will be created. These new tree entries "
862 "will appear\n last amongst their siblings"
865 static void cmd_touch(struct command *cmd) {
866 const char *path = arg_value(cmd, "path");
869 r = aug_match(cmd->aug, path, NULL);
871 r = aug_set(cmd->aug, path, NULL);
873 ERR_REPORT(cmd, AUG_ECMDRUN, "Touching %s failed", path);
877 static const struct command_opt_def cmd_touch_opts[] = {
878 { .type = CMD_PATH, .name = "path", .optional = false,
879 .help = "touch this node" },
883 static const struct command_def cmd_touch_def = {
885 .opts = cmd_touch_opts,
886 .handler = cmd_touch,
887 .synopsis = "create a new node",
888 .help = "Create PATH with the value NULL if it is not in the tree yet. "
889 "All its\n ancestors will also be created. These new tree entries will "
890 "appear\n last amongst their siblings."
893 static void cmd_get(struct command *cmd) {
894 const char *path = arg_value(cmd, "path");
898 r = aug_get(cmd->aug, path, &val);
900 fprintf(cmd->out, "%s", path);
902 fprintf(cmd->out, " (o)\n");
903 } else if (val == NULL) {
904 fprintf(cmd->out, " (none)\n");
906 fprintf(cmd->out, " = %s\n", val);
910 static const struct command_opt_def cmd_get_opts[] = {
911 { .type = CMD_PATH, .name = "path", .optional = false,
912 .help = "get the value of this node" },
916 static const struct command_def cmd_get_def = {
918 .opts = cmd_get_opts,
920 .synopsis = "get the value of a node",
921 .help = "Get and print the value associated with PATH"
924 static void cmd_label(struct command *cmd) {
925 const char *path = arg_value(cmd, "path");
929 r = aug_label(cmd->aug, path, &lbl);
931 fprintf(cmd->out, "%s", path);
933 fprintf(cmd->out, " (o)\n");
934 } else if (lbl == NULL) {
935 fprintf(cmd->out, " (none)\n");
937 fprintf(cmd->out, " = %s\n", lbl);
941 static const struct command_opt_def cmd_label_opts[] = {
942 { .type = CMD_PATH, .name = "path", .optional = false,
943 .help = "get the label of this node" },
947 static const struct command_def cmd_label_def = {
949 .opts = cmd_label_opts,
950 .handler = cmd_label,
951 .synopsis = "get the label of a node",
952 .help = "Get and print the label associated with PATH"
955 static void cmd_print(struct command *cmd) {
956 const char *path = arg_value(cmd, "path");
958 aug_print(cmd->aug, cmd->out, path);
961 static const struct command_opt_def cmd_print_opts[] = {
962 { .type = CMD_PATH, .name = "path", .optional = true,
963 .help = "print this subtree" },
967 static const struct command_def cmd_print_def = {
969 .opts = cmd_print_opts,
970 .handler = cmd_print,
971 .synopsis = "print a subtree",
972 .help = "Print entries in the tree. If PATH is given, printing starts there,\n otherwise the whole tree is printed"
975 static void cmd_source(struct command *cmd) {
976 const char *path = arg_value(cmd, "path");
977 char *file_path = NULL;
979 aug_source(cmd->aug, path, &file_path);
981 if (file_path != NULL) {
982 fprintf(cmd->out, "%s\n", file_path);
987 static const struct command_opt_def cmd_source_opts[] = {
988 { .type = CMD_PATH, .name = "path", .optional = false,
989 .help = "path to a single node" },
993 static const struct command_def cmd_source_def = {
995 .opts = cmd_source_opts,
996 .handler = cmd_source,
997 .synopsis = "print the file to which a node belongs",
998 .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."
1001 static void cmd_context(struct command *cmd) {
1002 const char *path = arg_value(cmd, "path");
1005 aug_get(cmd->aug, "/augeas/context", &path);
1008 fprintf(cmd->out, "/\n");
1010 fprintf(cmd->out, "%s\n", path);
1013 aug_set(cmd->aug, "/augeas/context", path);
1018 static const struct command_opt_def cmd_context_opts[] = {
1019 { .type = CMD_PATH, .name = "path", .optional = true,
1020 .help = "new context for relative paths" },
1024 static const struct command_def cmd_context_def = {
1026 .opts = cmd_context_opts,
1027 .handler = cmd_context,
1028 .synopsis = "change how relative paths are interpreted",
1029 .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'."
1032 static void cmd_dump_xml(struct command *cmd) {
1033 const char *path = arg_value(cmd, "path");
1037 r = aug_to_xml(cmd->aug, path, &xmldoc, 0);
1039 ERR_REPORT(cmd, AUG_ECMDRUN,
1040 "XML export of path %s failed", path);
1042 xmlElemDump(stdout, NULL, xmldoc);
1045 xmlFreeNode(xmldoc);
1048 static const struct command_opt_def cmd_dump_xml_opts[] = {
1049 { .type = CMD_PATH, .name = "path", .optional = true,
1050 .help = "print this subtree" },
1054 static const struct command_def cmd_dump_xml_def = {
1056 .opts = cmd_dump_xml_opts,
1057 .handler = cmd_dump_xml,
1058 .synopsis = "print a subtree as XML",
1059 .help = "Export entries in the tree as XML. If PATH is given, printing starts there,\n otherwise the whole tree is printed."
1062 static void cmd_transform(struct command *cmd) {
1063 const char *lens = arg_value(cmd, "lens");
1064 const char *filter = arg_value(cmd, "filter");
1065 const char *file = arg_value(cmd, "file");
1068 if (STREQ("excl", filter))
1070 else if (STREQ("incl", filter))
1073 ERR_REPORT(cmd, AUG_ECMDRUN,
1074 "FILTER must be \"incl\" or \"excl\"");
1076 r = aug_transform(cmd->aug, lens, file, excl);
1078 ERR_REPORT(cmd, AUG_ECMDRUN,
1079 "Adding transform for %s on lens %s failed", lens, file);
1082 static const struct command_opt_def cmd_transform_opts[] = {
1083 { .type = CMD_PATH, .name = "lens", .optional = false,
1084 .help = "the lens to use" },
1085 { .type = CMD_PATH, .name = "filter", .optional = false,
1086 .help = "the type of filter, either \"incl\" or \"excl\"" },
1087 { .type = CMD_PATH, .name = "file", .optional = false,
1088 .help = "the file to associate to the lens" },
1092 static const char cmd_transform_help[] =
1093 "Add a transform for FILE using LENS. The LENS may be a module name or a\n"
1094 " full lens name. If a module name is given, then \"lns\" will be the lens\n"
1095 " assumed. The FILTER must be either \"incl\" or \"excl\". If the filter is\n"
1096 " \"incl\", the FILE will be parsed by the LENS. If the filter is \"excl\",\n"
1097 " the FILE will be excluded from the LENS. FILE may contain wildcards." ;
1099 static const struct command_def cmd_transform_def = {
1100 .name = "transform",
1101 .opts = cmd_transform_opts,
1102 .handler = cmd_transform,
1103 .synopsis = "add a file transform",
1104 .help = cmd_transform_help
1107 static void cmd_load_file(struct command *cmd) {
1108 const char *file = arg_value(cmd, "file");
1111 r = aug_load_file(cmd->aug, file);
1113 ERR_REPORT(cmd, AUG_ECMDRUN,
1114 "Failed to load file %s", file);
1117 static const struct command_opt_def cmd_load_file_opts[] = {
1118 { .type = CMD_PATH, .name = "file", .optional = false,
1119 .help = "the file to load" },
1123 static const char cmd_load_file_help[] =
1124 "Load a specific FILE, using autoload statements.\n";
1126 static const struct command_def cmd_load_file_def = {
1127 .name = "load-file",
1128 .opts = cmd_load_file_opts,
1129 .handler = cmd_load_file,
1130 .synopsis = "load a specific file",
1131 .help = cmd_load_file_help
1134 static void cmd_save(struct command *cmd) {
1136 r = aug_save(cmd->aug);
1138 ERR_REPORT(cmd, AUG_ECMDRUN,
1139 "saving failed (run 'errors' for details)");
1141 r = aug_match(cmd->aug, "/augeas/events/saved", NULL);
1143 fprintf(cmd->out, "Saved %d file(s)\n", r);
1148 static const struct command_opt_def cmd_save_opts[] = {
1152 static const struct command_def cmd_save_def = {
1154 .opts = cmd_save_opts,
1155 .handler = cmd_save,
1156 .synopsis = "save all pending changes",
1157 .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"
1160 static void cmd_load(struct command *cmd) {
1162 r = aug_load(cmd->aug);
1164 ERR_REPORT(cmd, AUG_ECMDRUN,
1165 "loading failed (run 'errors' for details)");
1169 static const struct command_opt_def cmd_load_opts[] = {
1173 static const struct command_def cmd_load_def = {
1175 .opts = cmd_load_opts,
1176 .handler = cmd_load,
1177 .synopsis = "(re)load files under /files",
1178 .help = "Load files according to the transforms in /augeas/load. "
1179 "A transform\n Foo is represented with a subtree /augeas/load/Foo."
1180 " Underneath\n /augeas/load/Foo, one node labelled 'lens' must exist,"
1181 " whose value is\n the fully qualified name of a lens, for example "
1182 "'Foo.lns', and\n multiple nodes 'incl' and 'excl' whose values are "
1183 "globs that determine\n which files are transformed by that lens. It "
1184 "is an error if one file\n can be processed by multiple transforms."
1187 static void cmd_info(struct command *cmd) {
1191 aug_get(cmd->aug, "/augeas/version", &v);
1194 fprintf(cmd->out, "version = %s\n", v);
1197 aug_get(cmd->aug, "/augeas/root", &v);
1200 fprintf(cmd->out, "root = %s\n", v);
1203 fprintf(cmd->out, "loadpath = ");
1204 for (char *entry = cmd->aug->modpathz;
1206 entry = argz_next(cmd->aug->modpathz, cmd->aug->nmodpath, entry)) {
1207 if (entry != cmd->aug->modpathz) {
1208 fprintf(cmd->out, ":");
1210 fprintf(cmd->out, "%s", entry);
1212 fprintf(cmd->out, "\n");
1214 aug_get(cmd->aug, "/augeas/context", &v);
1219 fprintf(cmd->out, "context = %s\n", v);
1221 n = aug_match(cmd->aug, "/augeas/files//path", NULL);
1222 fprintf(cmd->out, "num_files = %d\n", n);
1225 static const struct command_opt_def cmd_info_opts[] = {
1229 static const struct command_def cmd_info_def = {
1231 .opts = cmd_info_opts,
1232 .handler = cmd_info,
1233 .synopsis = "print runtime information",
1234 .help = "Print information about Augeas. The output contains:\n"
1235 " version : the version number from /augeas/version\n"
1236 " root : what Augeas considers the filesystem root\n"
1237 " from /augeas/root\n"
1238 " loadpath : the paths from which Augeas loads modules\n"
1239 " context : the context path (see context command)\n"
1240 " num_files : the number of files currently loaded (based on\n"
1241 " the number of /augeas/files//path nodes)"
1244 static void cmd_ins(struct command *cmd) {
1245 const char *label = arg_value(cmd, "label");
1246 const char *where = arg_value(cmd, "where");
1247 const char *path = arg_value(cmd, "path");
1250 if (STREQ(where, "after"))
1252 else if (STREQ(where, "before"))
1255 ERR_REPORT(cmd, AUG_ECMDRUN,
1256 "the <WHERE> argument for ins must be either 'before' or 'after'.");
1260 aug_insert(cmd->aug, path, label, before);
1263 static const struct command_opt_def cmd_ins_opts[] = {
1264 { .type = CMD_STR, .name = "label", .optional = false,
1265 .help = "the label for the new node" },
1266 { .type = CMD_STR, .name = "where", .optional = false,
1267 .help = "either 'before' or 'after'" },
1268 { .type = CMD_PATH, .name = "path", .optional = false,
1269 .help = "the node before/after which to insert" },
1273 static const char cmd_ins_help[] =
1274 "Insert a new node with label LABEL right before or after "
1275 "PATH into the\n tree. WHERE must be either 'before' or 'after'.";
1277 static const struct command_def cmd_ins_def = {
1279 .opts = cmd_ins_opts,
1281 .synopsis = "insert new node",
1282 .help = cmd_ins_help
1285 static const struct command_def cmd_insert_def = {
1287 .opts = cmd_ins_opts,
1289 .synopsis = "insert new node (alias of 'ins')",
1290 .help = cmd_ins_help
1293 static void cmd_store(struct command *cmd) {
1294 const char *lens = arg_value(cmd, "lens");
1295 const char *path = arg_value(cmd, "path");
1296 const char *node = arg_value(cmd, "node");
1298 aug_text_store(cmd->aug, lens, node, path);
1301 static const struct command_opt_def cmd_store_opts[] = {
1302 { .type = CMD_STR, .name = "lens", .optional = false,
1303 .help = "the name of the lens" },
1304 { .type = CMD_PATH, .name = "node", .optional = false,
1305 .help = "where to find the input text" },
1306 { .type = CMD_PATH, .name = "path", .optional = false,
1307 .help = "where to store parsed text" },
1311 static const char cmd_store_help[] =
1312 "Parse NODE using LENS and store the resulting tree at PATH.";
1314 static const struct command_def cmd_store_def = {
1316 .opts = cmd_store_opts,
1317 .handler = cmd_store,
1318 .synopsis = "parse text into tree",
1319 .help = cmd_store_help
1322 static void cmd_retrieve(struct command *cmd) {
1323 const char *lens = arg_value(cmd, "lens");
1324 const char *node_in = arg_value(cmd, "node_in");
1325 const char *path = arg_value(cmd, "path");
1326 const char *node_out = arg_value(cmd, "node_out");
1328 aug_text_retrieve(cmd->aug, lens, node_in, path, node_out);
1331 static const struct command_opt_def cmd_retrieve_opts[] = {
1332 { .type = CMD_STR, .name = "lens", .optional = false,
1333 .help = "the name of the lens" },
1334 { .type = CMD_PATH, .name = "node_in", .optional = false,
1335 .help = "the node containing the initial text (path expression)" },
1336 { .type = CMD_PATH, .name = "path", .optional = false,
1337 .help = "the tree to transform (path expression)" },
1338 { .type = CMD_PATH, .name = "node_out", .optional = false,
1339 .help = "where to store the resulting text (path expression)" },
1343 static const char cmd_retrieve_help[] =
1344 "Transform tree at PATH back into text using lens LENS and store the\n"
1345 " resulting string at NODE_OUT. Assume that the tree was initially read in\n"
1346 " with the same lens and the string stored at NODE_IN as input.";
1348 static const struct command_def cmd_retrieve_def = {
1350 .opts = cmd_retrieve_opts,
1351 .handler = cmd_retrieve,
1352 .synopsis = "transform tree into text",
1353 .help = cmd_retrieve_help
1356 /* Given a path "/augeas/files/FILENAME/error", return FILENAME */
1357 static char *err_filename(const char *match) {
1358 int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
1359 if (strlen(match) < noise + 1)
1361 return strndup(match + strlen(AUGEAS_META_FILES), strlen(match) - noise);
1363 return strdup("(no filename)");
1366 static const char *err_get(struct augeas *aug,
1367 const char *match, const char *child) {
1369 const char *value = "";
1372 r = pathjoin(&path, 2, match, child);
1373 ERR_NOMEM(r < 0, aug);
1375 aug_get(aug, path, &value);
1383 static void cmd_errors(struct command *cmd) {
1384 char **matches = NULL;
1386 struct augeas *aug = cmd->aug;
1388 cnt = aug_match(aug, "/augeas//error", &matches);
1390 ERR_THROW(cnt < 0, aug, AUG_ECMDRUN,
1391 " (problem retrieving error messages)\n");
1393 fprintf(cmd->out, " (no errors)\n");
1397 for (int i=0; i < cnt; i++) {
1398 const char *match = matches[i];
1399 const char *line = err_get(aug, match, "line");
1400 const char *char_pos = err_get(aug, match, "char");
1401 const char *lens = err_get(aug, match, "lens");
1402 const char *last = err_get(aug, match, "lens/last_matched");
1403 const char *next = err_get(aug, match, "lens/next_not_matched");
1404 const char *msg = err_get(aug, match, "message");
1405 const char *path = err_get(aug, match, "path");
1406 const char *kind = NULL;
1408 aug_get(aug, match, &kind);
1411 char *filename = err_filename(match);
1412 ERR_NOMEM(filename == NULL, aug);
1415 fprintf(cmd->out, "\n");
1418 fprintf(cmd->out, "Error in %s:%s.%s (%s)\n",
1419 filename, line, char_pos, kind);
1420 } else if (path != NULL) {
1421 fprintf(cmd->out, "Error in %s at node %s (%s)\n", filename, path, kind);
1423 fprintf(cmd->out, "Error in %s (%s)\n", filename, kind);
1428 fprintf(cmd->out, " %s\n", msg);
1430 fprintf(cmd->out, " Lens: %s\n", lens);
1432 fprintf(cmd->out, " Last matched: %s\n", last);
1434 fprintf(cmd->out, " Next (no match): %s\n", next);
1439 for (int i=0; i < cnt; i++)
1444 static const struct command_opt_def cmd_errors_opts[] = {
1448 static const char cmd_errors_help[] =
1449 "Show all the errors encountered in processing files. For each error,\n"
1450 " print detailed information about where it happened and how. The same\n"
1451 " information can be retrieved by running 'print /augeas//error'\n\n"
1452 " For each error, the file in which the error occurred together with the\n"
1453 " line number and position in that line is shown, as well as information\n"
1454 " about the lens that encountered the error. For some errors, the last\n"
1455 " lens that matched successfully and the next lens that should have\n"
1456 " matched but didn't are also shown\n";
1458 static const struct command_def cmd_errors_def = {
1460 .opts = cmd_errors_opts,
1461 .handler = cmd_errors,
1462 .synopsis = "show all errors encountered in processing files",
1463 .help = cmd_errors_help
1466 /* Groups of commands */
1467 static const struct command_grp_def cmd_grp_admin_def = {
1482 static const struct command_grp_def cmd_grp_info_def = {
1483 .name = "Informational",
1493 static const struct command_grp_def cmd_grp_read_def = {
1508 static const struct command_grp_def cmd_grp_write_def = {
1528 static const struct command_grp_def cmd_grp_pathx_def = {
1529 .name = "Path expression",
1537 static const struct command_grp_def *const cmd_groups[] = {
1546 static const struct command_def *lookup_cmd_def(const char *name) {
1547 for (int i = 0; cmd_groups[i]->name != NULL; i++) {
1548 for (int j = 0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1549 if (STREQ(name, cmd_groups[i]->commands[j]->name))
1550 return cmd_groups[i]->commands[j];
1556 static void cmd_help(struct command *cmd) {
1557 const char *name = arg_value(cmd, "command");
1561 //fprintf(cmd->out, "Commands:\n\n");
1562 fprintf(cmd->out, "\n");
1563 for (int i=0; cmd_groups[i]->name != NULL; i++) {
1564 fprintf(cmd->out, "%s commands:\n", cmd_groups[i]->name);
1565 for (int j=0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1566 const struct command_def *def = cmd_groups[i]->commands[j];
1567 fprintf(cmd->out, " %-10s - %s\n", def->name, def->synopsis);
1569 fprintf(cmd->out, "\n");
1572 "Type 'help <command>' for more information on a command\n\n");
1574 const struct command_def *def = lookup_cmd_def(name);
1575 const struct command_opt_def *odef = NULL;
1577 ERR_THROW(def == NULL, cmd->aug, AUG_ECMDRUN,
1578 "unknown command %s\n", name);
1579 fprintf(cmd->out, " COMMAND\n");
1580 fprintf(cmd->out, " %s - %s\n\n", name, def->synopsis);
1581 fprintf(cmd->out, " SYNOPSIS\n");
1582 fprintf(cmd->out, " %s", name);
1584 for (odef = def->opts; odef->name != NULL; odef++) {
1585 format_defname(buf, odef, true);
1586 fprintf(cmd->out, "%s", buf);
1588 fprintf(cmd->out, "\n\n");
1589 fprintf(cmd->out, " DESCRIPTION\n");
1590 format_desc(def->help);
1591 if (def->opts->name != NULL) {
1592 fprintf(cmd->out, " OPTIONS\n");
1593 for (odef = def->opts; odef->name != NULL; odef++) {
1594 const char *help = odef->help;
1597 format_defname(buf, odef, false);
1598 fprintf(cmd->out, " %-10s %s\n", buf, help);
1601 fprintf(cmd->out, "\n");
1607 int aug_srun(augeas *aug, FILE *out, const char *text) {
1617 cmd.error = aug->error;
1623 while (*text != '\0' && result >= 0) {
1624 eol = strchrnul(text, '\n');
1625 while (isspace(*text) && text < eol) text++;
1628 if (*text == '#' || text == eol) {
1629 text = (*eol == '\0') ? eol : eol + 1;
1633 line = strndup(text, eol - text);
1634 ERR_NOMEM(line == NULL, aug);
1636 if (parseline(&cmd, line) == 0) {
1637 cmd.def->handler(&cmd);
1644 if (result >= 0 && cmd.quit) {
1649 free_command_opts(&cmd);
1651 text = (*eol == '\0') ? eol : eol + 1;
1654 free_command_opts(&cmd);
1666 * indent-tabs-mode: nil