2 * augeas.c: the core data structure for storing key/value pairs
4 * Copyright (C) 2007-2017 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 <dlutter@redhat.com>
28 #include "transform.h"
37 /* Some popular labels that we use in /augeas */
38 static const char *const s_augeas = "augeas";
39 static const char *const s_files = "files";
40 static const char *const s_load = "load";
41 static const char *const s_pathx = "pathx";
42 static const char *const s_error = "error";
43 static const char *const s_pos = "pos";
44 static const char *const s_vars = "variables";
45 static const char *const s_lens = "lens";
46 static const char *const s_excl = "excl";
47 static const char *const s_incl = "incl";
49 #define AUGEAS_META_PATHX_FUNC AUGEAS_META_TREE "/version/pathx/functions"
51 static const char *const static_nodes[][2] = {
52 { AUGEAS_FILES_TREE, NULL },
53 { AUGEAS_META_TREE "/variables", NULL },
54 { AUGEAS_META_TREE "/version", PACKAGE_VERSION },
55 { AUGEAS_META_TREE "/version/save/mode[1]", AUG_SAVE_BACKUP_TEXT },
56 { AUGEAS_META_TREE "/version/save/mode[2]", AUG_SAVE_NEWFILE_TEXT },
57 { AUGEAS_META_TREE "/version/save/mode[3]", AUG_SAVE_NOOP_TEXT },
58 { AUGEAS_META_TREE "/version/save/mode[4]", AUG_SAVE_OVERWRITE_TEXT },
59 { AUGEAS_META_TREE "/version/defvar/expr", NULL },
60 { AUGEAS_META_PATHX_FUNC "/count", NULL },
61 { AUGEAS_META_PATHX_FUNC "/glob", NULL },
62 { AUGEAS_META_PATHX_FUNC "/label", NULL },
63 { AUGEAS_META_PATHX_FUNC "/last", NULL },
64 { AUGEAS_META_PATHX_FUNC "/position", NULL },
65 { AUGEAS_META_PATHX_FUNC "/regexp", NULL }
68 static const char *const errcodes[] = {
69 "No error", /* AUG_NOERROR */
70 "Cannot allocate memory", /* AUG_ENOMEM */
71 "Internal error (please file a bug)", /* AUG_EINTERNAL */
72 "Invalid path expression", /* AUG_EPATHX */
73 "No match for path expression", /* AUG_ENOMATCH */
74 "Too many matches for path expression", /* AUG_EMMATCH */
75 "Syntax error in lens definition", /* AUG_ESYNTAX */
76 "Lens not found", /* AUG_ENOLENS */
77 "Multiple transforms", /* AUG_EMXFM */
78 "Node has no span info", /* AUG_ENOSPAN */
79 "Cannot move node into its descendant", /* AUG_EMVDESC */
80 "Failed to execute command", /* AUG_ECMDRUN */
81 "Invalid argument in function call", /* AUG_EBADARG */
82 "Invalid label", /* AUG_ELABEL */
83 "Cannot copy node into its descendant" /* AUG_ECPDESC */
86 static void tree_mark_dirty(struct tree *tree) {
90 } while (tree != tree->parent && !tree->dirty);
94 void tree_clean(struct tree *tree) {
96 list_for_each(c, tree->children)
102 struct tree *tree_child(struct tree *tree, const char *label) {
106 list_for_each(child, tree->children) {
107 if (streqv(label, child->label))
113 struct tree *tree_child_cr(struct tree *tree, const char *label) {
114 static struct tree *child = NULL;
119 child = tree_child(tree, label);
121 char *l = strdup(label);
124 child = tree_append(tree, l, NULL);
129 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
133 for (int i=0; i < n; i++) {
134 const char *l = va_arg(ap, const char *);
135 tree = tree_child_cr(tree, l);
141 static struct tree *tree_fpath_int(struct augeas *aug, const char *fpath,
144 char *steps = NULL, *step = NULL;
146 struct tree *result = NULL;
148 r = argz_create_sep(fpath, '/', &steps, &nsteps);
149 ERR_NOMEM(r < 0, aug);
150 result = aug->origin;
151 while ((step = argz_next(steps, nsteps, step))) {
153 result = tree_child_cr(result, step);
154 ERR_THROW(result == NULL, aug, AUG_ENOMEM,
155 "while searching %s: can not create %s", fpath, step);
158 result = tree_child(result, step);
171 struct tree *tree_fpath(struct augeas *aug, const char *fpath) {
172 return tree_fpath_int(aug, fpath, false);
175 struct tree *tree_fpath_cr(struct augeas *aug, const char *fpath) {
176 return tree_fpath_int(aug, fpath, true);
179 struct tree *tree_find(struct augeas *aug, const char *path) {
180 struct pathx *p = NULL;
181 struct tree *result = NULL;
184 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
187 r = pathx_find_one(p, &result);
189 "Multiple matches for %s when only one was expected",
199 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
200 struct pathx *p = NULL;
201 struct tree *result = NULL;
204 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
207 r = pathx_expand_tree(p, &result);
209 ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
215 void tree_store_value(struct tree *tree, char **value) {
216 if (streqv(tree->value, *value)) {
221 if (tree->value != NULL) {
225 if (*value != NULL) {
226 tree->value = *value;
229 tree_mark_dirty(tree);
232 int tree_set_value(struct tree *tree, const char *value) {
235 if (streqv(tree->value, value))
242 tree_store_value(tree, &v);
246 static void store_error(const struct augeas *aug, const char *label, const char *value,
251 ensure(nentries % 2 == 0, aug);
252 tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
256 tree_set_value(tree, value);
258 va_start(ap, nentries);
259 for (int i=0; i < nentries; i += 2) {
260 char *l = va_arg(ap, char *);
261 char *v = va_arg(ap, char *);
262 struct tree *t = tree_child_cr(tree, l);
264 tree_set_value(t, v);
271 /* Report pathx errors in /augeas/pathx/error */
272 static void store_pathx_error(const struct augeas *aug) {
273 if (aug->error->code != AUG_EPATHX)
276 store_error(aug, s_pathx, aug->error->minor_details,
277 2, s_pos, aug->error->details);
280 struct pathx *pathx_aug_parse(const struct augeas *aug,
282 struct tree *root_ctx,
283 const char *path, bool need_nodeset) {
284 struct pathx *result;
285 struct error *err = err_of_aug(aug);
290 pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
294 /* Find the tree stored in AUGEAS_CONTEXT */
295 struct tree *tree_root_ctx(const struct augeas *aug) {
296 struct pathx *p = NULL;
297 struct tree *match = NULL;
298 const char *ctx_path;
301 p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
304 r = pathx_find_one(p, &match);
305 ERR_THROW(r > 1, aug, AUG_EMMATCH,
306 "There are %d nodes matching %s, expecting one",
309 if (match == NULL || match->value == NULL || *match->value == '\0')
312 /* Clean via augrun's helper to ensure it's valid */
313 ctx_path = cleanpath(match->value);
316 p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
319 if (pathx_first(p) == NULL) {
320 r = pathx_expand_tree(p, &match);
323 r = tree_set_value(match, NULL);
327 r = pathx_find_one(p, &match);
328 ERR_THROW(r > 1, aug, AUG_EMMATCH,
329 "There are %d nodes matching the context %s, expecting one",
341 struct tree *tree_append(struct tree *parent,
342 char *label, char *value) {
343 struct tree *result = make_tree(label, value, parent, NULL);
345 list_append(parent->children, result);
349 static struct tree *tree_append_s(struct tree *parent,
350 const char *l0, char *v) {
359 result = tree_append(parent, l, v);
365 static struct tree *tree_from_transform(struct augeas *aug,
367 struct transform *xfm) {
368 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
369 struct tree *load = NULL, *txfm = NULL, *t;
373 ERR_NOMEM(meta == NULL, aug);
375 load = tree_child_cr(meta, s_load);
376 ERR_NOMEM(load == NULL, aug);
381 txfm = tree_append_s(load, modname, NULL);
382 ERR_NOMEM(txfm == NULL, aug);
384 r = asprintf(&v, "@%s", modname);
385 ERR_NOMEM(r < 0, aug);
387 t = tree_append_s(txfm, s_lens, v);
388 ERR_NOMEM(t == NULL, aug);
391 list_for_each(f, xfm->filter) {
392 const char *l = f->include ? s_incl : s_excl;
393 v = strdup(f->glob->str);
394 ERR_NOMEM(v == NULL, aug);
395 t = tree_append_s(txfm, l, v);
396 ERR_NOMEM(t == NULL, aug);
401 tree_unlink(aug, txfm);
405 /* Save user locale and switch to C locale */
407 static void save_locale(struct augeas *aug) {
408 if (aug->c_locale == NULL) {
409 aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
410 ERR_NOMEM(aug->c_locale == NULL, aug);
413 aug->user_locale = uselocale(aug->c_locale);
418 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
422 static void restore_locale(struct augeas *aug) {
423 uselocale(aug->user_locale);
424 aug->user_locale = NULL;
427 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
430 /* Clean up old error messages every time we enter through the public
431 * API. Since we make internal calls through the public API, we keep a
432 * count of how many times a public API call was made, and only reset when
433 * that count is 0. That requires that all public functions enclose their
434 * work within a matching pair of api_entry/api_exit calls.
436 void api_entry(const struct augeas *aug) {
437 struct error *err = ((struct augeas *) aug)->error;
439 ((struct augeas *) aug)->api_entries += 1;
441 if (aug->api_entries > 1)
445 save_locale((struct augeas *) aug);
448 void api_exit(const struct augeas *aug) {
449 assert(aug->api_entries > 0);
450 ((struct augeas *) aug)->api_entries -= 1;
451 if (aug->api_entries == 0) {
452 store_pathx_error(aug);
453 restore_locale((struct augeas *) aug);
457 static int init_root(struct augeas *aug, const char *root0) {
459 root0 = getenv(AUGEAS_ROOT_ENV);
460 if (root0 == NULL || root0[0] == '\0')
463 aug->root = strdup(root0);
464 if (aug->root == NULL)
467 if (aug->root[strlen(aug->root)-1] != SEP) {
468 if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
470 strcat((char *) aug->root, "/");
475 static int init_loadpath(struct augeas *aug, const char *loadpath) {
478 aug->modpathz = NULL;
480 if (loadpath != NULL) {
481 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
482 loadpath, PATH_SEP_CHAR);
486 char *env = getenv(AUGEAS_LENS_ENV);
488 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
493 if (!(aug->flags & AUG_NO_STDINC)) {
494 r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
497 r = argz_add(&aug->modpathz, &aug->nmodpath,
498 AUGEAS_LENS_DIST_DIR);
502 /* Clean up trailing slashes */
503 if (aug->nmodpath > 0) {
504 argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
506 const char *e = aug->modpathz + strlen(aug->modpathz);
507 for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
510 while (*p == '/') p += 1;
511 if (*p == '\0' || *p == PATH_SEP_CHAR)
523 aug->modpathz = NULL;
524 r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
533 static void init_save_mode(struct augeas *aug) {
534 const char *v = AUG_SAVE_OVERWRITE_TEXT;
536 if (aug->flags & AUG_SAVE_NEWFILE) {
537 v = AUG_SAVE_NEWFILE_TEXT;
538 } else if (aug->flags & AUG_SAVE_BACKUP) {
539 v = AUG_SAVE_BACKUP_TEXT;
540 } else if (aug->flags & AUG_SAVE_NOOP) {
541 v = AUG_SAVE_NOOP_TEXT;
544 aug_set(aug, AUGEAS_META_SAVE_MODE, v);
547 struct augeas *aug_init(const char *root, const char *loadpath,
548 unsigned int flags) {
549 struct augeas *result;
550 struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
552 bool close_on_error = true;
554 if (tree_root == NULL)
557 if (ALLOC(result) < 0)
559 if (ALLOC(result->error) < 0)
561 if (make_ref(result->error->info) < 0)
563 result->error->info->error = result->error;
564 result->error->info->filename = dup_string("(unknown file)");
565 if (result->error->info->filename == NULL)
567 result->error->aug = result;
569 result->origin = make_tree_origin(tree_root);
570 if (result->origin == NULL) {
571 free_tree(tree_root);
577 result->flags = flags;
579 r = init_root(result, root);
580 ERR_NOMEM(r < 0, result);
582 result->origin->children->label = strdup(s_augeas);
584 /* We are now initialized enough that we can dare return RESULT even
585 * when we encounter errors if the caller so wishes */
586 close_on_error = !(flags & AUG_NO_ERR_CLOSE);
588 r = init_loadpath(result, loadpath);
589 ERR_NOMEM(r < 0, result);
591 /* We report the root dir in AUGEAS_META_ROOT, but we only use the
592 value we store internally, to avoid any problems with
593 AUGEAS_META_ROOT getting changed. */
594 aug_set(result, AUGEAS_META_ROOT, result->root);
597 /* Set the default path context */
598 aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
601 for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
602 aug_set(result, static_nodes[i][0], static_nodes[i][1]);
606 init_save_mode(result);
609 const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
610 aug_set(result, AUGEAS_SPAN_OPTION, v);
613 if (interpreter_init(result) == -1)
616 list_for_each(modl, result->modules) {
617 struct transform *xform = modl->autoload;
620 tree_from_transform(result, modl->name, xform);
623 if (!(result->flags & AUG_NO_LOAD))
624 if (aug_load(result) < 0)
631 if (close_on_error) {
635 if (result != NULL && result->api_entries > 0)
640 /* Free one tree node */
641 static void free_tree_node(struct tree *tree) {
645 if (tree->span != NULL)
646 free_span(tree->span);
652 /* Only unlink; assume we know TREE is not in the symtab */
653 static int tree_unlink_raw(struct tree *tree) {
656 assert (tree->parent != NULL);
657 list_remove(tree, tree->parent->children);
658 tree_mark_dirty(tree->parent);
659 result = free_tree(tree->children) + 1;
660 free_tree_node(tree);
664 int tree_unlink(struct augeas *aug, struct tree *tree) {
667 pathx_symtab_remove_descendants(aug->symtab, tree);
668 return tree_unlink_raw(tree);
671 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
675 pathx_symtab_remove_descendants(aug->symtab, tree);
677 while (tree->children != NULL)
678 tree_unlink_raw(tree->children);
681 static void tree_mark_files(struct tree *tree) {
682 if (tree_child(tree, "path") != NULL) {
683 tree_mark_dirty(tree);
685 list_for_each(c, tree->children) {
691 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
697 if (tree->file && ((p = tree_child(tree, "path")) != NULL)) {
698 tree_unlink(aug, tree_fpath(aug, p->value));
699 tree_unlink(aug, tree);
701 struct tree *c = tree->children;
703 struct tree *next = c->next;
704 tree_rm_dirty_files(aug, c);
710 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
711 struct tree *protect) {
715 struct tree *c = tree->children;
717 struct tree *next = c->next;
718 tree_rm_dirty_leaves(aug, c, protect);
722 if (tree != protect && tree->children == NULL)
723 tree_unlink(aug, tree);
726 int aug_load(struct augeas *aug) {
727 const char *option = NULL;
728 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
729 struct tree *meta_files = tree_child_cr(meta, s_files);
730 struct tree *files = tree_child_cr(aug->origin, s_files);
731 struct tree *load = tree_child_cr(meta, s_load);
732 struct tree *vars = tree_child_cr(meta, s_vars);
736 ERR_NOMEM(load == NULL, aug);
738 /* To avoid unnecessary loads of files, we reload an existing file in
740 * (1) mark all file nodes under /augeas/files as dirty (and only those)
741 * (2) process all files matched by a lens; we check (in
742 * transform_load) if the file has been modified. If it has, we
743 * reparse it. Either way, we clear the dirty flag. We also need to
744 * reread the file if part or all of it has been modified in the
745 * tree but not been saved yet
746 * (3) remove all files from the tree that still have a dirty entry
747 * under /augeas/files. Those files are not processed by any lens
749 * (4) Remove entries from /augeas/files and /files that correspond
750 * to directories without any files of interest
753 /* update flags according to option value */
754 if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
755 if (strcmp(option, AUG_ENABLE) == 0) {
756 aug->flags |= AUG_ENABLE_SPAN;
758 aug->flags &= ~AUG_ENABLE_SPAN;
762 tree_clean(meta_files);
763 tree_mark_files(meta_files);
765 list_for_each(xfm, load->children) {
766 if (transform_validate(aug, xfm) == 0)
767 transform_load(aug, xfm, NULL);
770 /* This makes it possible to spot 'directories' that are now empty
771 * because we removed their file contents */
774 tree_rm_dirty_files(aug, meta_files);
775 tree_rm_dirty_leaves(aug, meta_files, meta_files);
776 tree_rm_dirty_leaves(aug, files, files);
778 tree_clean(aug->origin);
780 list_for_each(v, vars->children) {
781 aug_defvar(aug, v->label, v->value);
792 static int find_one_node(struct pathx *p, struct tree **match) {
793 struct error *err = err_of_pathx(p);
794 int r = pathx_find_one(p, match);
800 report_error(err, AUG_ENOMATCH, NULL);
803 report_error(err, AUG_EMMATCH, NULL);
809 int aug_get(const struct augeas *aug, const char *path, const char **value) {
810 struct pathx *p = NULL;
819 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
822 r = pathx_find_one(p, &match);
824 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
827 if (r == 1 && value != NULL)
828 *value = match->value;
839 int aug_label(const struct augeas *aug, const char *path, const char **label) {
840 struct pathx *p = NULL;
846 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
852 r = pathx_find_one(p, &match);
854 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
857 if (r == 1 && label != NULL)
858 *label = match->label;
869 static void record_var_meta(struct augeas *aug, const char *name,
871 /* Record the definition of the variable */
872 struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
873 ERR_NOMEM(tree == NULL, aug);
875 tree_unlink(aug, tree_child(tree, name));
877 tree = tree_child_cr(tree, name);
878 ERR_NOMEM(tree == NULL, aug);
879 tree_set_value(tree, expr);
885 int aug_defvar(augeas *aug, const char *name, const char *expr) {
886 struct pathx *p = NULL;
892 result = pathx_symtab_undefine(&(aug->symtab), name);
894 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
896 result = pathx_symtab_define(&(aug->symtab), name, p);
900 record_var_meta(aug, name, expr);
908 int aug_defnode(augeas *aug, const char *name, const char *expr,
909 const char *value, int *created) {
910 struct pathx *p = NULL;
922 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
925 if (pathx_first(p) == NULL) {
926 r = pathx_expand_tree(p, &tree);
935 r = tree_set_value(tree, value);
938 result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
939 char *e = path_of_tree(tree);
940 ERR_NOMEM(e == NULL, aug)
941 record_var_meta(aug, name, e);
945 result = pathx_symtab_define(&(aug->symtab), name, p);
946 record_var_meta(aug, name, expr);
957 struct tree *tree_set(struct pathx *p, const char *value) {
961 r = pathx_expand_tree(p, &tree);
965 r = tree_set_value(tree, value);
971 int aug_set(struct augeas *aug, const char *path, const char *value) {
972 struct pathx *p = NULL;
977 /* Get-out clause, in case context is broken */
978 struct tree *root_ctx = NULL;
979 if (STRNEQ(path, AUGEAS_CONTEXT))
980 root_ctx = tree_root_ctx(aug);
982 p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
985 result = tree_set(p, value) == NULL ? -1 : 0;
992 int aug_setm(struct augeas *aug, const char *base,
993 const char *sub, const char *value) {
994 struct pathx *bx = NULL, *sx = NULL;
995 struct tree *bt, *st;
1000 bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
1003 if (sub != NULL && STREQ(sub, "."))
1007 for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
1009 /* Handle subnodes of BT */
1010 sx = pathx_aug_parse(aug, bt, NULL, sub, true);
1012 if (pathx_first(sx) != NULL) {
1013 /* Change existing subnodes matching SUB */
1014 for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
1015 r = tree_set_value(st, value);
1016 ERR_NOMEM(r < 0, aug);
1020 /* Create a new subnode matching SUB */
1021 r = pathx_expand_tree(sx, &st);
1024 r = tree_set_value(st, value);
1025 ERR_NOMEM(r < 0, aug);
1031 /* Set nodes matching BT directly */
1032 r = tree_set_value(bt, value);
1033 ERR_NOMEM(r < 0, aug);
1048 int tree_insert(struct pathx *p, const char *label, int before) {
1049 struct tree *new = NULL, *match;
1051 if (strchr(label, SEP) != NULL)
1054 if (find_one_node(p, &match) < 0)
1057 new = make_tree(strdup(label), NULL, match->parent, NULL);
1058 if (new == NULL || new->label == NULL)
1062 list_insert_before(new, match, new->parent->children);
1064 new->next = match->next;
1073 int aug_insert(struct augeas *aug, const char *path, const char *label,
1075 struct pathx *p = NULL;
1080 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1083 result = tree_insert(p, label, before);
1090 struct tree *make_tree(char *label, char *value, struct tree *parent,
1091 struct tree *children) {
1093 if (ALLOC(tree) < 0)
1096 tree->label = label;
1097 tree->value = value;
1098 tree->parent = parent;
1099 tree->children = children;
1100 list_for_each(c, tree->children)
1103 tree_mark_dirty(tree);
1109 struct tree *make_tree_origin(struct tree *root) {
1110 struct tree *origin = NULL;
1112 origin = make_tree(NULL, NULL, NULL, root);
1116 origin->parent = origin;
1120 /* Recursively free the whole tree TREE and all its siblings */
1121 int free_tree(struct tree *tree) {
1124 while (tree != NULL) {
1125 struct tree *del = tree;
1127 cnt += free_tree(del->children);
1128 free_tree_node(del);
1135 int tree_rm(struct pathx *p) {
1136 struct tree *tree, **del;
1137 int cnt = 0, ndel = 0, i;
1139 /* set ndel to the number of trees we could possibly delete */
1140 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1141 if (! TREE_HIDDEN(tree))
1148 if (ALLOC_N(del, ndel) < 0) {
1153 for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1154 if (TREE_HIDDEN(tree))
1156 pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1157 /* Collect the tree nodes that actually need to be deleted in
1158 del. Mark the root of every subtree we are going to free by
1159 setting tree->added. Only add a node to del if none of its
1160 ancestors would have been freed by the time we get to freeing
1161 that node; this avoids double frees for situations where the
1162 path expression matches both /node and /node/child as unlinking
1163 /node implicitly unlinks /node/child */
1165 for (struct tree *t = tree; live && ! ROOT_P(t); t = t->parent) {
1175 /* ndel now means: the number of trees we are actually going to delete */
1178 for (i = 0; i < ndel; i++) {
1179 if (del[i] != NULL) {
1180 cnt += tree_unlink_raw(del[i]);
1188 int aug_rm(struct augeas *aug, const char *path) {
1189 struct pathx *p = NULL;
1194 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1197 result = tree_rm(p);
1205 int aug_span(struct augeas *aug, const char *path, char **filename,
1206 uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1207 uint *span_start, uint *span_end) {
1208 struct pathx *p = NULL;
1210 struct tree *tree = NULL;
1215 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1218 tree = pathx_first(p);
1221 ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1222 ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1223 ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1227 if (label_start != NULL)
1228 *label_start = span->label_start;
1230 if (label_end != NULL)
1231 *label_end = span->label_end;
1233 if (value_start != NULL)
1234 *value_start = span->value_start;
1236 if (value_end != NULL)
1237 *value_end = span->value_end;
1239 if (span_start != NULL)
1240 *span_start = span->span_start;
1242 if (span_end != NULL)
1243 *span_end = span->span_end;
1245 /* We are safer here, make sure we have a filename */
1246 if (filename != NULL) {
1247 if (span->filename == NULL || span->filename->str == NULL) {
1248 *filename = strdup("");
1250 *filename = strdup(span->filename->str);
1252 ERR_NOMEM(*filename == NULL, aug);
1262 int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1263 struct pathx *s = NULL, *d = NULL;
1264 struct tree *ts, *td, *t;
1270 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1273 d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1276 r = find_one_node(s, &ts);
1280 r = pathx_expand_tree(d, &td);
1284 /* Don't move SRC into its own descendent */
1287 ERR_THROW(t == ts, aug, AUG_EMVDESC,
1288 "destination %s is a descendant of %s", dst, src);
1290 } while (t != aug->origin);
1292 free_tree(td->children);
1294 td->children = ts->children;
1295 list_for_each(c, td->children) {
1299 td->value = ts->value;
1302 ts->children = NULL;
1304 tree_unlink(aug, ts);
1305 tree_mark_dirty(td);
1315 static void tree_copy_rec(struct tree *src, struct tree *dst) {
1319 list_for_each(c, src->children) {
1320 value = c->value == NULL ? NULL : strdup(c->value);
1321 n = tree_append_s(dst, c->label, value);
1322 tree_copy_rec(c, n);
1326 int aug_cp(struct augeas *aug, const char *src, const char *dst) {
1327 struct pathx *s = NULL, *d = NULL;
1328 struct tree *ts, *td, *t;
1334 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1337 d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1340 r = find_one_node(s, &ts);
1344 r = pathx_expand_tree(d, &td);
1348 /* Don't copy SRC into its own descendent */
1351 ERR_THROW(t == ts, aug, AUG_ECPDESC,
1352 "destination %s is a descendant of %s", dst, src);
1354 } while (t != aug->origin);
1356 tree_set_value(td, ts->value);
1357 free_tree(td->children);
1358 td->children = NULL;
1359 tree_copy_rec(ts, td);
1360 tree_mark_dirty(td);
1370 int aug_rename(struct augeas *aug, const char *src, const char *lbl) {
1371 struct pathx *s = NULL;
1379 ERR_THROW(strchr(lbl, '/') != NULL, aug, AUG_ELABEL,
1380 "Label %s contains a /", lbl);
1382 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1385 for (ts = pathx_first(s); ts != NULL; ts = pathx_next(s)) {
1387 ts->label = strdup(lbl);
1388 tree_mark_dirty(ts);
1401 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1402 struct pathx *p = NULL;
1408 if (matches != NULL)
1411 if (STREQ(pathin, "/")) {
1415 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1418 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1419 if (! TREE_HIDDEN(tree))
1424 if (matches == NULL)
1427 if (ALLOC_N(*matches, cnt) < 0)
1431 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1432 if (TREE_HIDDEN(tree))
1434 (*matches)[i] = path_of_tree(tree);
1435 if ((*matches)[i] == NULL) {
1447 if (matches != NULL) {
1448 if (*matches != NULL) {
1449 for (i=0; i < cnt; i++)
1450 free((*matches)[i]);
1459 /* XFM1 and XFM2 can both be used to save the same file. That is an error
1460 only if the two lenses in the two transforms are actually different. */
1461 static int check_save_dup(struct augeas *aug, const char *path,
1462 struct tree *xfm1, struct tree *xfm2) {
1464 struct lens *l1 = xfm_lens(aug, xfm1, NULL);
1465 struct lens *l2 = xfm_lens(aug, xfm2, NULL);
1467 const char *filename = path + strlen(AUGEAS_FILES_TREE) + 1;
1468 transform_file_error(aug, "mxfm_save", filename,
1469 "Lenses %s and %s could be used to save this file",
1470 xfm_lens_name(xfm1),
1471 xfm_lens_name(xfm2));
1472 ERR_REPORT(aug, AUG_EMXFM,
1473 "Path %s transformable by lens %s and %s",
1475 xfm_lens_name(xfm1),
1476 xfm_lens_name(xfm2));
1482 static int tree_save(struct augeas *aug, struct tree *tree,
1485 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1486 struct tree *load = tree_child_cr(meta, s_load);
1488 // FIXME: We need to detect subtrees that aren't saved by anything
1493 list_for_each(t, tree) {
1496 struct tree *transform = NULL;
1497 if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1501 list_for_each(xfm, load->children) {
1502 if (transform_applies(xfm, tpath)) {
1503 if (transform == NULL || transform == xfm) {
1506 result = check_save_dup(aug, tpath, transform, xfm);
1510 if (transform != NULL) {
1511 int r = transform_save(aug, transform, tpath, t);
1515 if (tree_save(aug, t->children, tpath) == -1)
1524 /* Reset the flags based on what is set in the tree. */
1525 static int update_save_flags(struct augeas *aug) {
1526 const char *savemode ;
1528 aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1529 if (savemode == NULL)
1532 aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1533 if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1534 aug->flags |= AUG_SAVE_NEWFILE;
1535 } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1536 aug->flags |= AUG_SAVE_BACKUP;
1537 } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1538 aug->flags |= AUG_SAVE_NOOP ;
1539 } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1546 static int unlink_removed_files(struct augeas *aug,
1547 struct tree *files, struct tree *meta) {
1548 /* Find all nodes that correspond to a file and might have to be
1549 * unlinked. A node corresponds to a file if it has a child labelled
1550 * 'path', and we only consider it if there are no errors associated
1552 static const char *const file_nodes =
1553 "descendant-or-self::*[path][count(error) = 0]";
1560 for (struct tree *tm = meta->children; tm != NULL;) {
1561 struct tree *tf = tree_child(files, tm->label);
1562 struct tree *next = tm->next;
1564 /* Unlink all files in tm */
1565 struct pathx *px = NULL;
1566 if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1567 aug->symtab, NULL, &px) != PATHX_NOERROR) {
1572 for (struct tree *t = pathx_first(px);
1574 t = pathx_next(px)) {
1575 if (remove_file(aug, t) < 0)
1579 } else if (tf->dirty && ! tree_child(tm, "path")) {
1580 if (unlink_removed_files(aug, tf, tm) < 0)
1588 int aug_save(struct augeas *aug) {
1590 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1591 struct tree *meta_files = tree_child_cr(meta, s_files);
1592 struct tree *files = tree_child_cr(aug->origin, s_files);
1593 struct tree *load = tree_child_cr(meta, s_load);
1597 if (update_save_flags(aug) < 0)
1600 if (files == NULL || meta == NULL || load == NULL)
1603 aug_rm(aug, AUGEAS_EVENTS_SAVED);
1605 list_for_each(xfm, load->children)
1606 transform_validate(aug, xfm);
1609 if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
1612 /* Remove files whose entire subtree was removed. */
1613 if (meta_files != NULL) {
1614 if (unlink_removed_files(aug, files, meta_files) < 0)
1618 if (!(aug->flags & AUG_SAVE_NOOP)) {
1619 tree_clean(aug->origin);
1629 static int print_one(FILE *out, const char *path, const char *value) {
1632 r = fprintf(out, "%s", path);
1635 if (value != NULL) {
1636 char *val = escape(value, -1, STR_ESCAPES);
1637 r = fprintf(out, " = \"%s\"", val);
1642 r = fputc('\n', out);
1648 /* PATH is the path up to TREE's parent */
1649 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1654 list_for_each(tree, start) {
1655 if (TREE_HIDDEN(tree) && ! pr_hidden)
1658 path = path_expand(tree, ppath);
1662 r = print_one(out, path, tree->value);
1665 r = print_rec(out, tree->children, path, pr_hidden);
1677 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1682 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1683 if (TREE_HIDDEN(tree) && ! pr_hidden)
1686 path = path_of_tree(tree);
1689 r = print_one(out, path, tree->value);
1692 r = print_rec(out, tree->children, path, pr_hidden);
1704 int dump_tree(FILE *out, struct tree *tree) {
1708 if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR) {
1713 result = print_tree(out, p, 1);
1718 int aug_text_store(augeas *aug, const char *lens, const char *node,
1727 /* Validate PATH is syntactically correct */
1728 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1732 r = aug_get(aug, node, &src);
1734 ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1735 "Source node %s does not exist", node);
1736 ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1737 "Source node %s has a NULL value", node);
1739 result = text_store(aug, lens, path, src);
1745 int aug_text_retrieve(struct augeas *aug, const char *lens,
1746 const char *node_in, const char *path,
1747 const char *node_out) {
1748 struct tree *tree = NULL;
1751 struct tree *tree_out;
1756 tree = tree_find(aug, path);
1759 r = aug_get(aug, node_in, &src);
1761 ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1762 "Source node %s does not exist", node_in);
1763 ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1764 "Source node %s has a NULL value", node_in);
1766 r = text_retrieve(aug, lens, path, tree, src, &out);
1770 tree_out = tree_find_cr(aug, node_out);
1773 tree_store_value(tree_out, &out);
1783 int aug_transform(struct augeas *aug, const char *lens,
1784 const char *file, int excl) {
1785 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1786 struct tree *load = tree_child_cr(meta, s_load);
1788 int r = 0, result = -1;
1789 struct tree *xfm = NULL, *lns = NULL, *t = NULL;
1790 const char *filter = NULL;
1793 char *lensname = NULL, *xfmname = NULL;
1797 ERR_NOMEM(meta == NULL || load == NULL, aug);
1799 ARG_CHECK(STREQ("", lens), aug, "aug_transform: LENS must not be empty");
1800 ARG_CHECK(STREQ("", file), aug, "aug_transform: FILE must not be empty");
1802 if ((p = strrchr(lens, '.'))) {
1803 lensname = strdup(lens);
1804 xfmname = strndup(lens, p - lens);
1805 ERR_NOMEM(lensname == NULL || xfmname == NULL, aug);
1807 r = xasprintf(&lensname, "%s.lns", lens);
1808 xfmname = strdup(lens);
1809 ERR_NOMEM(r < 0 || xfmname == NULL, aug);
1812 xfm = tree_child_cr(load, xfmname);
1813 ERR_NOMEM(xfm == NULL, aug);
1815 lns = tree_child_cr(xfm, s_lens);
1816 ERR_NOMEM(lns == NULL, aug);
1818 tree_store_value(lns, &lensname);
1822 filter = excl ? s_excl : s_incl;
1823 list_for_each(c, xfm->children) {
1824 if (c->value != NULL && STREQ(c->value, file)
1825 && streqv(c->label, filter)) {
1831 t = tree_append_s(xfm, filter, NULL);
1832 ERR_NOMEM(t == NULL, aug);
1833 r = tree_set_value(t, file);
1834 ERR_NOMEM(r < 0, aug);
1845 int aug_escape_name(augeas *aug, const char *in, char **out) {
1849 ARG_CHECK(in == NULL, aug, "aug_escape_name: IN must not be NULL");
1850 ARG_CHECK(out == NULL, aug, "aug_escape_name: OUT must not be NULL");
1852 result = pathx_escape_name(in, out);
1853 ERR_NOMEM(result < 0, aug);
1859 int aug_load_file(struct augeas *aug, const char *file) {
1861 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1862 struct tree *load = tree_child_cr(meta, s_load);
1863 char *tree_path = NULL;
1868 ERR_NOMEM(load == NULL, aug);
1870 list_for_each(xfm, load->children) {
1871 if (filter_matches(xfm, file)) {
1872 transform_load(aug, xfm, file);
1878 ERR_THROW(!found, aug, AUG_ENOLENS,
1879 "can not determine lens to load file %s", file);
1881 /* Mark the nodes we just loaded as clean so they won't get saved
1882 without additional modifications */
1883 r = xasprintf(&tree_path, "/files/%s", file);
1884 ERR_NOMEM(r < 0, aug);
1886 struct tree *t = tree_fpath(aug, tree_path);
1898 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
1904 if (pathin == NULL || strlen(pathin) == 0) {
1908 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1911 result = print_tree(out, p, 0);
1918 int aug_source(const augeas *aug, const char *path, char **file_path) {
1920 struct pathx *p = NULL;
1925 ARG_CHECK(file_path == NULL, aug,
1926 "aug_source_file: FILE_PATH must not be NULL");
1929 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1932 r = pathx_find_one(p, &match);
1934 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
1936 ERR_THROW(r == 0, aug, AUG_ENOMATCH, "There is no node matching %s",
1938 while (!(ROOT_P(match) || match->file))
1939 match = match->parent;
1942 *file_path = path_of_tree(match);
1943 ERR_NOMEM(file_path == NULL, aug);
1953 void aug_close(struct augeas *aug) {
1957 /* There's no point in bothering with api_entry/api_exit here */
1958 free_tree(aug->origin);
1959 unref(aug->modules, module);
1960 if (aug->error->exn != NULL) {
1961 aug->error->exn->ref = 0;
1962 free_value(aug->error->exn);
1963 aug->error->exn = NULL;
1965 free((void *) aug->root);
1966 free(aug->modpathz);
1967 free_symtab(aug->symtab);
1968 unref(aug->error->info, info);
1969 free(aug->error->details);
1974 int __aug_load_module_file(struct augeas *aug, const char *filename) {
1976 int r = load_module_file(aug, filename, NULL);
1981 int tree_equal(const struct tree *t1, const struct tree *t2) {
1982 while (t1 != NULL && t2 != NULL) {
1983 if (!streqv(t1->label, t2->label))
1985 if (!streqv(t1->value, t2->value))
1987 if (! tree_equal(t1->children, t2->children))
1996 * Error reporting API
1998 int aug_error(struct augeas *aug) {
1999 return aug->error->code;
2002 const char *aug_error_message(struct augeas *aug) {
2003 aug_errcode_t errcode = aug->error->code;
2005 if (errcode >= ARRAY_CARDINALITY(errcodes))
2006 errcode = AUG_EINTERNAL;
2007 return errcodes[errcode];
2010 const char *aug_error_minor_message(struct augeas *aug) {
2011 return aug->error->minor_details;
2014 const char *aug_error_details(struct augeas *aug) {
2015 return aug->error->details;
2020 * indent-tabs-mode: nil