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 const *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 */
154 case '"': /* pass both through if opposite quote, else fall */
155 if (quot && quot != *(s+1)) break;
156 case '\\': /* pass next character through */
161 ERR_REPORT(cmd, AUG_ECMDRUN, "unknown escape sequence");
167 if (*s == '[') nbracket += 1;
168 if (*s == ']') nbracket -= 1;
170 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
174 if (!path || nbracket == 0) {
175 if (!quot && (*s == '\'' || *s == '"')) {
178 } else if (quot && *s == quot) {
183 if (!quot && isblank(*s))
196 if (*s == '\0' && path && nbracket > 0) {
197 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched [");
200 if (*s == '\0' && quot) {
201 ERR_REPORT(cmd, AUG_ECMDRUN, "unmatched %c", quot);
210 static struct command_opt *
211 make_command_opt(struct command *cmd, const struct command_opt_def *def) {
212 struct command_opt *copt = NULL;
216 ERR_NOMEM(r < 0, cmd->aug);
218 list_append(cmd->opt, copt);
223 static void free_command_opts(struct command *cmd) {
224 struct command_opt *next;
227 while (next != NULL) {
228 struct command_opt *del = next;
235 static int parseline(struct command *cmd, char *line) {
237 int narg = 0, nopt = 0;
238 const struct command_opt_def *def;
240 tok = nexttoken(cmd, &line, false);
243 cmd->def = lookup_cmd_def(tok);
244 if (cmd->def == NULL) {
245 ERR_REPORT(cmd, AUG_ECMDRUN, "Unknown command '%s'", tok);
249 for (def = cmd->def->opts; def->name != NULL; def++) {
256 def = cmd->def->opts;
257 while (*line != '\0') {
258 while (*line && isblank(*line)) line += 1;
260 if (curarg >= narg) {
261 ERR_REPORT(cmd, AUG_ECMDRUN,
262 "Too many arguments. Command %s takes only %d arguments",
263 cmd->def->name, narg);
267 struct command_opt *opt = make_command_opt(cmd, def);
271 if (def->type == CMD_PATH) {
272 tok = nexttoken(cmd, &line, true);
275 tok = nexttoken(cmd, &line, false);
282 while (*line && isblank(*line)) line += 1;
285 if (curarg < narg - nopt) {
286 ERR_REPORT(cmd, AUG_ECMDRUN, "Not enough arguments for %s", cmd->def->name);
296 static void format_desc(const char *d) {
298 for (const char *s = d; *s; s++) {
307 static void format_defname(char *buf, const struct command_opt_def *def,
308 bool mark_optional) {
310 if (mark_optional && def->optional)
311 p = stpcpy(buf, " [<");
313 p = stpcpy(buf, " <");
314 for (int i=0; i < strlen(def->name); i++)
315 *p++ = toupper(def->name[i]);
317 if (mark_optional && def->optional)
322 static void cmd_help(struct command *cmd);
324 static const struct command_opt_def cmd_help_opts[] = {
325 { .type = CMD_STR, .name = "command", .optional = true,
326 .help = "print help for this command only" },
330 static const struct command_def cmd_help_def = {
332 .opts = cmd_help_opts,
334 .synopsis = "print help",
335 .help = "list all commands or print details about one command"
338 static void cmd_quit(ATTRIBUTE_UNUSED struct command *cmd) {
342 static const struct command_opt_def cmd_quit_opts[] = {
346 static const struct command_def cmd_quit_def = {
348 .opts = cmd_quit_opts,
350 .synopsis = "exit the program",
351 .help = "Exit the program"
354 static char *ls_pattern(struct command *cmd, const char *path) {
358 if (path[strlen(path)-1] == SEP)
359 r = xasprintf(&q, "%s*", path);
361 r = xasprintf(&q, "%s/*", path);
362 ERR_NOMEM(r < 0, cmd->aug);
367 static int child_count(struct command *cmd, const char *path) {
368 char *q = ls_pattern(cmd, path);
373 cnt = aug_match(cmd->aug, q, NULL);
380 static void cmd_ls(struct command *cmd) {
385 path = ls_pattern(cmd, arg_value(cmd, "path"));
388 cnt = aug_match(cmd->aug, path, &paths);
390 for (int i=0; i < cnt; i++) {
392 const char *basnam = strrchr(paths[i], SEP);
393 int dir = child_count(cmd, paths[i]);
394 aug_get(cmd->aug, paths[i], &val);
396 basnam = (basnam == NULL) ? paths[i] : basnam + 1;
399 fprintf(cmd->out, "%s%s= %s\n", basnam, dir ? "/ " : " ", val);
404 for (int i=0; i < cnt; i++)
409 static const struct command_opt_def cmd_ls_opts[] = {
410 { .type = CMD_PATH, .name = "path", .optional = false,
411 .help = "the node whose children to list" },
415 static const struct command_def cmd_ls_def = {
419 .synopsis = "list children of a node",
420 .help = "list the direct children of a node"
423 static void cmd_match(struct command *cmd) {
425 const char *pattern = arg_value(cmd, "path");
426 const char *value = arg_value(cmd, "value");
427 char **matches = NULL;
428 bool filter = (value != NULL) && (strlen(value) > 0);
430 cnt = aug_match(cmd->aug, pattern, &matches);
432 ERR_THROW(cnt < 0, cmd->aug, AUG_ECMDRUN,
433 " (error matching %s)\n", pattern);
435 fprintf(cmd->out, " (no matches)\n");
439 for (int i=0; i < cnt; i++) {
441 aug_get(cmd->aug, matches[i], &val);
446 if (STREQ(value, val))
447 fprintf(cmd->out, "%s\n", matches[i]);
449 fprintf(cmd->out, "%s = %s\n", matches[i], val);
454 for (int i=0; i < cnt; i++)
459 static const struct command_opt_def cmd_match_opts[] = {
460 { .type = CMD_PATH, .name = "path", .optional = false,
461 .help = "the path expression to match" },
462 { .type = CMD_STR, .name = "value", .optional = true,
463 .help = "only show matches with this value" },
467 static const struct command_def cmd_match_def = {
469 .opts = cmd_match_opts,
470 .handler = cmd_match,
471 .synopsis = "print matches for a path expression",
472 .help = "Find all paths that match the path expression PATH. "
473 "If VALUE is given,\n only the matching paths whose value equals "
477 static void cmd_rm(struct command *cmd) {
479 const char *path = arg_value(cmd, "path");
480 cnt = aug_rm(cmd->aug, path);
482 fprintf(cmd->out, "rm : %s %d\n", path, cnt);
485 static const struct command_opt_def cmd_rm_opts[] = {
486 { .type = CMD_PATH, .name = "path", .optional = false,
487 .help = "remove all nodes matching this path expression" },
491 static const struct command_def cmd_rm_def = {
495 .synopsis = "delete nodes and subtrees",
496 .help = "Delete PATH and all its children from the tree"
499 static void cmd_mv(struct command *cmd) {
500 const char *src = arg_value(cmd, "src");
501 const char *dst = arg_value(cmd, "dst");
504 r = aug_mv(cmd->aug, src, dst);
506 ERR_REPORT(cmd, AUG_ECMDRUN,
507 "Moving %s to %s failed", src, dst);
510 static const struct command_opt_def cmd_mv_opts[] = {
511 { .type = CMD_PATH, .name = "src", .optional = false,
512 .help = "the tree to move" },
513 { .type = CMD_PATH, .name = "dst", .optional = false,
514 .help = "where to put the source tree" },
518 static const char const cmd_mv_help[] =
519 "Move node SRC to DST. SRC must match exactly one node in "
520 "the tree.\n DST must either match exactly one node in the tree, "
521 "or may not\n exist yet. If DST exists already, it and all its "
522 "descendants are\n deleted. If DST does not exist yet, it and "
523 "all its missing\n ancestors are created.";
525 static const struct command_def cmd_mv_def = {
529 .synopsis = "move a subtree",
533 static const struct command_def cmd_move_def = {
537 .synopsis = "move a subtree (alias of 'mv')",
541 static void cmd_cp(struct command *cmd) {
542 const char *src = arg_value(cmd, "src");
543 const char *dst = arg_value(cmd, "dst");
546 r = aug_cp(cmd->aug, src, dst);
548 ERR_REPORT(cmd, AUG_ECMDRUN,
549 "Copying %s to %s failed", src, dst);
552 static const struct command_opt_def cmd_cp_opts[] = {
553 { .type = CMD_PATH, .name = "src", .optional = false,
554 .help = "the tree to copy" },
555 { .type = CMD_PATH, .name = "dst", .optional = false,
556 .help = "where to copy the source tree" },
560 static const char const cmd_cp_help[] =
561 "Copy node SRC to DST. SRC must match exactly one node in "
562 "the tree.\n DST must either match exactly one node in the tree, "
563 "or may not\n exist yet. If DST exists already, it and all its "
564 "descendants are\n deleted. If DST does not exist yet, it and "
565 "all its missing\n ancestors are created.";
567 static const struct command_def cmd_cp_def = {
571 .synopsis = "copy a subtree",
575 static const struct command_def cmd_copy_def = {
579 .synopsis = "copy a subtree (alias of 'cp')",
583 static void cmd_rename(struct command *cmd) {
584 const char *src = arg_value(cmd, "src");
585 const char *lbl = arg_value(cmd, "lbl");
588 cnt = aug_rename(cmd->aug, src, lbl);
590 ERR_REPORT(cmd, AUG_ECMDRUN,
591 "Renaming %s to %s failed", src, lbl);
593 fprintf(cmd->out, "rename : %s to %s %d\n", src, lbl, cnt);
596 static const struct command_opt_def cmd_rename_opts[] = {
597 { .type = CMD_PATH, .name = "src", .optional = false,
598 .help = "the tree to rename" },
599 { .type = CMD_STR, .name = "lbl", .optional = false,
600 .help = "the new label" },
604 static const char const cmd_rename_help[] =
605 "Rename the label of all nodes matching SRC to LBL.";
607 static const struct command_def cmd_rename_def = {
609 .opts = cmd_rename_opts,
610 .handler = cmd_rename,
611 .synopsis = "rename a subtree label",
612 .help = cmd_rename_help
615 static void cmd_set(struct command *cmd) {
616 const char *path = arg_value(cmd, "path");
617 const char *val = arg_value(cmd, "value");
620 r = aug_set(cmd->aug, path, val);
622 ERR_REPORT(cmd, AUG_ECMDRUN, "Setting %s failed", path);
625 static const struct command_opt_def cmd_set_opts[] = {
626 { .type = CMD_PATH, .name = "path", .optional = false,
627 .help = "set the value of this node" },
628 { .type = CMD_STR, .name = "value", .optional = true,
629 .help = "the new value for the node" },
633 static const struct command_def cmd_set_def = {
635 .opts = cmd_set_opts,
637 .synopsis = "set the value of a node",
638 .help = "Associate VALUE with PATH. If PATH is not in the tree yet, "
639 "it and all\n its ancestors will be created. These new tree entries "
640 "will appear last\n amongst their siblings"
643 static void cmd_setm(struct command *cmd) {
644 const char *base = arg_value(cmd, "base");
645 const char *sub = arg_value(cmd, "sub");
646 const char *val = arg_value(cmd, "value");
648 aug_setm(cmd->aug, base, sub, val);
651 static const struct command_opt_def cmd_setm_opts[] = {
652 { .type = CMD_PATH, .name = "base", .optional = false,
653 .help = "the base node" },
654 { .type = CMD_PATH, .name = "sub", .optional = false,
655 .help = "the subtree relative to the base" },
656 { .type = CMD_STR, .name = "value", .optional = true,
657 .help = "the value for the nodes" },
661 static const struct command_def cmd_setm_def = {
663 .opts = cmd_setm_opts,
665 .synopsis = "set the value of multiple nodes",
666 .help = "Set multiple nodes in one operation. Find or create a node"
667 " matching SUB\n by interpreting SUB as a path expression relative"
668 " to each node matching\n BASE. If SUB is '.', the nodes matching "
669 "BASE will be modified."
672 static void cmd_clearm(struct command *cmd) {
673 const char *base = arg_value(cmd, "base");
674 const char *sub = arg_value(cmd, "sub");
676 aug_setm(cmd->aug, base, sub, NULL);
679 static const struct command_opt_def cmd_clearm_opts[] = {
680 { .type = CMD_PATH, .name = "base", .optional = false,
681 .help = "the base node" },
682 { .type = CMD_PATH, .name = "sub", .optional = false,
683 .help = "the subtree relative to the base" },
687 static const struct command_def cmd_clearm_def = {
689 .opts = cmd_clearm_opts,
690 .handler = cmd_clearm,
691 .synopsis = "clear the value of multiple nodes",
692 .help = "Clear multiple nodes values in one operation. Find or create a"
693 " node matching SUB\n by interpreting SUB as a path expression relative"
694 " to each node matching\n BASE. If SUB is '.', the nodes matching "
695 "BASE will be modified."
698 static void cmd_span(struct command *cmd) {
699 const char *path = arg_value(cmd, "path");
701 uint label_start, label_end, value_start, value_end, span_start, span_end;
702 char *filename = NULL;
703 const char *option = NULL;
705 if (aug_get(cmd->aug, AUGEAS_SPAN_OPTION, &option) != 1) {
706 printf("Error: option " AUGEAS_SPAN_OPTION " not found\n");
709 if (streqv(AUG_DISABLE, option)) {
710 ERR_REPORT(cmd, AUG_ECMDRUN,
711 "Span is not enabled. To enable, run the commands:\n"
712 " set %s %s\n rm %s\n load\n",
713 AUGEAS_SPAN_OPTION, AUG_ENABLE, AUGEAS_FILES_TREE);
715 } else if (! streqv(AUG_ENABLE, option)) {
716 ERR_REPORT(cmd, AUG_ECMDRUN,
717 "option %s must be %s or %s\n", AUGEAS_SPAN_OPTION,
718 AUG_ENABLE, AUG_DISABLE);
721 r = aug_span(cmd->aug, path, &filename, &label_start, &label_end,
722 &value_start, &value_end, &span_start, &span_end);
723 ERR_THROW(r == -1, cmd, AUG_ECMDRUN, "failed to retrieve span");
725 fprintf(cmd->out, "%s label=(%i:%i) value=(%i:%i) span=(%i,%i)\n",
726 filename, label_start, label_end,
727 value_start, value_end, span_start, span_end);
732 static const struct command_opt_def cmd_span_opts[] = {
733 { .type = CMD_PATH, .name = "path", .optional = false,
734 .help = "path matching exactly one node" },
738 static const struct command_def cmd_span_def = {
740 .opts = cmd_span_opts,
742 .synopsis = "print position in input file corresponding to tree",
743 .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."
746 static void cmd_defvar(struct command *cmd) {
747 const char *name = arg_value(cmd, "name");
748 const char *path = arg_value(cmd, "expr");
750 aug_defvar(cmd->aug, name, path);
753 static const struct command_opt_def cmd_defvar_opts[] = {
754 { .type = CMD_STR, .name = "name", .optional = false,
755 .help = "the name of the variable" },
756 { .type = CMD_PATH, .name = "expr", .optional = false,
757 .help = "the path expression" },
761 static const struct command_def cmd_defvar_def = {
763 .opts = cmd_defvar_opts,
764 .handler = cmd_defvar,
765 .synopsis = "set a variable",
766 .help = "Evaluate EXPR and set the variable NAME to the resulting "
767 "nodeset. The\n variable can be used in path expressions as $NAME. "
768 "Note that EXPR is\n evaluated when the variable is defined, not when "
772 static void cmd_defnode(struct command *cmd) {
773 const char *name = arg_value(cmd, "name");
774 const char *path = arg_value(cmd, "expr");
775 const char *value = arg_value(cmd, "value");
777 /* Make 'defnode foo ""' mean the same as 'defnode foo' */
778 if (value != NULL && strlen(value) == 0)
780 aug_defnode(cmd->aug, name, path, value, NULL);
783 static const struct command_opt_def cmd_defnode_opts[] = {
784 { .type = CMD_STR, .name = "name", .optional = false,
785 .help = "the name of the variable" },
786 { .type = CMD_PATH, .name = "expr", .optional = false,
787 .help = "the path expression" },
788 { .type = CMD_STR, .name = "value", .optional = true,
789 .help = "the value for the new node" },
793 static const struct command_def cmd_defnode_def = {
795 .opts = cmd_defnode_opts,
796 .handler = cmd_defnode,
797 .synopsis = "set a variable, possibly creating a new node",
798 .help = "Define the variable NAME to the result of evaluating EXPR, "
799 " which must\n be a nodeset. If no node matching EXPR exists yet, one "
800 "is created and\n NAME will refer to it. When a node is created and "
801 "VALUE is given, the\n new node's value is set to VALUE."
804 static void cmd_clear(struct command *cmd) {
805 const char *path = arg_value(cmd, "path");
808 r = aug_set(cmd->aug, path, NULL);
810 ERR_REPORT(cmd, AUG_ECMDRUN, "Clearing %s failed", path);
813 static const struct command_opt_def cmd_clear_opts[] = {
814 { .type = CMD_PATH, .name = "path", .optional = false,
815 .help = "clear the value of this node" },
819 static const struct command_def cmd_clear_def = {
821 .opts = cmd_clear_opts,
822 .handler = cmd_clear,
823 .synopsis = "clear the value of a node",
824 .help = "Set the value for PATH to NULL. If PATH is not in the tree yet, "
825 "it and\n all its ancestors will be created. These new tree entries "
826 "will appear\n last amongst their siblings"
829 static void cmd_touch(struct command *cmd) {
830 const char *path = arg_value(cmd, "path");
833 r = aug_match(cmd->aug, path, NULL);
835 r = aug_set(cmd->aug, path, NULL);
837 ERR_REPORT(cmd, AUG_ECMDRUN, "Touching %s failed", path);
841 static const struct command_opt_def cmd_touch_opts[] = {
842 { .type = CMD_PATH, .name = "path", .optional = false,
843 .help = "touch this node" },
847 static const struct command_def cmd_touch_def = {
849 .opts = cmd_touch_opts,
850 .handler = cmd_touch,
851 .synopsis = "create a new node",
852 .help = "Create PATH with the value NULL if it is not in the tree yet. "
853 "All its\n ancestors will also be created. These new tree entries will "
854 "appear\n last amongst their siblings."
857 static void cmd_get(struct command *cmd) {
858 const char *path = arg_value(cmd, "path");
862 r = aug_get(cmd->aug, path, &val);
864 fprintf(cmd->out, "%s", path);
866 fprintf(cmd->out, " (o)\n");
867 } else if (val == NULL) {
868 fprintf(cmd->out, " (none)\n");
870 fprintf(cmd->out, " = %s\n", val);
874 static const struct command_opt_def cmd_get_opts[] = {
875 { .type = CMD_PATH, .name = "path", .optional = false,
876 .help = "get the value of this node" },
880 static const struct command_def cmd_get_def = {
882 .opts = cmd_get_opts,
884 .synopsis = "get the value of a node",
885 .help = "Get and print the value associated with PATH"
888 static void cmd_label(struct command *cmd) {
889 const char *path = arg_value(cmd, "path");
893 r = aug_label(cmd->aug, path, &lbl);
895 fprintf(cmd->out, "%s", path);
897 fprintf(cmd->out, " (o)\n");
898 } else if (lbl == NULL) {
899 fprintf(cmd->out, " (none)\n");
901 fprintf(cmd->out, " = %s\n", lbl);
905 static const struct command_opt_def cmd_label_opts[] = {
906 { .type = CMD_PATH, .name = "path", .optional = false,
907 .help = "get the label of this node" },
911 static const struct command_def cmd_label_def = {
913 .opts = cmd_label_opts,
914 .handler = cmd_label,
915 .synopsis = "get the label of a node",
916 .help = "Get and print the label associated with PATH"
919 static void cmd_print(struct command *cmd) {
920 const char *path = arg_value(cmd, "path");
922 aug_print(cmd->aug, cmd->out, path);
925 static const struct command_opt_def cmd_print_opts[] = {
926 { .type = CMD_PATH, .name = "path", .optional = true,
927 .help = "print this subtree" },
931 static const struct command_def cmd_print_def = {
933 .opts = cmd_print_opts,
934 .handler = cmd_print,
935 .synopsis = "print a subtree",
936 .help = "Print entries in the tree. If PATH is given, printing starts there,\n otherwise the whole tree is printed"
939 static void cmd_source(struct command *cmd) {
940 const char *path = arg_value(cmd, "path");
941 char *file_path = NULL;
943 aug_source(cmd->aug, path, &file_path);
945 if (file_path != NULL) {
946 fprintf(cmd->out, "%s\n", file_path);
951 static const struct command_opt_def cmd_source_opts[] = {
952 { .type = CMD_PATH, .name = "path", .optional = false,
953 .help = "path to a single node" },
957 static const struct command_def cmd_source_def = {
959 .opts = cmd_source_opts,
960 .handler = cmd_source,
961 .synopsis = "print the file to which a node belongs",
962 .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."
965 static void cmd_context(struct command *cmd) {
966 const char *path = arg_value(cmd, "path");
969 aug_get(cmd->aug, "/augeas/context", &path);
972 fprintf(cmd->out, "/\n");
974 fprintf(cmd->out, "%s\n", path);
977 aug_set(cmd->aug, "/augeas/context", path);
982 static const struct command_opt_def cmd_context_opts[] = {
983 { .type = CMD_PATH, .name = "path", .optional = true,
984 .help = "new context for relative paths" },
988 static const struct command_def cmd_context_def = {
990 .opts = cmd_context_opts,
991 .handler = cmd_context,
992 .synopsis = "change how relative paths are interpreted",
993 .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'."
996 static void cmd_dump_xml(struct command *cmd) {
997 const char *path = arg_value(cmd, "path");
1001 r = aug_to_xml(cmd->aug, path, &xmldoc, 0);
1003 ERR_REPORT(cmd, AUG_ECMDRUN,
1004 "XML export of path %s failed", path);
1006 xmlElemDump(stdout, NULL, xmldoc);
1009 xmlFreeNode(xmldoc);
1012 static const struct command_opt_def cmd_dump_xml_opts[] = {
1013 { .type = CMD_PATH, .name = "path", .optional = true,
1014 .help = "print this subtree" },
1018 static const struct command_def cmd_dump_xml_def = {
1020 .opts = cmd_dump_xml_opts,
1021 .handler = cmd_dump_xml,
1022 .synopsis = "print a subtree as XML",
1023 .help = "Export entries in the tree as XML. If PATH is given, printing starts there,\n otherwise the whole tree is printed."
1026 static void cmd_transform(struct command *cmd) {
1027 const char *lens = arg_value(cmd, "lens");
1028 const char *filter = arg_value(cmd, "filter");
1029 const char *file = arg_value(cmd, "file");
1032 if (STREQ("excl", filter))
1034 else if (STREQ("incl", filter))
1037 ERR_REPORT(cmd, AUG_ECMDRUN,
1038 "FILTER must be \"incl\" or \"excl\"");
1040 r = aug_transform(cmd->aug, lens, file, excl);
1042 ERR_REPORT(cmd, AUG_ECMDRUN,
1043 "Adding transform for %s on lens %s failed", lens, file);
1046 static const struct command_opt_def cmd_transform_opts[] = {
1047 { .type = CMD_PATH, .name = "lens", .optional = false,
1048 .help = "the lens to use" },
1049 { .type = CMD_PATH, .name = "filter", .optional = false,
1050 .help = "the type of filter, either \"incl\" or \"excl\"" },
1051 { .type = CMD_PATH, .name = "file", .optional = false,
1052 .help = "the file to associate to the lens" },
1056 static const char const cmd_transform_help[] =
1057 "Add a transform for FILE using LENS. The LENS may be a module name or a\n"
1058 " full lens name. If a module name is given, then \"lns\" will be the lens\n"
1059 " assumed. The FILTER must be either \"incl\" or \"excl\". If the filter is\n"
1060 " \"incl\", the FILE will be parsed by the LENS. If the filter is \"excl\",\n"
1061 " the FILE will be excluded from the LENS. FILE may contain wildcards." ;
1063 static const struct command_def cmd_transform_def = {
1064 .name = "transform",
1065 .opts = cmd_transform_opts,
1066 .handler = cmd_transform,
1067 .synopsis = "add a file transform",
1068 .help = cmd_transform_help
1071 static void cmd_load_file(struct command *cmd) {
1072 const char *file = arg_value(cmd, "file");
1075 r = aug_load_file(cmd->aug, file);
1077 ERR_REPORT(cmd, AUG_ECMDRUN,
1078 "Failed to load file %s", file);
1081 static const struct command_opt_def cmd_load_file_opts[] = {
1082 { .type = CMD_PATH, .name = "file", .optional = false,
1083 .help = "the file to load" },
1087 static const char const cmd_load_file_help[] =
1088 "Load a specific FILE, using autoload statements.\n";
1090 static const struct command_def cmd_load_file_def = {
1091 .name = "load-file",
1092 .opts = cmd_load_file_opts,
1093 .handler = cmd_load_file,
1094 .synopsis = "load a specific file",
1095 .help = cmd_load_file_help
1098 static void cmd_save(struct command *cmd) {
1100 r = aug_save(cmd->aug);
1102 ERR_REPORT(cmd, AUG_ECMDRUN,
1103 "saving failed (run 'errors' for details)");
1105 r = aug_match(cmd->aug, "/augeas/events/saved", NULL);
1107 fprintf(cmd->out, "Saved %d file(s)\n", r);
1112 static const struct command_opt_def cmd_save_opts[] = {
1116 static const struct command_def cmd_save_def = {
1118 .opts = cmd_save_opts,
1119 .handler = cmd_save,
1120 .synopsis = "save all pending changes",
1121 .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"
1124 static void cmd_load(struct command *cmd) {
1126 r = aug_load(cmd->aug);
1128 ERR_REPORT(cmd, AUG_ECMDRUN,
1129 "loading failed (run 'errors' for details)");
1133 static const struct command_opt_def cmd_load_opts[] = {
1137 static const struct command_def cmd_load_def = {
1139 .opts = cmd_load_opts,
1140 .handler = cmd_load,
1141 .synopsis = "(re)load files under /files",
1142 .help = "Load files according to the transforms in /augeas/load. "
1143 "A transform\n Foo is represented with a subtree /augeas/load/Foo."
1144 " Underneath\n /augeas/load/Foo, one node labelled 'lens' must exist,"
1145 " whose value is\n the fully qualified name of a lens, for example "
1146 "'Foo.lns', and\n multiple nodes 'incl' and 'excl' whose values are "
1147 "globs that determine\n which files are transformed by that lens. It "
1148 "is an error if one file\n can be processed by multiple transforms."
1151 static void cmd_info(struct command *cmd) {
1155 aug_get(cmd->aug, "/augeas/version", &v);
1158 fprintf(cmd->out, "version = %s\n", v);
1161 aug_get(cmd->aug, "/augeas/root", &v);
1164 fprintf(cmd->out, "root = %s\n", v);
1167 fprintf(cmd->out, "loadpath = ");
1168 for (char *entry = cmd->aug->modpathz;
1170 entry = argz_next(cmd->aug->modpathz, cmd->aug->nmodpath, entry)) {
1171 if (entry != cmd->aug->modpathz) {
1172 fprintf(cmd->out, ":");
1174 fprintf(cmd->out, "%s", entry);
1176 fprintf(cmd->out, "\n");
1178 aug_get(cmd->aug, "/augeas/context", &v);
1183 fprintf(cmd->out, "context = %s\n", v);
1185 n = aug_match(cmd->aug, "/augeas/files//path", NULL);
1186 fprintf(cmd->out, "num_files = %d\n", n);
1189 static const struct command_opt_def cmd_info_opts[] = {
1193 static const struct command_def cmd_info_def = {
1195 .opts = cmd_info_opts,
1196 .handler = cmd_info,
1197 .synopsis = "print runtime information",
1198 .help = "Print information about Augeas. The output contains:\n"
1199 " version : the version number from /augeas/version\n"
1200 " root : what Augeas considers the filesystem root\n"
1201 " from /augeas/root\n"
1202 " loadpath : the paths from which Augeas loads modules\n"
1203 " context : the context path (see context command)\n"
1204 " num_files : the number of files currently loaded (based on\n"
1205 " the number of /augeas/files//path nodes)"
1208 static void cmd_ins(struct command *cmd) {
1209 const char *label = arg_value(cmd, "label");
1210 const char *where = arg_value(cmd, "where");
1211 const char *path = arg_value(cmd, "path");
1214 if (STREQ(where, "after"))
1216 else if (STREQ(where, "before"))
1219 ERR_REPORT(cmd, AUG_ECMDRUN,
1220 "the <WHERE> argument for ins must be either 'before' or 'after'.");
1224 aug_insert(cmd->aug, path, label, before);
1227 static const struct command_opt_def cmd_ins_opts[] = {
1228 { .type = CMD_STR, .name = "label", .optional = false,
1229 .help = "the label for the new node" },
1230 { .type = CMD_STR, .name = "where", .optional = false,
1231 .help = "either 'before' or 'after'" },
1232 { .type = CMD_PATH, .name = "path", .optional = false,
1233 .help = "the node before/after which to insert" },
1237 static const char const cmd_ins_help[] =
1238 "Insert a new node with label LABEL right before or after "
1239 "PATH into the\n tree. WHERE must be either 'before' or 'after'.";
1241 static const struct command_def cmd_ins_def = {
1243 .opts = cmd_ins_opts,
1245 .synopsis = "insert new node",
1246 .help = cmd_ins_help
1249 static const struct command_def cmd_insert_def = {
1251 .opts = cmd_ins_opts,
1253 .synopsis = "insert new node (alias of 'ins')",
1254 .help = cmd_ins_help
1257 static void cmd_store(struct command *cmd) {
1258 const char *lens = arg_value(cmd, "lens");
1259 const char *path = arg_value(cmd, "path");
1260 const char *node = arg_value(cmd, "node");
1262 aug_text_store(cmd->aug, lens, node, path);
1265 static const struct command_opt_def cmd_store_opts[] = {
1266 { .type = CMD_STR, .name = "lens", .optional = false,
1267 .help = "the name of the lens" },
1268 { .type = CMD_PATH, .name = "node", .optional = false,
1269 .help = "where to find the input text" },
1270 { .type = CMD_PATH, .name = "path", .optional = false,
1271 .help = "where to store parsed text" },
1275 static const char const cmd_store_help[] =
1276 "Parse NODE using LENS and store the resulting tree at PATH.";
1278 static const struct command_def cmd_store_def = {
1280 .opts = cmd_store_opts,
1281 .handler = cmd_store,
1282 .synopsis = "parse text into tree",
1283 .help = cmd_store_help
1286 static void cmd_retrieve(struct command *cmd) {
1287 const char *lens = arg_value(cmd, "lens");
1288 const char *node_in = arg_value(cmd, "node_in");
1289 const char *path = arg_value(cmd, "path");
1290 const char *node_out = arg_value(cmd, "node_out");
1292 aug_text_retrieve(cmd->aug, lens, node_in, path, node_out);
1295 static const struct command_opt_def cmd_retrieve_opts[] = {
1296 { .type = CMD_STR, .name = "lens", .optional = false,
1297 .help = "the name of the lens" },
1298 { .type = CMD_PATH, .name = "node_in", .optional = false,
1299 .help = "the node containing the initial text (path expression)" },
1300 { .type = CMD_PATH, .name = "path", .optional = false,
1301 .help = "the tree to transform (path expression)" },
1302 { .type = CMD_PATH, .name = "node_out", .optional = false,
1303 .help = "where to store the resulting text (path expression)" },
1307 static const char const cmd_retrieve_help[] =
1308 "Transform tree at PATH back into text using lens LENS and store the\n"
1309 " resulting string at NODE_OUT. Assume that the tree was initially read in\n"
1310 " with the same lens and the string stored at NODE_IN as input.";
1312 static const struct command_def cmd_retrieve_def = {
1314 .opts = cmd_retrieve_opts,
1315 .handler = cmd_retrieve,
1316 .synopsis = "transform tree into text",
1317 .help = cmd_retrieve_help
1320 /* Given a path "/augeas/files/FILENAME/error", return FILENAME */
1321 static char *err_filename(const char *match) {
1322 int noise = strlen(AUGEAS_META_FILES) + strlen("/error");
1323 if (strlen(match) < noise + 1)
1325 return strndup(match + strlen(AUGEAS_META_FILES), strlen(match) - noise);
1327 return strdup("(no filename)");
1330 static const char *err_get(struct augeas *aug,
1331 const char *match, const char *child) {
1333 const char *value = "";
1336 r = pathjoin(&path, 2, match, child);
1337 ERR_NOMEM(r < 0, aug);
1339 aug_get(aug, path, &value);
1347 static void cmd_errors(struct command *cmd) {
1348 char **matches = NULL;
1350 struct augeas *aug = cmd->aug;
1352 cnt = aug_match(aug, "/augeas//error", &matches);
1354 ERR_THROW(cnt < 0, aug, AUG_ECMDRUN,
1355 " (problem retrieving error messages)\n");
1357 fprintf(cmd->out, " (no errors)\n");
1361 for (int i=0; i < cnt; i++) {
1362 const char *match = matches[i];
1363 const char *line = err_get(aug, match, "line");
1364 const char *char_pos = err_get(aug, match, "char");
1365 const char *lens = err_get(aug, match, "lens");
1366 const char *last = err_get(aug, match, "lens/last_matched");
1367 const char *next = err_get(aug, match, "lens/next_not_matched");
1368 const char *msg = err_get(aug, match, "message");
1369 const char *path = err_get(aug, match, "path");
1370 const char *kind = NULL;
1372 aug_get(aug, match, &kind);
1375 char *filename = err_filename(match);
1376 ERR_NOMEM(filename == NULL, aug);
1379 fprintf(cmd->out, "\n");
1382 fprintf(cmd->out, "Error in %s:%s.%s (%s)\n",
1383 filename, line, char_pos, kind);
1384 } else if (path != NULL) {
1385 fprintf(cmd->out, "Error in %s at node %s (%s)\n", filename, path, kind);
1387 fprintf(cmd->out, "Error in %s (%s)\n", filename, kind);
1392 fprintf(cmd->out, " %s\n", msg);
1394 fprintf(cmd->out, " Lens: %s\n", lens);
1396 fprintf(cmd->out, " Last matched: %s\n", last);
1398 fprintf(cmd->out, " Next (no match): %s\n", next);
1403 for (int i=0; i < cnt; i++)
1408 static const struct command_opt_def cmd_errors_opts[] = {
1412 static const char const cmd_errors_help[] =
1413 "Show all the errors encountered in processing files. For each error,\n"
1414 " print detailed information about where it happened and how. The same\n"
1415 " information can be retrieved by running 'print /augeas//error'\n\n"
1416 " For each error, the file in which the error occurred together with the\n"
1417 " line number and position in that line is shown, as well as information\n"
1418 " about the lens that encountered the error. For some errors, the last\n"
1419 " lens that matched successfully and the next lens that should have\n"
1420 " matched but didn't are also shown\n";
1422 static const struct command_def cmd_errors_def = {
1424 .opts = cmd_errors_opts,
1425 .handler = cmd_errors,
1426 .synopsis = "show all errors encountered in processing files",
1427 .help = cmd_errors_help
1430 /* Groups of commands */
1431 static const struct command_grp_def cmd_grp_admin_def = {
1446 static const struct command_grp_def cmd_grp_info_def = {
1447 .name = "Informational",
1457 static const struct command_grp_def cmd_grp_read_def = {
1471 static const struct command_grp_def cmd_grp_write_def = {
1491 static const struct command_grp_def cmd_grp_pathx_def = {
1492 .name = "Path expression",
1500 static const struct command_grp_def const *cmd_groups[] = {
1509 static const struct command_def *lookup_cmd_def(const char *name) {
1510 for (int i = 0; cmd_groups[i]->name != NULL; i++) {
1511 for (int j = 0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1512 if (STREQ(name, cmd_groups[i]->commands[j]->name))
1513 return cmd_groups[i]->commands[j];
1519 static void cmd_help(struct command *cmd) {
1520 const char *name = arg_value(cmd, "command");
1524 //fprintf(cmd->out, "Commands:\n\n");
1525 fprintf(cmd->out, "\n");
1526 for (int i=0; cmd_groups[i]->name != NULL; i++) {
1527 fprintf(cmd->out, "%s commands:\n", cmd_groups[i]->name);
1528 for (int j=0; cmd_groups[i]->commands[j]->name != NULL; j++) {
1529 const struct command_def *def = cmd_groups[i]->commands[j];
1530 fprintf(cmd->out, " %-10s - %s\n", def->name, def->synopsis);
1532 fprintf(cmd->out, "\n");
1535 "Type 'help <command>' for more information on a command\n\n");
1537 const struct command_def *def = lookup_cmd_def(name);
1538 const struct command_opt_def *odef = NULL;
1540 ERR_THROW(def == NULL, cmd->aug, AUG_ECMDRUN,
1541 "unknown command %s\n", name);
1542 fprintf(cmd->out, " COMMAND\n");
1543 fprintf(cmd->out, " %s - %s\n\n", name, def->synopsis);
1544 fprintf(cmd->out, " SYNOPSIS\n");
1545 fprintf(cmd->out, " %s", name);
1547 for (odef = def->opts; odef->name != NULL; odef++) {
1548 format_defname(buf, odef, true);
1549 fprintf(cmd->out, "%s", buf);
1551 fprintf(cmd->out, "\n\n");
1552 fprintf(cmd->out, " DESCRIPTION\n");
1553 format_desc(def->help);
1554 if (def->opts->name != NULL) {
1555 fprintf(cmd->out, " OPTIONS\n");
1556 for (odef = def->opts; odef->name != NULL; odef++) {
1557 const char *help = odef->help;
1560 format_defname(buf, odef, false);
1561 fprintf(cmd->out, " %-10s %s\n", buf, help);
1564 fprintf(cmd->out, "\n");
1570 int aug_srun(augeas *aug, FILE *out, const char *text) {
1580 cmd.error = aug->error;
1586 while (*text != '\0' && result >= 0) {
1587 eol = strchrnul(text, '\n');
1588 while (isspace(*text) && text < eol) text++;
1591 if (*text == '#' || text == eol) {
1592 text = (*eol == '\0') ? eol : eol + 1;
1596 line = strndup(text, eol - text);
1597 ERR_NOMEM(line == NULL, aug);
1599 if (parseline(&cmd, line) == 0) {
1600 cmd.def->handler(&cmd);
1607 if (result >= 0 && cmd.quit) {
1612 free_command_opts(&cmd);
1614 text = (*eol == '\0') ? eol : eol + 1;
1617 free_command_opts(&cmd);
1629 * indent-tabs-mode: nil