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_load_file(struct command *cmd) {
1014 const char *file = arg_value(cmd, "file");
1017 r = aug_load_file(cmd->aug, file);
1019 ERR_REPORT(cmd, AUG_ECMDRUN,
1020 "Failed to load file %s", file);
1023 static const struct command_opt_def cmd_load_file_opts[] = {
1024 { .type = CMD_PATH, .name = "file", .optional = false,
1025 .help = "the file to load" },
1029 static const char const cmd_load_file_help[] =
1030 "Load a specific FILE, using autoload statements.\n";
1032 static const struct command_def cmd_load_file_def = {
1033 .name = "load-file",
1034 .opts = cmd_load_file_opts,
1035 .handler = cmd_load_file,
1036 .synopsis = "load a specific file",
1037 .help = cmd_load_file_help
1040 static void cmd_save(struct command *cmd) {
1042 r = aug_save(cmd->aug);
1044 ERR_REPORT(cmd, AUG_ECMDRUN,
1045 "saving failed (run 'errors' for details)");
1047 r = aug_match(cmd->aug, "/augeas/events/saved", NULL);
1049 fprintf(cmd->out, "Saved %d file(s)\n", r);
1054 static const struct command_opt_def cmd_save_opts[] = {
1058 static const struct command_def cmd_save_def = {
1060 .opts = cmd_save_opts,
1061 .handler = cmd_save,
1062 .synopsis = "save all pending changes",
1063 .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"
1066 static void cmd_load(struct command *cmd) {
1068 r = aug_load(cmd->aug);
1070 ERR_REPORT(cmd, AUG_ECMDRUN,
1071 "loading failed (run 'errors' for details)");
1075 static const struct command_opt_def cmd_load_opts[] = {
1079 static const struct command_def cmd_load_def = {
1081 .opts = cmd_load_opts,
1082 .handler = cmd_load,
1083 .synopsis = "(re)load files under /files",
1084 .help = "Load files according to the transforms in /augeas/load. "
1085 "A transform\n Foo is represented with a subtree /augeas/load/Foo."
1086 " Underneath\n /augeas/load/Foo, one node labelled 'lens' must exist,"
1087 " whose value is\n the fully qualified name of a lens, for example "
1088 "'Foo.lns', and\n multiple nodes 'incl' and 'excl' whose values are "
1089 "globs that determine\n which files are transformed by that lens. It "
1090 "is an error if one file\n can be processed by multiple transforms."
1093 static void cmd_ins(struct command *cmd) {
1094 const char *label = arg_value(cmd, "label");
1095 const char *where = arg_value(cmd, "where");
1096 const char *path = arg_value(cmd, "path");
1099 if (STREQ(where, "after"))
1101 else if (STREQ(where, "before"))
1104 ERR_REPORT(cmd, AUG_ECMDRUN,
1105 "the <WHERE> argument for ins must be either 'before' or 'after'.");
1109 aug_insert(cmd->aug, path, label, before);
1112 static const struct command_opt_def cmd_ins_opts[] = {
1113 { .type = CMD_STR, .name = "label", .optional = false,
1114 .help = "the label for the new node" },
1115 { .type = CMD_STR, .name = "where", .optional = false,
1116 .help = "either 'before' or 'after'" },
1117 { .type = CMD_PATH, .name = "path", .optional = false,
1118 .help = "the node before/after which to insert" },
1122 static const char const cmd_ins_help[] =
1123 "Insert a new node with label LABEL right before or after "
1124 "PATH into the\n tree. WHERE must be either 'before' or 'after'.";
1126 static const struct command_def cmd_ins_def = {
1128 .opts = cmd_ins_opts,
1130 .synopsis = "insert new node",
1131 .help = cmd_ins_help
1134 static const struct command_def cmd_insert_def = {
1136 .opts = cmd_ins_opts,
1138 .synopsis = "insert new node (alias of 'ins')",
1139 .help = cmd_ins_help
1142 static void cmd_store(struct command *cmd) {
1143 const char *lens = arg_value(cmd, "lens");
1144 const char *path = arg_value(cmd, "path");
1145 const char *node = arg_value(cmd, "node");
1147 aug_text_store(cmd->aug, lens, node, path);
1150 static const struct command_opt_def cmd_store_opts[] = {
1151 { .type = CMD_STR, .name = "lens", .optional = false,
1152 .help = "the name of the lens" },
1153 { .type = CMD_PATH, .name = "node", .optional = false,
1154 .help = "where to find the input text" },
1155 { .type = CMD_PATH, .name = "path", .optional = false,
1156 .help = "where to store parsed text" },
1160 static const char const cmd_store_help[] =
1161 "Parse NODE using LENS and store the resulting tree at PATH.";
1163 static const struct command_def cmd_store_def = {
1165 .opts = cmd_store_opts,
1166 .handler = cmd_store,
1167 .synopsis = "parse text into tree",
1168 .help = cmd_store_help
1171 static void cmd_retrieve(struct command *cmd) {
1172 const char *lens = arg_value(cmd, "lens");
1173 const char *node_in = arg_value(cmd, "node_in");
1174 const char *path = arg_value(cmd, "path");
1175 const char *node_out = arg_value(cmd, "node_out");
1177 aug_text_retrieve(cmd->aug, lens, node_in, path, node_out);
1180 static const struct command_opt_def cmd_retrieve_opts[] = {
1181 { .type = CMD_STR, .name = "lens", .optional = false,
1182 .help = "the name of the lens" },
1183 { .type = CMD_PATH, .name = "node_in", .optional = false,
1184 .help = "the node containing the initial text (path expression)" },
1185 { .type = CMD_PATH, .name = "path", .optional = false,
1186 .help = "the tree to transform (path expression)" },
1187 { .type = CMD_PATH, .name = "node_out", .optional = false,
1188 .help = "where to store the resulting text (path expression)" },
1192 static const char const cmd_retrieve_help[] =
1193 "Transform tree at PATH back into text using lens LENS and store the\n"
1194 " resulting string at NODE_OUT. Assume that the tree was initially read in\n"
1195 " with the same lens and the string stored at NODE_IN as input.";
1197 static const struct command_def cmd_retrieve_def = {
1199 .opts = cmd_retrieve_opts,
1200 .handler = cmd_retrieve,
1201 .synopsis = "transform tree into text",
1202 .help = cmd_retrieve_help
1205 /* Given a path "/augeas/files/FILENAME/error", return FILENAME */
1206 static char *err_filename(const char *match) {
1207 int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
1208 if (strlen(match) < noise + 1)
1210 return strndup(match + strlen(AUGEAS_META_FILES), strlen(match) - noise);
1212 return strdup("(no filename)");
1215 static const char *err_get(struct augeas *aug,
1216 const char *match, const char *child) {
1218 const char *value = "";
1221 r = pathjoin(&path, 2, match, child);
1222 ERR_NOMEM(r < 0, aug);
1224 aug_get(aug, path, &value);
1232 static void cmd_errors(struct command *cmd) {
1233 char **matches = NULL;
1235 char *filename = NULL;
1236 struct augeas *aug = cmd->aug;
1238 cnt = aug_match(aug, "/augeas//error", &matches);
1240 ERR_THROW(cnt < 0, aug, AUG_ECMDRUN,
1241 " (problem retrieving error messages)\n");
1243 fprintf(cmd->out, " (no errors)\n");
1247 for (int i=0; i < cnt; i++) {
1248 const char *match = matches[i];
1249 const char *line = err_get(aug, match, "line");
1250 const char *char_pos = err_get(aug, match, "char");
1251 const char *lens = err_get(aug, match, "lens");
1252 const char *last = err_get(aug, match, "lens/last_matched");
1253 const char *next = err_get(aug, match, "lens/next_not_matched");
1254 const char *msg = err_get(aug, match, "message");
1255 const char *path = err_get(aug, match, "path");
1256 const char *kind = NULL;
1258 aug_get(aug, match, &kind);
1261 filename = err_filename(match);
1262 ERR_NOMEM(filename == NULL, aug);
1265 fprintf(cmd->out, "\n");
1268 fprintf(cmd->out, "Error in %s:%s.%s (%s)\n",
1269 filename, line, char_pos, kind);
1270 } else if (path != NULL) {
1271 fprintf(cmd->out, "Error in %s at node %s (%s)\n", filename, path, kind);
1273 fprintf(cmd->out, "Error in %s (%s)\n", filename, kind);
1277 fprintf(cmd->out, " %s\n", msg);
1279 fprintf(cmd->out, " Lens: %s\n", lens);
1281 fprintf(cmd->out, " Last matched: %s\n", last);
1283 fprintf(cmd->out, " Next (no match): %s\n", next);
1288 for (int i=0; i < cnt; i++)
1294 static const struct command_opt_def cmd_errors_opts[] = {
1298 static const char const cmd_errors_help[] =
1299 "Show all the errors encountered in processing files. For each error,\n"
1300 " print detailed information about where it happened and how. The same\n"
1301 " information can be retrieved by running 'print /augeas//error'\n\n"
1302 " For each error, the file in which the error occurred together with the\n"
1303 " line number and position in that line is shown, as well as information\n"
1304 " about the lens that encountered the error. For some errors, the last\n"
1305 " lens that matched successfully and the next lens that should have\n"
1306 " matched but didn't are also shown\n";
1308 static const struct command_def cmd_errors_def = {
1310 .opts = cmd_errors_opts,
1311 .handler = cmd_errors,
1312 .synopsis = "show all errors encountered in processing files",
1313 .help = cmd_errors_help
1316 /* Groups of commands */
1317 static const struct command_grp_def cmd_grp_admin_def = {
1332 static const struct command_grp_def cmd_grp_read_def = {
1347 static const struct command_grp_def cmd_grp_write_def = {
1367 static const struct command_grp_def cmd_grp_pathx_def = {
1368 .name = "Path expression",
1376 static const struct command_grp_def const *cmd_groups[] = {
1384 static const struct command_def *lookup_cmd_def(const char *name) {
1385 for (int i = 0; cmd_groups[i]->name != NULL; i++) {
1386 for (int j = 0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1387 if (STREQ(name, cmd_groups[i]->commands[j]->name))
1388 return cmd_groups[i]->commands[j];
1394 static void cmd_help(struct command *cmd) {
1395 const char *name = arg_value(cmd, "command");
1399 //fprintf(cmd->out, "Commands:\n\n");
1400 fprintf(cmd->out, "\n");
1401 for (int i=0; cmd_groups[i]->name != NULL; i++) {
1402 fprintf(cmd->out, "%s commands:\n", cmd_groups[i]->name);
1403 for (int j=0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1404 const struct command_def *def = cmd_groups[i]->commands[j];
1405 fprintf(cmd->out, " %-10s - %s\n", def->name, def->synopsis);
1407 fprintf(cmd->out, "\n");
1410 "Type 'help <command>' for more information on a command\n\n");
1412 const struct command_def *def = lookup_cmd_def(name);
1413 const struct command_opt_def *odef = NULL;
1415 ERR_THROW(def == NULL, cmd->aug, AUG_ECMDRUN,
1416 "unknown command %s\n", name);
1417 fprintf(cmd->out, " COMMAND\n");
1418 fprintf(cmd->out, " %s - %s\n\n", name, def->synopsis);
1419 fprintf(cmd->out, " SYNOPSIS\n");
1420 fprintf(cmd->out, " %s", name);
1422 for (odef = def->opts; odef->name != NULL; odef++) {
1423 format_defname(buf, odef, true);
1424 fprintf(cmd->out, "%s", buf);
1426 fprintf(cmd->out, "\n\n");
1427 fprintf(cmd->out, " DESCRIPTION\n");
1428 format_desc(def->help);
1429 if (def->opts->name != NULL) {
1430 fprintf(cmd->out, " OPTIONS\n");
1431 for (odef = def->opts; odef->name != NULL; odef++) {
1432 const char *help = odef->help;
1435 format_defname(buf, odef, false);
1436 fprintf(cmd->out, " %-10s %s\n", buf, help);
1439 fprintf(cmd->out, "\n");
1445 int aug_srun(augeas *aug, FILE *out, const char *text) {
1458 cmd.error = aug->error;
1461 while (*text != '\0' && result >= 0) {
1462 eol = strchrnul(text, '\n');
1463 while (isspace(*text) && text < eol) text++;
1466 if (*text == '#' || text == eol) {
1467 text = (*eol == '\0') ? eol : eol + 1;
1471 line = strndup(text, eol - text);
1472 ERR_NOMEM(line == NULL, aug);
1474 if (parseline(&cmd, line) == 0) {
1475 cmd.def->handler(&cmd);
1482 if (result >= 0 && cmd.quit) {
1487 free_command_opts(&cmd);
1489 text = (*eol == '\0') ? eol : eol + 1;
1503 * indent-tabs-mode: nil