2 * augrun.c: command interpreter for augeas
4 * Copyright (C) 2011-2015 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>
33 * Command handling infrastructure
35 enum command_opt_type {
37 CMD_STR, /* String argument */
38 CMD_PATH /* Path expression */
41 struct command_opt_def {
42 bool optional; /* Optional or mandatory */
43 enum command_opt_type type;
48 #define CMD_OPT_DEF_LAST { .type = CMD_NONE, .name = NULL }
51 const struct command_def *def;
52 struct command_opt *opt;
54 struct error *error; /* Same as aug->error */
59 typedef void (*cmd_handler)(struct command*);
64 const struct command_opt_def *opts;
70 static const struct command_def cmd_def_last =
71 { .name = NULL, .opts = NULL, .handler = NULL,
72 .synopsis = NULL, .help = NULL };
75 struct command_opt *next;
76 const struct command_opt_def *def;
80 struct command_grp_def {
82 const struct command_def const *commands[];
85 static const struct command_grp_def cmd_grp_def_last =
86 { .name = NULL, .commands = { } };
88 static const struct command_def *lookup_cmd_def(const char *name);
90 static const struct command_opt_def *
91 find_def(const struct command *cmd, const char *name) {
92 const struct command_opt_def *def;
93 for (def = cmd->def->opts; def->name != NULL; def++) {
94 if (STREQ(def->name, name))
100 static struct command_opt *
101 find_opt(const struct command *cmd, const char *name) {
102 const struct command_opt_def *def = find_def(cmd, name);
105 for (struct command_opt *opt = cmd->opt; opt != NULL; opt = opt->next) {
109 assert(def->optional);
113 static const char *arg_value(const struct command *cmd, const char *name) {
114 struct command_opt *opt = find_opt(cmd, name);
116 return (opt == NULL) ? NULL : opt->value;
119 static char *nexttoken(struct command *cmd, char **line, bool path) {
128 while (*s && isblank(*s)) s+= 1;
136 case ']': /* pass both literally */
139 case 't': /* insert tab */
144 case 'n': /* insert newline */
150 case '\t': /* pass both through if quoted, else fall */
153 case '"': /* pass both through if opposite quote, else fall */
154 if (quot && quot != *(s+1)) break;
155 case '\\': /* pass next character through */
160 ERR_REPORT(cmd, AUG_ECMDRUN, "unknown escape sequence");
166 if (*s == '[') nbracket += 1;
167 if (*s == ']') nbracket -= 1;
169 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
173 if (!path || nbracket == 0) {
174 if (!quot && (*s == '\'' || *s == '"')) {
177 } else if (quot && *s == quot) {
182 if (!quot && isblank(*s))
195 if (*s == '\0' && path && nbracket > 0) {
196 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
199 if (*s == '\0' && quot) {
200 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched %c", quot);
209 static struct command_opt *
210 make_command_opt(struct command *cmd, const struct command_opt_def *def) {
211 struct command_opt *copt = NULL;
215 ERR_NOMEM(r < 0, cmd->aug);
217 list_append(cmd->opt, copt);
222 static void free_command_opts(struct command *cmd) {
223 struct command_opt *next;
226 while (next != NULL) {
227 struct command_opt *del = next;
234 static int parseline(struct command *cmd, char *line) {
236 int narg = 0, nopt = 0;
237 const struct command_opt_def *def;
239 tok = nexttoken(cmd, &line, false);
242 cmd->def = lookup_cmd_def(tok);
243 if (cmd->def == NULL) {
244 ERR_REPORT(cmd, AUG_ECMDRUN, "Unknown command '%s'", tok);
248 for (def = cmd->def->opts; def->name != NULL; def++) {
255 def = cmd->def->opts;
256 while (*line != '\0') {
257 while (*line && isblank(*line)) line += 1;
259 if (curarg >= narg) {
260 ERR_REPORT(cmd, AUG_ECMDRUN,
261 "Too many arguments. Command %s takes only %d arguments",
262 cmd->def->name, narg);
266 struct command_opt *opt = make_command_opt(cmd, def);
270 if (def->type == CMD_PATH) {
271 tok = nexttoken(cmd, &line, true);
274 tok = nexttoken(cmd, &line, false);
281 while (*line && isblank(*line)) line += 1;
284 if (curarg < narg - nopt) {
285 ERR_REPORT(cmd, AUG_ECMDRUN, "Not enough arguments for %s", cmd->def->name);
295 static void format_desc(const char *d) {
297 for (const char *s = d; *s; s++) {
306 static void format_defname(char *buf, const struct command_opt_def *def,
307 bool mark_optional) {
309 if (mark_optional && def->optional)
310 p = stpcpy(buf, " [<");
312 p = stpcpy(buf, " <");
313 for (int i=0; i < strlen(def->name); i++)
314 *p++ = toupper(def->name[i]);
316 if (mark_optional && def->optional)
321 static void cmd_help(struct command *cmd);
323 static const struct command_opt_def cmd_help_opts[] = {
324 { .type = CMD_STR, .name = "command", .optional = true,
325 .help = "print help for this command only" },
329 static const struct command_def cmd_help_def = {
331 .opts = cmd_help_opts,
333 .synopsis = "print help",
334 .help = "list all commands or print details about one command"
337 static void cmd_quit(ATTRIBUTE_UNUSED struct command *cmd) {
341 static const struct command_opt_def cmd_quit_opts[] = {
345 static const struct command_def cmd_quit_def = {
347 .opts = cmd_quit_opts,
349 .synopsis = "exit the program",
350 .help = "Exit the program"
353 static char *ls_pattern(struct command *cmd, const char *path) {
357 if (path[strlen(path)-1] == SEP)
358 r = xasprintf(&q, "%s*", path);
360 r = xasprintf(&q, "%s/*", path);
361 ERR_NOMEM(r < 0, cmd->aug);
366 static int child_count(struct command *cmd, const char *path) {
367 char *q = ls_pattern(cmd, path);
372 cnt = aug_match(cmd->aug, q, NULL);
379 static void cmd_ls(struct command *cmd) {
384 path = ls_pattern(cmd, arg_value(cmd, "path"));
387 cnt = aug_match(cmd->aug, path, &paths);
389 for (int i=0; i < cnt; i++) {
391 const char *basnam = strrchr(paths[i], SEP);
392 int dir = child_count(cmd, paths[i]);
393 aug_get(cmd->aug, paths[i], &val);
395 basnam = (basnam == NULL) ? paths[i] : basnam + 1;
398 fprintf(cmd->out, "%s%s= %s\n", basnam, dir ? "/ " : " ", val);
403 for (int i=0; i < cnt; i++)
408 static const struct command_opt_def cmd_ls_opts[] = {
409 { .type = CMD_PATH, .name = "path", .optional = false,
410 .help = "the node whose children to list" },
414 static const struct command_def cmd_ls_def = {
418 .synopsis = "list children of a node",
419 .help = "list the direct children of a node"
422 static void cmd_match(struct command *cmd) {
424 const char *pattern = arg_value(cmd, "path");
425 const char *value = arg_value(cmd, "value");
426 char **matches = NULL;
427 bool filter = (value != NULL) && (strlen(value) > 0);
429 cnt = aug_match(cmd->aug, pattern, &matches);
431 ERR_THROW(cnt < 0, cmd->aug, AUG_ECMDRUN,
432 " (error matching %s)\n", pattern);
434 fprintf(cmd->out, " (no matches)\n");
438 for (int i=0; i < cnt; i++) {
440 aug_get(cmd->aug, matches[i], &val);
445 if (STREQ(value, val))
446 fprintf(cmd->out, "%s\n", matches[i]);
448 fprintf(cmd->out, "%s = %s\n", matches[i], val);
453 for (int i=0; i < cnt; i++)
458 static const struct command_opt_def cmd_match_opts[] = {
459 { .type = CMD_PATH, .name = "path", .optional = false,
460 .help = "the path expression to match" },
461 { .type = CMD_STR, .name = "value", .optional = true,
462 .help = "only show matches with this value" },
466 static const struct command_def cmd_match_def = {
468 .opts = cmd_match_opts,
469 .handler = cmd_match,
470 .synopsis = "print matches for a path expression",
471 .help = "Find all paths that match the path expression PATH. "
472 "If VALUE is given,\n only the matching paths whose value equals "
476 static void cmd_rm(struct command *cmd) {
478 const char *path = arg_value(cmd, "path");
479 cnt = aug_rm(cmd->aug, path);
481 fprintf(cmd->out, "rm : %s %d\n", path, cnt);
484 static const struct command_opt_def cmd_rm_opts[] = {
485 { .type = CMD_PATH, .name = "path", .optional = false,
486 .help = "remove all nodes matching this path expression" },
490 static const struct command_def cmd_rm_def = {
494 .synopsis = "delete nodes and subtrees",
495 .help = "Delete PATH and all its children from the tree"
498 static void cmd_mv(struct command *cmd) {
499 const char *src = arg_value(cmd, "src");
500 const char *dst = arg_value(cmd, "dst");
503 r = aug_mv(cmd->aug, src, dst);
505 ERR_REPORT(cmd, AUG_ECMDRUN,
506 "Moving %s to %s failed", src, dst);
509 static const struct command_opt_def cmd_mv_opts[] = {
510 { .type = CMD_PATH, .name = "src", .optional = false,
511 .help = "the tree to move" },
512 { .type = CMD_PATH, .name = "dst", .optional = false,
513 .help = "where to put the source tree" },
517 static const char const cmd_mv_help[] =
518 "Move node SRC to DST. SRC must match exactly one node in "
519 "the tree.\n DST must either match exactly one node in the tree, "
520 "or may not\n exist yet. If DST exists already, it and all its "
521 "descendants are\n deleted. If DST does not exist yet, it and "
522 "all its missing\n ancestors are created.";
524 static const struct command_def cmd_mv_def = {
528 .synopsis = "move a subtree",
532 static const struct command_def cmd_move_def = {
536 .synopsis = "move a subtree (alias of 'mv')",
540 static void cmd_cp(struct command *cmd) {
541 const char *src = arg_value(cmd, "src");
542 const char *dst = arg_value(cmd, "dst");
545 r = aug_cp(cmd->aug, src, dst);
547 ERR_REPORT(cmd, AUG_ECMDRUN,
548 "Copying %s to %s failed", src, dst);
551 static const struct command_opt_def cmd_cp_opts[] = {
552 { .type = CMD_PATH, .name = "src", .optional = false,
553 .help = "the tree to copy" },
554 { .type = CMD_PATH, .name = "dst", .optional = false,
555 .help = "where to copy the source tree" },
559 static const char const cmd_cp_help[] =
560 "Copy node SRC to DST. SRC must match exactly one node in "
561 "the tree.\n DST must either match exactly one node in the tree, "
562 "or may not\n exist yet. If DST exists already, it and all its "
563 "descendants are\n deleted. If DST does not exist yet, it and "
564 "all its missing\n ancestors are created.";
566 static const struct command_def cmd_cp_def = {
570 .synopsis = "copy a subtree",
574 static const struct command_def cmd_copy_def = {
578 .synopsis = "copy a subtree (alias of 'cp')",
582 static void cmd_rename(struct command *cmd) {
583 const char *src = arg_value(cmd, "src");
584 const char *lbl = arg_value(cmd, "lbl");
587 cnt = aug_rename(cmd->aug, src, lbl);
589 ERR_REPORT(cmd, AUG_ECMDRUN,
590 "Renaming %s to %s failed", src, lbl);
592 fprintf(cmd->out, "rename : %s to %s %d\n", src, lbl, cnt);
595 static const struct command_opt_def cmd_rename_opts[] = {
596 { .type = CMD_PATH, .name = "src", .optional = false,
597 .help = "the tree to rename" },
598 { .type = CMD_STR, .name = "lbl", .optional = false,
599 .help = "the new label" },
603 static const char const cmd_rename_help[] =
604 "Rename the label of all nodes matching SRC to LBL.";
606 static const struct command_def cmd_rename_def = {
608 .opts = cmd_rename_opts,
609 .handler = cmd_rename,
610 .synopsis = "rename a subtree label",
611 .help = cmd_rename_help
614 static void cmd_set(struct command *cmd) {
615 const char *path = arg_value(cmd, "path");
616 const char *val = arg_value(cmd, "value");
619 r = aug_set(cmd->aug, path, val);
621 ERR_REPORT(cmd, AUG_ECMDRUN, "Setting %s failed", path);
624 static const struct command_opt_def cmd_set_opts[] = {
625 { .type = CMD_PATH, .name = "path", .optional = false,
626 .help = "set the value of this node" },
627 { .type = CMD_STR, .name = "value", .optional = true,
628 .help = "the new value for the node" },
632 static const struct command_def cmd_set_def = {
634 .opts = cmd_set_opts,
636 .synopsis = "set the value of a node",
637 .help = "Associate VALUE with PATH. If PATH is not in the tree yet, "
638 "it and all\n its ancestors will be created. These new tree entries "
639 "will appear last\n amongst their siblings"
642 static void cmd_setm(struct command *cmd) {
643 const char *base = arg_value(cmd, "base");
644 const char *sub = arg_value(cmd, "sub");
645 const char *val = arg_value(cmd, "value");
647 aug_setm(cmd->aug, base, sub, val);
650 static const struct command_opt_def cmd_setm_opts[] = {
651 { .type = CMD_PATH, .name = "base", .optional = false,
652 .help = "the base node" },
653 { .type = CMD_PATH, .name = "sub", .optional = false,
654 .help = "the subtree relative to the base" },
655 { .type = CMD_STR, .name = "value", .optional = true,
656 .help = "the value for the nodes" },
660 static const struct command_def cmd_setm_def = {
662 .opts = cmd_setm_opts,
664 .synopsis = "set the value of multiple nodes",
665 .help = "Set multiple nodes in one operation. Find or create a node"
666 " matching SUB\n by interpreting SUB as a path expression relative"
667 " to each node matching\n BASE. If SUB is '.', the nodes matching "
668 "BASE will be modified."
671 static void cmd_clearm(struct command *cmd) {
672 const char *base = arg_value(cmd, "base");
673 const char *sub = arg_value(cmd, "sub");
675 aug_setm(cmd->aug, base, sub, NULL);
678 static const struct command_opt_def cmd_clearm_opts[] = {
679 { .type = CMD_PATH, .name = "base", .optional = false,
680 .help = "the base node" },
681 { .type = CMD_PATH, .name = "sub", .optional = false,
682 .help = "the subtree relative to the base" },
686 static const struct command_def cmd_clearm_def = {
688 .opts = cmd_clearm_opts,
689 .handler = cmd_clearm,
690 .synopsis = "clear the value of multiple nodes",
691 .help = "Clear multiple nodes values in one operation. Find or create a"
692 " node matching SUB\n by interpreting SUB as a path expression relative"
693 " to each node matching\n BASE. If SUB is '.', the nodes matching "
694 "BASE will be modified."
697 static void cmd_span(struct command *cmd) {
698 const char *path = arg_value(cmd, "path");
700 uint label_start, label_end, value_start, value_end, span_start, span_end;
701 char *filename = NULL;
702 const char *option = NULL;
704 if (aug_get(cmd->aug, AUGEAS_SPAN_OPTION, &option) != 1) {
705 printf("Error: option " AUGEAS_SPAN_OPTION " not found\n");
708 if (streqv(AUG_DISABLE, option)) {
709 ERR_REPORT(cmd, AUG_ECMDRUN,
710 "Span is not enabled. To enable, run the commands:\n"
711 " set %s %s\n rm %s\n load\n",
712 AUGEAS_SPAN_OPTION, AUG_ENABLE, AUGEAS_FILES_TREE);
714 } else if (! streqv(AUG_ENABLE, option)) {
715 ERR_REPORT(cmd, AUG_ECMDRUN,
716 "option %s must be %s or %s\n", AUGEAS_SPAN_OPTION,
717 AUG_ENABLE, AUG_DISABLE);
720 r = aug_span(cmd->aug, path, &filename, &label_start, &label_end,
721 &value_start, &value_end, &span_start, &span_end);
722 ERR_THROW(r == -1, cmd, AUG_ECMDRUN, "failed to retrieve span");
724 fprintf(cmd->out, "%s label=(%i:%i) value=(%i:%i) span=(%i,%i)\n",
725 filename, label_start, label_end,
726 value_start, value_end, span_start, span_end);
731 static const struct command_opt_def cmd_span_opts[] = {
732 { .type = CMD_PATH, .name = "path", .optional = false,
733 .help = "path matching exactly one node" },
737 static const struct command_def cmd_span_def = {
739 .opts = cmd_span_opts,
741 .synopsis = "print position in input file corresponding to tree",
742 .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."
745 static void cmd_defvar(struct command *cmd) {
746 const char *name = arg_value(cmd, "name");
747 const char *path = arg_value(cmd, "expr");
749 aug_defvar(cmd->aug, name, path);
752 static const struct command_opt_def cmd_defvar_opts[] = {
753 { .type = CMD_STR, .name = "name", .optional = false,
754 .help = "the name of the variable" },
755 { .type = CMD_PATH, .name = "expr", .optional = false,
756 .help = "the path expression" },
760 static const struct command_def cmd_defvar_def = {
762 .opts = cmd_defvar_opts,
763 .handler = cmd_defvar,
764 .synopsis = "set a variable",
765 .help = "Evaluate EXPR and set the variable NAME to the resulting "
766 "nodeset. The\n variable can be used in path expressions as $NAME. "
767 "Note that EXPR is\n evaluated when the variable is defined, not when "
771 static void cmd_defnode(struct command *cmd) {
772 const char *name = arg_value(cmd, "name");
773 const char *path = arg_value(cmd, "expr");
774 const char *value = arg_value(cmd, "value");
776 /* Make 'defnode foo ""' mean the same as 'defnode foo' */
777 if (value != NULL && strlen(value) == 0)
779 aug_defnode(cmd->aug, name, path, value, NULL);
782 static const struct command_opt_def cmd_defnode_opts[] = {
783 { .type = CMD_STR, .name = "name", .optional = false,
784 .help = "the name of the variable" },
785 { .type = CMD_PATH, .name = "expr", .optional = false,
786 .help = "the path expression" },
787 { .type = CMD_STR, .name = "value", .optional = true,
788 .help = "the value for the new node" },
792 static const struct command_def cmd_defnode_def = {
794 .opts = cmd_defnode_opts,
795 .handler = cmd_defnode,
796 .synopsis = "set a variable, possibly creating a new node",
797 .help = "Define the variable NAME to the result of evaluating EXPR, "
798 " which must\n be a nodeset. If no node matching EXPR exists yet, one "
799 "is created and\n NAME will refer to it. When a node is created and "
800 "VALUE is given, the\n new node's value is set to VALUE."
803 static void cmd_clear(struct command *cmd) {
804 const char *path = arg_value(cmd, "path");
807 r = aug_set(cmd->aug, path, NULL);
809 ERR_REPORT(cmd, AUG_ECMDRUN, "Clearing %s failed", path);
812 static const struct command_opt_def cmd_clear_opts[] = {
813 { .type = CMD_PATH, .name = "path", .optional = false,
814 .help = "clear the value of this node" },
818 static const struct command_def cmd_clear_def = {
820 .opts = cmd_clear_opts,
821 .handler = cmd_clear,
822 .synopsis = "clear the value of a node",
823 .help = "Set the value for PATH to NULL. If PATH is not in the tree yet, "
824 "it and\n all its ancestors will be created. These new tree entries "
825 "will appear\n last amongst their siblings"
828 static void cmd_touch(struct command *cmd) {
829 const char *path = arg_value(cmd, "path");
832 r = aug_match(cmd->aug, path, NULL);
834 r = aug_set(cmd->aug, path, NULL);
836 ERR_REPORT(cmd, AUG_ECMDRUN, "Touching %s failed", path);
840 static const struct command_opt_def cmd_touch_opts[] = {
841 { .type = CMD_PATH, .name = "path", .optional = false,
842 .help = "touch this node" },
846 static const struct command_def cmd_touch_def = {
848 .opts = cmd_touch_opts,
849 .handler = cmd_touch,
850 .synopsis = "create a new node",
851 .help = "Create PATH with the value NULL if it is not in the tree yet. "
852 "All its\n ancestors will also be created. These new tree entries will "
853 "appear\n last amongst their siblings."
856 static void cmd_get(struct command *cmd) {
857 const char *path = arg_value(cmd, "path");
861 r = aug_get(cmd->aug, path, &val);
863 fprintf(cmd->out, "%s", path);
865 fprintf(cmd->out, " (o)\n");
866 } else if (val == NULL) {
867 fprintf(cmd->out, " (none)\n");
869 fprintf(cmd->out, " = %s\n", val);
873 static const struct command_opt_def cmd_get_opts[] = {
874 { .type = CMD_PATH, .name = "path", .optional = false,
875 .help = "get the value of this node" },
879 static const struct command_def cmd_get_def = {
881 .opts = cmd_get_opts,
883 .synopsis = "get the value of a node",
884 .help = "Get and print the value associated with PATH"
887 static void cmd_label(struct command *cmd) {
888 const char *path = arg_value(cmd, "path");
892 r = aug_label(cmd->aug, path, &lbl);
894 fprintf(cmd->out, "%s", path);
896 fprintf(cmd->out, " (o)\n");
897 } else if (lbl == NULL) {
898 fprintf(cmd->out, " (none)\n");
900 fprintf(cmd->out, " = %s\n", lbl);
904 static const struct command_opt_def cmd_label_opts[] = {
905 { .type = CMD_PATH, .name = "path", .optional = false,
906 .help = "get the label of this node" },
910 static const struct command_def cmd_label_def = {
912 .opts = cmd_label_opts,
913 .handler = cmd_label,
914 .synopsis = "get the label of a node",
915 .help = "Get and print the label associated with PATH"
918 static void cmd_print(struct command *cmd) {
919 const char *path = arg_value(cmd, "path");
921 aug_print(cmd->aug, cmd->out, path);
924 static const struct command_opt_def cmd_print_opts[] = {
925 { .type = CMD_PATH, .name = "path", .optional = true,
926 .help = "print this subtree" },
930 static const struct command_def cmd_print_def = {
932 .opts = cmd_print_opts,
933 .handler = cmd_print,
934 .synopsis = "print a subtree",
935 .help = "Print entries in the tree. If PATH is given, printing starts there,\n otherwise the whole tree is printed"
938 static void cmd_dump_xml(struct command *cmd) {
939 const char *path = arg_value(cmd, "path");
943 r = aug_to_xml(cmd->aug, path, &xmldoc, 0);
945 ERR_REPORT(cmd, AUG_ECMDRUN,
946 "XML export of path %s failed", path);
948 xmlElemDump(stdout, NULL, xmldoc);
954 static const struct command_opt_def cmd_dump_xml_opts[] = {
955 { .type = CMD_PATH, .name = "path", .optional = true,
956 .help = "print this subtree" },
960 static const struct command_def cmd_dump_xml_def = {
962 .opts = cmd_dump_xml_opts,
963 .handler = cmd_dump_xml,
964 .synopsis = "print a subtree as XML",
965 .help = "Export entries in the tree as XML. If PATH is given, printing starts there,\n otherwise the whole tree is printed."
968 static void cmd_transform(struct command *cmd) {
969 const char *lens = arg_value(cmd, "lens");
970 const char *filter = arg_value(cmd, "filter");
971 const char *file = arg_value(cmd, "file");
974 if (STREQ("excl", filter))
976 else if (STREQ("incl", filter))
979 ERR_REPORT(cmd, AUG_ECMDRUN,
980 "FILTER must be \"incl\" or \"excl\"");
982 r = aug_transform(cmd->aug, lens, file, excl);
984 ERR_REPORT(cmd, AUG_ECMDRUN,
985 "Adding transform for %s on lens %s failed", lens, file);
988 static const struct command_opt_def cmd_transform_opts[] = {
989 { .type = CMD_PATH, .name = "lens", .optional = false,
990 .help = "the lens to use" },
991 { .type = CMD_PATH, .name = "filter", .optional = false,
992 .help = "the type of filter, either \"incl\" or \"excl\"" },
993 { .type = CMD_PATH, .name = "file", .optional = false,
994 .help = "the file to associate to the lens" },
998 static const char const cmd_transform_help[] =
999 "Add a transform for FILE using LENS. The LENS may be a module name or a\n"
1000 " full lens name. If a module name is given, then \"lns\" will be the lens\n"
1001 " assumed. The FILTER must be either \"incl\" or \"excl\". If the filter is\n"
1002 " \"incl\", the FILE will be parsed by the LENS. If the filter is \"excl\",\n"
1003 " the FILE will be excluded from the LENS. FILE may contain wildcards." ;
1005 static const struct command_def cmd_transform_def = {
1006 .name = "transform",
1007 .opts = cmd_transform_opts,
1008 .handler = cmd_transform,
1009 .synopsis = "add a file transform",
1010 .help = cmd_transform_help
1013 static void cmd_save(struct command *cmd) {
1015 r = aug_save(cmd->aug);
1017 ERR_REPORT(cmd, AUG_ECMDRUN,
1018 "saving failed (run 'errors' for details)");
1020 r = aug_match(cmd->aug, "/augeas/events/saved", NULL);
1022 fprintf(cmd->out, "Saved %d file(s)\n", r);
1027 static const struct command_opt_def cmd_save_opts[] = {
1031 static const struct command_def cmd_save_def = {
1033 .opts = cmd_save_opts,
1034 .handler = cmd_save,
1035 .synopsis = "save all pending changes",
1036 .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"
1039 static void cmd_load(struct command *cmd) {
1041 r = aug_load(cmd->aug);
1043 ERR_REPORT(cmd, AUG_ECMDRUN,
1044 "loading failed (run 'errors' for details)");
1048 static const struct command_opt_def cmd_load_opts[] = {
1052 static const struct command_def cmd_load_def = {
1054 .opts = cmd_load_opts,
1055 .handler = cmd_load,
1056 .synopsis = "(re)load files under /files",
1057 .help = "Load files according to the transforms in /augeas/load. "
1058 "A transform\n Foo is represented with a subtree /augeas/load/Foo."
1059 " Underneath\n /augeas/load/Foo, one node labelled 'lens' must exist,"
1060 " whose value is\n the fully qualified name of a lens, for example "
1061 "'Foo.lns', and\n multiple nodes 'incl' and 'excl' whose values are "
1062 "globs that determine\n which files are transformed by that lens. It "
1063 "is an error if one file\n can be processed by multiple transforms."
1066 static void cmd_ins(struct command *cmd) {
1067 const char *label = arg_value(cmd, "label");
1068 const char *where = arg_value(cmd, "where");
1069 const char *path = arg_value(cmd, "path");
1072 if (STREQ(where, "after"))
1074 else if (STREQ(where, "before"))
1077 ERR_REPORT(cmd, AUG_ECMDRUN,
1078 "the <WHERE> argument for ins must be either 'before' or 'after'.");
1082 aug_insert(cmd->aug, path, label, before);
1085 static const struct command_opt_def cmd_ins_opts[] = {
1086 { .type = CMD_STR, .name = "label", .optional = false,
1087 .help = "the label for the new node" },
1088 { .type = CMD_STR, .name = "where", .optional = false,
1089 .help = "either 'before' or 'after'" },
1090 { .type = CMD_PATH, .name = "path", .optional = false,
1091 .help = "the node before/after which to insert" },
1095 static const char const cmd_ins_help[] =
1096 "Insert a new node with label LABEL right before or after "
1097 "PATH into the\n tree. WHERE must be either 'before' or 'after'.";
1099 static const struct command_def cmd_ins_def = {
1101 .opts = cmd_ins_opts,
1103 .synopsis = "insert new node",
1104 .help = cmd_ins_help
1107 static const struct command_def cmd_insert_def = {
1109 .opts = cmd_ins_opts,
1111 .synopsis = "insert new node (alias of 'ins')",
1112 .help = cmd_ins_help
1115 static void cmd_store(struct command *cmd) {
1116 const char *lens = arg_value(cmd, "lens");
1117 const char *path = arg_value(cmd, "path");
1118 const char *node = arg_value(cmd, "node");
1120 aug_text_store(cmd->aug, lens, node, path);
1123 static const struct command_opt_def cmd_store_opts[] = {
1124 { .type = CMD_STR, .name = "lens", .optional = false,
1125 .help = "the name of the lens" },
1126 { .type = CMD_PATH, .name = "node", .optional = false,
1127 .help = "where to find the input text" },
1128 { .type = CMD_PATH, .name = "path", .optional = false,
1129 .help = "where to store parsed text" },
1133 static const char const cmd_store_help[] =
1134 "Parse NODE using LENS and store the resulting tree at PATH.";
1136 static const struct command_def cmd_store_def = {
1138 .opts = cmd_store_opts,
1139 .handler = cmd_store,
1140 .synopsis = "parse text into tree",
1141 .help = cmd_store_help
1144 static void cmd_retrieve(struct command *cmd) {
1145 const char *lens = arg_value(cmd, "lens");
1146 const char *node_in = arg_value(cmd, "node_in");
1147 const char *path = arg_value(cmd, "path");
1148 const char *node_out = arg_value(cmd, "node_out");
1150 aug_text_retrieve(cmd->aug, lens, node_in, path, node_out);
1153 static const struct command_opt_def cmd_retrieve_opts[] = {
1154 { .type = CMD_STR, .name = "lens", .optional = false,
1155 .help = "the name of the lens" },
1156 { .type = CMD_PATH, .name = "node_in", .optional = false,
1157 .help = "the node containing the initial text (path expression)" },
1158 { .type = CMD_PATH, .name = "path", .optional = false,
1159 .help = "the tree to transform (path expression)" },
1160 { .type = CMD_PATH, .name = "node_out", .optional = false,
1161 .help = "where to store the resulting text (path expression)" },
1165 static const char const cmd_retrieve_help[] =
1166 "Transform tree at PATH back into text using lens LENS and store the\n"
1167 " resulting string at NODE_OUT. Assume that the tree was initially read in\n"
1168 " with the same lens and the string stored at NODE_IN as input.";
1170 static const struct command_def cmd_retrieve_def = {
1172 .opts = cmd_retrieve_opts,
1173 .handler = cmd_retrieve,
1174 .synopsis = "transform tree into text",
1175 .help = cmd_retrieve_help
1178 /* Given a path "/augeas/files/FILENAME/error", return FILENAME */
1179 static char *err_filename(const char *match) {
1180 int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
1181 if (strlen(match) < noise + 1)
1183 return strndup(match + strlen(AUGEAS_META_FILES), strlen(match) - noise);
1185 return strdup("(no filename)");
1188 static const char *err_get(struct augeas *aug,
1189 const char *match, const char *child) {
1191 const char *value = "";
1194 r = pathjoin(&path, 2, match, child);
1195 ERR_NOMEM(r < 0, aug);
1197 aug_get(aug, path, &value);
1205 static void cmd_errors(struct command *cmd) {
1206 char **matches = NULL;
1208 char *filename = NULL;
1209 struct augeas *aug = cmd->aug;
1211 cnt = aug_match(aug, "/augeas//error", &matches);
1213 ERR_THROW(cnt < 0, aug, AUG_ECMDRUN,
1214 " (problem retrieving error messages)\n");
1216 fprintf(cmd->out, " (no errors)\n");
1220 for (int i=0; i < cnt; i++) {
1221 const char *match = matches[i];
1222 const char *line = err_get(aug, match, "line");
1223 const char *char_pos = err_get(aug, match, "char");
1224 const char *lens = err_get(aug, match, "lens");
1225 const char *last = err_get(aug, match, "lens/last_matched");
1226 const char *next = err_get(aug, match, "lens/next_not_matched");
1227 const char *msg = err_get(aug, match, "message");
1228 const char *path = err_get(aug, match, "path");
1229 const char *kind = NULL;
1231 aug_get(aug, match, &kind);
1234 filename = err_filename(match);
1235 ERR_NOMEM(filename == NULL, aug);
1238 fprintf(cmd->out, "\n");
1241 fprintf(cmd->out, "Error in %s:%s.%s (%s)\n",
1242 filename, line, char_pos, kind);
1243 } else if (path != NULL) {
1244 fprintf(cmd->out, "Error in %s at node %s (%s)\n", filename, path, kind);
1246 fprintf(cmd->out, "Error in %s (%s)\n", filename, kind);
1250 fprintf(cmd->out, " %s\n", msg);
1252 fprintf(cmd->out, " Lens: %s\n", lens);
1254 fprintf(cmd->out, " Last matched: %s\n", last);
1256 fprintf(cmd->out, " Next (no match): %s\n", next);
1261 for (int i=0; i < cnt; i++)
1267 static const struct command_opt_def cmd_errors_opts[] = {
1271 static const char const cmd_errors_help[] =
1272 "Show all the errors encountered in processing files. For each error,\n"
1273 " print detailed information about where it happened and how. The same\n"
1274 " information can be retrieved by running 'print /augeas//error'\n\n"
1275 " For each error, the file in which the error occurred together with the\n"
1276 " line number and position in that line is shown, as well as information\n"
1277 " about the lens that encountered the error. For some errors, the last\n"
1278 " lens that matched successfully and the next lens that should have\n"
1279 " matched but didn't are also shown\n";
1281 static const struct command_def cmd_errors_def = {
1283 .opts = cmd_errors_opts,
1284 .handler = cmd_errors,
1285 .synopsis = "show all errors encountered in processing files",
1286 .help = cmd_errors_help
1289 /* Groups of commands */
1290 static const struct command_grp_def cmd_grp_admin_def = {
1304 static const struct command_grp_def cmd_grp_read_def = {
1319 static const struct command_grp_def cmd_grp_write_def = {
1339 static const struct command_grp_def cmd_grp_pathx_def = {
1340 .name = "Path expression",
1348 static const struct command_grp_def const *cmd_groups[] = {
1356 static const struct command_def *lookup_cmd_def(const char *name) {
1357 for (int i = 0; cmd_groups[i]->name != NULL; i++) {
1358 for (int j = 0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1359 if (STREQ(name, cmd_groups[i]->commands[j]->name))
1360 return cmd_groups[i]->commands[j];
1366 static void cmd_help(struct command *cmd) {
1367 const char *name = arg_value(cmd, "command");
1371 //fprintf(cmd->out, "Commands:\n\n");
1372 fprintf(cmd->out, "\n");
1373 for (int i=0; cmd_groups[i]->name != NULL; i++) {
1374 fprintf(cmd->out, "%s commands:\n", cmd_groups[i]->name);
1375 for (int j=0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1376 const struct command_def *def = cmd_groups[i]->commands[j];
1377 fprintf(cmd->out, " %-10s - %s\n", def->name, def->synopsis);
1379 fprintf(cmd->out, "\n");
1382 "Type 'help <command>' for more information on a command\n\n");
1384 const struct command_def *def = lookup_cmd_def(name);
1385 const struct command_opt_def *odef = NULL;
1387 ERR_THROW(def == NULL, cmd->aug, AUG_ECMDRUN,
1388 "unknown command %s\n", name);
1389 fprintf(cmd->out, " COMMAND\n");
1390 fprintf(cmd->out, " %s - %s\n\n", name, def->synopsis);
1391 fprintf(cmd->out, " SYNOPSIS\n");
1392 fprintf(cmd->out, " %s", name);
1394 for (odef = def->opts; odef->name != NULL; odef++) {
1395 format_defname(buf, odef, true);
1396 fprintf(cmd->out, "%s", buf);
1398 fprintf(cmd->out, "\n\n");
1399 fprintf(cmd->out, " DESCRIPTION\n");
1400 format_desc(def->help);
1401 if (def->opts->name != NULL) {
1402 fprintf(cmd->out, " OPTIONS\n");
1403 for (odef = def->opts; odef->name != NULL; odef++) {
1404 const char *help = odef->help;
1407 format_defname(buf, odef, false);
1408 fprintf(cmd->out, " %-10s %s\n", buf, help);
1411 fprintf(cmd->out, "\n");
1417 int aug_srun(augeas *aug, FILE *out, const char *text) {
1430 cmd.error = aug->error;
1433 while (*text != '\0' && result >= 0) {
1434 eol = strchrnul(text, '\n');
1435 while (isspace(*text) && text < eol) text++;
1438 if (*text == '#' || text == eol) {
1439 text = (*eol == '\0') ? eol : eol + 1;
1443 line = strndup(text, eol - text);
1444 ERR_NOMEM(line == NULL, aug);
1446 if (parseline(&cmd, line) == 0) {
1447 cmd.def->handler(&cmd);
1454 if (result >= 0 && cmd.quit) {
1459 free_command_opts(&cmd);
1461 text = (*eol == '\0') ? eol : eol + 1;
1475 * indent-tabs-mode: nil