2 * augeas.c: the core data structure for storing key/value pairs
4 * Copyright (C) 2007-2011 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"
36 #include <libxml/tree.h>
38 /* Some popular labels that we use in /augeas */
39 static const char *const s_augeas = "augeas";
40 static const char *const s_files = "files";
41 static const char *const s_load = "load";
42 static const char *const s_pathx = "pathx";
43 static const char *const s_error = "error";
44 static const char *const s_pos = "pos";
45 static const char *const s_vars = "variables";
47 #define TREE_HIDDEN(tree) ((tree)->label == NULL)
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 */
84 static void tree_mark_dirty(struct tree *tree) {
88 } while (tree != tree->parent && !tree->dirty);
92 void tree_clean(struct tree *tree) {
94 list_for_each(c, tree->children)
100 struct tree *tree_child(struct tree *tree, const char *label) {
104 list_for_each(child, tree->children) {
105 if (streqv(label, child->label))
111 struct tree *tree_child_cr(struct tree *tree, const char *label) {
112 static struct tree *child = NULL;
117 child = tree_child(tree, label);
119 char *l = strdup(label);
122 child = tree_append(tree, l, NULL);
127 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
131 for (int i=0; i < n; i++) {
132 const char *l = va_arg(ap, const char *);
133 tree = tree_child_cr(tree, l);
139 struct tree *tree_find(struct augeas *aug, const char *path) {
140 struct pathx *p = NULL;
141 struct tree *result = NULL;
144 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
147 r = pathx_find_one(p, &result);
149 "Multiple matches for %s when only one was expected",
159 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
160 struct pathx *p = NULL;
161 struct tree *result = NULL;
164 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
167 r = pathx_expand_tree(p, &result);
169 ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
175 void tree_store_value(struct tree *tree, char **value) {
176 if (streqv(tree->value, *value)) {
181 if (tree->value != NULL) {
185 if (*value != NULL) {
186 tree->value = *value;
189 tree_mark_dirty(tree);
192 int tree_set_value(struct tree *tree, const char *value) {
195 if (streqv(tree->value, value))
202 tree_store_value(tree, &v);
206 static void store_error(const struct augeas *aug, const char *label, const char *value,
211 ensure(nentries % 2 == 0, aug);
212 tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
216 tree_set_value(tree, value);
218 va_start(ap, nentries);
219 for (int i=0; i < nentries; i += 2) {
220 char *l = va_arg(ap, char *);
221 char *v = va_arg(ap, char *);
222 struct tree *t = tree_child_cr(tree, l);
224 tree_set_value(t, v);
231 /* Report pathx errors in /augeas/pathx/error */
232 static void store_pathx_error(const struct augeas *aug) {
233 if (aug->error->code != AUG_EPATHX)
236 store_error(aug, s_pathx, aug->error->minor_details,
237 2, s_pos, aug->error->details);
240 struct pathx *pathx_aug_parse(const struct augeas *aug,
242 struct tree *root_ctx,
243 const char *path, bool need_nodeset) {
244 struct pathx *result;
245 struct error *err = err_of_aug(aug);
250 pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
254 /* Find the tree stored in AUGEAS_CONTEXT */
255 struct tree *tree_root_ctx(const struct augeas *aug) {
256 struct pathx *p = NULL;
257 struct tree *match = NULL;
258 const char *ctx_path;
261 p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
264 r = pathx_find_one(p, &match);
265 ERR_THROW(r > 1, aug, AUG_EMMATCH,
266 "There are %d nodes matching %s, expecting one",
269 if (match == NULL || match->value == NULL || *match->value == '\0')
272 /* Clean via augrun's helper to ensure it's valid */
273 ctx_path = cleanpath(match->value);
276 p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
279 r = pathx_find_one(p, &match);
280 ERR_THROW(r > 1, aug, AUG_EMMATCH,
281 "There are %d nodes matching the context %s, expecting one",
292 struct tree *tree_append(struct tree *parent,
293 char *label, char *value) {
294 struct tree *result = make_tree(label, value, parent, NULL);
296 list_append(parent->children, result);
300 static struct tree *tree_append_s(struct tree *parent,
301 const char *l0, char *v) {
303 char *l = strdup(l0);
307 result = tree_append(parent, l, v);
313 static struct tree *tree_from_transform(struct augeas *aug,
315 struct transform *xfm) {
316 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
317 struct tree *load = NULL, *txfm = NULL, *t;
321 ERR_NOMEM(meta == NULL, aug);
323 load = tree_child_cr(meta, s_load);
324 ERR_NOMEM(load == NULL, aug);
329 txfm = tree_append_s(load, modname, NULL);
330 ERR_NOMEM(txfm == NULL, aug);
332 r = asprintf(&v, "@%s", modname);
333 ERR_NOMEM(r < 0, aug);
335 t = tree_append_s(txfm, "lens", v);
336 ERR_NOMEM(t == NULL, aug);
339 list_for_each(f, xfm->filter) {
340 const char *l = f->include ? strdup("incl") : strdup("excl");
341 v = strdup(f->glob->str);
342 ERR_NOMEM(v == NULL, aug);
343 t = tree_append_s(txfm, l, v);
344 ERR_NOMEM(t == NULL, aug);
353 /* Save user locale and switch to C locale */
355 static void save_locale(struct augeas *aug) {
356 if (aug->c_locale == NULL) {
357 aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
358 ERR_NOMEM(aug->c_locale == NULL, aug);
361 aug->user_locale = uselocale(aug->c_locale);
366 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
370 static void restore_locale(struct augeas *aug) {
371 uselocale(aug->user_locale);
372 aug->user_locale = NULL;
375 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
378 /* Clean up old error messages every time we enter through the public
379 * API. Since we make internal calls through the public API, we keep a
380 * count of how many times a public API call was made, and only reset when
381 * that count is 0. That requires that all public functions enclose their
382 * work within a matching pair of api_entry/api_exit calls.
384 void api_entry(const struct augeas *aug) {
385 struct error *err = ((struct augeas *) aug)->error;
387 ((struct augeas *) aug)->api_entries += 1;
389 if (aug->api_entries > 1)
393 save_locale((struct augeas *) aug);
396 void api_exit(const struct augeas *aug) {
397 assert(aug->api_entries > 0);
398 ((struct augeas *) aug)->api_entries -= 1;
399 if (aug->api_entries == 0) {
400 store_pathx_error(aug);
401 restore_locale((struct augeas *) aug);
405 static int init_root(struct augeas *aug, const char *root0) {
407 root0 = getenv(AUGEAS_ROOT_ENV);
408 if (root0 == NULL || root0[0] == '\0')
411 aug->root = strdup(root0);
412 if (aug->root == NULL)
415 if (aug->root[strlen(aug->root)-1] != SEP) {
416 if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
418 strcat((char *) aug->root, "/");
423 static int init_loadpath(struct augeas *aug, const char *loadpath) {
426 aug->modpathz = NULL;
428 if (loadpath != NULL) {
429 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
430 loadpath, PATH_SEP_CHAR);
434 char *env = getenv(AUGEAS_LENS_ENV);
436 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
441 if (!(aug->flags & AUG_NO_STDINC)) {
442 r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
445 r = argz_add(&aug->modpathz, &aug->nmodpath,
446 AUGEAS_LENS_DIST_DIR);
450 /* Clean up trailing slashes */
451 if (aug->nmodpath > 0) {
452 argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
454 const char *e = aug->modpathz + strlen(aug->modpathz);
455 for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
458 while (*p == '/') p += 1;
459 if (*p == '\0' || *p == PATH_SEP_CHAR)
471 aug->modpathz = NULL;
472 r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
481 static void init_save_mode(struct augeas *aug) {
482 const char *v = AUG_SAVE_OVERWRITE_TEXT;
484 if (aug->flags & AUG_SAVE_NEWFILE) {
485 v = AUG_SAVE_NEWFILE_TEXT;
486 } else if (aug->flags & AUG_SAVE_BACKUP) {
487 v = AUG_SAVE_BACKUP_TEXT;
488 } else if (aug->flags & AUG_SAVE_NOOP) {
489 v = AUG_SAVE_NOOP_TEXT;
492 aug_set(aug, AUGEAS_META_SAVE_MODE, v);
495 struct augeas *aug_init(const char *root, const char *loadpath,
496 unsigned int flags) {
497 struct augeas *result;
498 struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
500 bool close_on_error = true;
502 if (tree_root == NULL)
505 if (ALLOC(result) < 0)
507 if (ALLOC(result->error) < 0)
509 if (make_ref(result->error->info) < 0)
511 result->error->info->error = result->error;
512 result->error->info->filename = dup_string("(unknown file)");
513 if (result->error->info->filename == NULL)
515 result->error->aug = result;
517 result->origin = make_tree_origin(tree_root);
518 if (result->origin == NULL) {
519 free_tree(tree_root);
525 result->flags = flags;
527 r = init_root(result, root);
528 ERR_NOMEM(r < 0, result);
530 result->origin->children->label = strdup(s_augeas);
532 /* We are now initialized enough that we can dare return RESULT even
533 * when we encounter errors if the caller so wishes */
534 close_on_error = !(flags & AUG_NO_ERR_CLOSE);
536 r = init_loadpath(result, loadpath);
537 ERR_NOMEM(r < 0, result);
539 /* We report the root dir in AUGEAS_META_ROOT, but we only use the
540 value we store internally, to avoid any problems with
541 AUGEAS_META_ROOT getting changed. */
542 aug_set(result, AUGEAS_META_ROOT, result->root);
545 /* Set the default path context */
546 aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
549 for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
550 aug_set(result, static_nodes[i][0], static_nodes[i][1]);
554 init_save_mode(result);
557 const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
558 aug_set(result, AUGEAS_SPAN_OPTION, v);
561 if (interpreter_init(result) == -1)
564 list_for_each(modl, result->modules) {
565 struct transform *xform = modl->autoload;
568 tree_from_transform(result, modl->name, xform);
571 if (!(result->flags & AUG_NO_LOAD))
572 if (aug_load(result) < 0)
579 if (close_on_error) {
583 if (result != NULL && result->api_entries > 0)
588 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
592 pathx_symtab_remove_descendants(aug->symtab, tree);
594 while (tree->children != NULL)
595 tree_unlink(tree->children);
598 static void tree_mark_files(struct tree *tree) {
599 if (tree_child(tree, "path") != NULL) {
600 tree_mark_dirty(tree);
602 list_for_each(c, tree->children) {
608 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
614 if ((p = tree_child(tree, "path")) != NULL) {
615 aug_rm(aug, p->value);
618 struct tree *c = tree->children;
620 struct tree *next = c->next;
621 tree_rm_dirty_files(aug, c);
627 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
628 struct tree *protect) {
632 struct tree *c = tree->children;
634 struct tree *next = c->next;
635 tree_rm_dirty_leaves(aug, c, protect);
639 if (tree != protect && tree->children == NULL)
643 int aug_load(struct augeas *aug) {
644 const char *option = NULL;
645 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
646 struct tree *meta_files = tree_child_cr(meta, s_files);
647 struct tree *files = tree_child_cr(aug->origin, s_files);
648 struct tree *load = tree_child_cr(meta, s_load);
649 struct tree *vars = tree_child_cr(meta, s_vars);
653 ERR_NOMEM(load == NULL, aug);
655 /* To avoid unnecessary loads of files, we reload an existing file in
657 * (1) mark all file nodes under /augeas/files as dirty (and only those)
658 * (2) process all files matched by a lens; we check (in
659 * transform_load) if the file has been modified. If it has, we
660 * reparse it. Either way, we clear the dirty flag. We also need to
661 * reread the file if part or all of it has been modified in the
662 * tree but not been saved yet
663 * (3) remove all files from the tree that still have a dirty entry
664 * under /augeas/files. Those files are not processed by any lens
666 * (4) Remove entries from /augeas/files and /files that correspond
667 * to directories without any files of interest
670 /* update flags according to option value */
671 if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
672 if (strcmp(option, AUG_ENABLE) == 0) {
673 aug->flags |= AUG_ENABLE_SPAN;
675 aug->flags &= ~AUG_ENABLE_SPAN;
679 tree_clean(meta_files);
680 tree_mark_files(meta_files);
682 list_for_each(xfm, load->children) {
683 if (transform_validate(aug, xfm) == 0)
684 transform_load(aug, xfm);
687 /* This makes it possible to spot 'directories' that are now empty
688 * because we removed their file contents */
691 tree_rm_dirty_files(aug, meta_files);
692 tree_rm_dirty_leaves(aug, meta_files, meta_files);
693 tree_rm_dirty_leaves(aug, files, files);
695 tree_clean(aug->origin);
697 list_for_each(v, vars->children) {
698 aug_defvar(aug, v->label, v->value);
709 static int find_one_node(struct pathx *p, struct tree **match) {
710 struct error *err = err_of_pathx(p);
711 int r = pathx_find_one(p, match);
717 report_error(err, AUG_ENOMATCH, NULL);
720 report_error(err, AUG_EMMATCH, NULL);
726 int aug_get(const struct augeas *aug, const char *path, const char **value) {
727 struct pathx *p = NULL;
733 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
739 r = pathx_find_one(p, &match);
741 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
744 if (r == 1 && value != NULL)
745 *value = match->value;
756 static void record_var_meta(struct augeas *aug, const char *name,
758 /* Record the definition of the variable */
759 struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
760 ERR_NOMEM(tree == NULL, aug);
762 tree = tree_child(tree, name);
766 tree = tree_child_cr(tree, name);
767 ERR_NOMEM(tree == NULL, aug);
768 tree_set_value(tree, expr);
774 int aug_defvar(augeas *aug, const char *name, const char *expr) {
775 struct pathx *p = NULL;
781 result = pathx_symtab_undefine(&(aug->symtab), name);
783 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
785 result = pathx_symtab_define(&(aug->symtab), name, p);
789 record_var_meta(aug, name, expr);
797 int aug_defnode(augeas *aug, const char *name, const char *expr,
798 const char *value, int *created) {
811 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
814 if (pathx_first(p) == NULL) {
815 r = pathx_expand_tree(p, &tree);
824 r = tree_set_value(tree, value);
827 result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
828 char *e = path_of_tree(tree);
829 ERR_NOMEM(e == NULL, aug)
830 record_var_meta(aug, name, e);
834 result = pathx_symtab_define(&(aug->symtab), name, p);
835 record_var_meta(aug, name, expr);
848 struct tree *tree_set(struct pathx *p, const char *value) {
852 r = pathx_expand_tree(p, &tree);
856 r = tree_set_value(tree, value);
862 int aug_set(struct augeas *aug, const char *path, const char *value) {
868 /* Get-out clause, in case context is broken */
869 struct tree *root_ctx = NULL;
870 if (STRNEQ(path, AUGEAS_CONTEXT))
871 root_ctx = tree_root_ctx(aug);
873 p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
876 result = tree_set(p, value) == NULL ? -1 : 0;
886 int aug_setm(struct augeas *aug, const char *base,
887 const char *sub, const char *value) {
888 struct pathx *bx = NULL, *sx = NULL;
889 struct tree *bt, *st;
894 bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
897 if (sub != NULL && STREQ(sub, "."))
901 for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
903 /* Handle subnodes of BT */
904 sx = pathx_aug_parse(aug, bt, NULL, sub, true);
906 if (pathx_first(sx) != NULL) {
907 /* Change existing subnodes matching SUB */
908 for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
909 r = tree_set_value(st, value);
910 ERR_NOMEM(r < 0, aug);
914 /* Create a new subnode matching SUB */
915 r = pathx_expand_tree(sx, &st);
918 r = tree_set_value(st, value);
919 ERR_NOMEM(r < 0, aug);
925 /* Set nodes matching BT directly */
926 r = tree_set_value(bt, value);
927 ERR_NOMEM(r < 0, aug);
940 int tree_insert(struct pathx *p, const char *label, int before) {
941 struct tree *new = NULL, *match;
943 if (strchr(label, SEP) != NULL)
946 if (find_one_node(p, &match) < 0)
949 new = make_tree(strdup(label), NULL, match->parent, NULL);
950 if (new == NULL || new->label == NULL)
954 list_insert_before(new, match, new->parent->children);
956 new->next = match->next;
965 int aug_insert(struct augeas *aug, const char *path, const char *label,
967 struct pathx *p = NULL;
972 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
975 result = tree_insert(p, label, before);
982 struct tree *make_tree(char *label, char *value, struct tree *parent,
983 struct tree *children) {
990 tree->parent = parent;
991 tree->children = children;
992 list_for_each(c, tree->children)
995 tree_mark_dirty(tree);
1001 struct tree *make_tree_origin(struct tree *root) {
1002 struct tree *origin = NULL;
1004 origin = make_tree(NULL, NULL, NULL, root);
1008 origin->parent = origin;
1012 /* Free one tree node */
1013 static void free_tree_node(struct tree *tree) {
1017 if (tree->span != NULL)
1018 free_span(tree->span);
1024 /* Recursively free the whole tree TREE and all its siblings */
1025 int free_tree(struct tree *tree) {
1028 while (tree != NULL) {
1029 struct tree *del = tree;
1031 cnt += free_tree(del->children);
1032 free_tree_node(del);
1039 int tree_unlink(struct tree *tree) {
1042 assert (tree->parent != NULL);
1043 list_remove(tree, tree->parent->children);
1044 tree_mark_dirty(tree->parent);
1045 result = free_tree(tree->children) + 1;
1046 free_tree_node(tree);
1050 int tree_rm(struct pathx *p) {
1051 struct tree *tree, **del;
1052 int cnt = 0, ndel = 0, i;
1054 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1055 if (! TREE_HIDDEN(tree))
1062 if (ALLOC_N(del, ndel) < 0) {
1067 for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1068 if (TREE_HIDDEN(tree))
1070 pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1075 for (i = 0; i < ndel; i++)
1076 cnt += tree_unlink(del[i]);
1082 int aug_rm(struct augeas *aug, const char *path) {
1083 struct pathx *p = NULL;
1088 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1091 result = tree_rm(p);
1102 int aug_span(struct augeas *aug, const char *path, char **filename,
1103 uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1104 uint *span_start, uint *span_end) {
1105 struct pathx *p = NULL;
1107 struct tree *tree = NULL;
1112 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1115 tree = pathx_first(p);
1118 ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1119 ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1120 ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1124 if (label_start != NULL)
1125 *label_start = span->label_start;
1127 if (label_end != NULL)
1128 *label_end = span->label_end;
1130 if (value_start != NULL)
1131 *value_start = span->value_start;
1133 if (value_end != NULL)
1134 *value_end = span->value_end;
1136 if (span_start != NULL)
1137 *span_start = span->span_start;
1139 if (span_end != NULL)
1140 *span_end = span->span_end;
1142 /* We are safer here, make sure we have a filename */
1143 if (filename != NULL) {
1144 if (span->filename == NULL || span->filename->str == NULL) {
1145 *filename = strdup("");
1147 *filename = strdup(span->filename->str);
1149 ERR_NOMEM(*filename == NULL, aug);
1159 int tree_replace(struct augeas *aug, const char *path, struct tree *sub) {
1160 struct tree *parent;
1161 struct pathx *p = NULL;
1164 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1171 parent = tree_set(p, NULL);
1175 list_append(parent->children, sub);
1176 list_for_each(s, sub) {
1186 int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1187 struct pathx *s = NULL, *d = NULL;
1188 struct tree *ts, *td, *t;
1194 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1197 d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1200 r = find_one_node(s, &ts);
1204 r = pathx_expand_tree(d, &td);
1208 /* Don't move SRC into its own descendent */
1211 ERR_THROW(t == ts, aug, AUG_EMVDESC,
1212 "destination %s is a descendant of %s", dst, src);
1214 } while (t != aug->origin);
1216 free_tree(td->children);
1218 td->children = ts->children;
1219 list_for_each(c, td->children) {
1223 td->value = ts->value;
1226 ts->children = NULL;
1229 tree_mark_dirty(td);
1239 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1240 struct pathx *p = NULL;
1246 if (matches != NULL)
1249 if (STREQ(pathin, "/")) {
1253 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1256 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1257 if (! TREE_HIDDEN(tree))
1262 if (matches == NULL)
1265 if (ALLOC_N(*matches, cnt) < 0)
1269 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1270 if (TREE_HIDDEN(tree))
1272 (*matches)[i] = path_of_tree(tree);
1273 if ((*matches)[i] == NULL) {
1285 if (matches != NULL) {
1286 if (*matches != NULL) {
1287 for (i=0; i < cnt; i++)
1288 free((*matches)[i]);
1297 static int tree_save(struct augeas *aug, struct tree *tree,
1300 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1301 struct tree *load = tree_child_cr(meta, s_load);
1303 // FIXME: We need to detect subtrees that aren't saved by anything
1308 list_for_each(t, tree) {
1311 struct tree *transform = NULL;
1312 if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1316 list_for_each(xfm, load->children) {
1317 if (transform_applies(xfm, tpath)) {
1318 if (transform == NULL || transform == xfm) {
1321 const char *filename =
1322 tpath + strlen(AUGEAS_FILES_TREE) + 1;
1323 transform_file_error(aug, "mxfm_save", filename,
1324 "Lenses %s and %s could be used to save this file",
1325 xfm_lens_name(transform),
1326 xfm_lens_name(xfm));
1327 ERR_REPORT(aug, AUG_EMXFM,
1328 "Path %s transformable by lens %s and %s",
1330 xfm_lens_name(transform),
1331 xfm_lens_name(xfm));
1336 if (transform != NULL) {
1337 int r = transform_save(aug, transform, tpath, t);
1341 if (tree_save(aug, t->children, tpath) == -1)
1350 /* Reset the flags based on what is set in the tree. */
1351 static int update_save_flags(struct augeas *aug) {
1352 const char *savemode ;
1354 aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1355 if (savemode == NULL)
1358 aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1359 if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1360 aug->flags |= AUG_SAVE_NEWFILE;
1361 } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1362 aug->flags |= AUG_SAVE_BACKUP;
1363 } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1364 aug->flags |= AUG_SAVE_NOOP ;
1365 } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1372 static int unlink_removed_files(struct augeas *aug,
1373 struct tree *files, struct tree *meta) {
1374 /* Find all nodes that correspond to a file and might have to be
1375 * unlinked. A node corresponds to a file if it has a child labelled
1376 * 'path', and we only consider it if there are no errors associated
1378 static const char *const file_nodes =
1379 "descendant-or-self::*[path][count(error) = 0]";
1386 for (struct tree *tm = meta->children; tm != NULL;) {
1387 struct tree *tf = tree_child(files, tm->label);
1388 struct tree *next = tm->next;
1390 /* Unlink all files in tm */
1391 struct pathx *px = NULL;
1392 if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1393 aug->symtab, NULL, &px) != PATHX_NOERROR) {
1397 for (struct tree *t = pathx_first(px);
1399 t = pathx_next(px)) {
1400 remove_file(aug, t);
1403 } else if (tf->dirty && ! tree_child(tm, "path")) {
1404 if (unlink_removed_files(aug, tf, tm) < 0)
1412 int aug_save(struct augeas *aug) {
1414 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1415 struct tree *meta_files = tree_child_cr(meta, s_files);
1416 struct tree *files = tree_child_cr(aug->origin, s_files);
1417 struct tree *load = tree_child_cr(meta, s_load);
1421 if (update_save_flags(aug) < 0)
1424 if (files == NULL || meta == NULL || load == NULL)
1427 aug_rm(aug, AUGEAS_EVENTS_SAVED);
1429 list_for_each(xfm, load->children)
1430 transform_validate(aug, xfm);
1433 list_for_each(t, files->children) {
1434 if (tree_save(aug, t, AUGEAS_FILES_TREE) == -1)
1437 /* Remove files whose entire subtree was removed. */
1438 if (meta_files != NULL) {
1439 if (unlink_removed_files(aug, files, meta_files) < 0)
1443 if (!(aug->flags & AUG_SAVE_NOOP)) {
1444 tree_clean(aug->origin);
1454 static int print_one(FILE *out, const char *path, const char *value) {
1457 r = fprintf(out, "%s", path);
1460 if (value != NULL) {
1461 char *val = escape(value, -1, STR_ESCAPES);
1462 r = fprintf(out, " = \"%s\"", val);
1467 r = fputc('\n', out);
1473 /* PATH is the path up to TREE's parent */
1474 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1479 list_for_each(tree, start) {
1480 if (TREE_HIDDEN(tree) && ! pr_hidden)
1483 path = path_expand(tree, ppath);
1487 r = print_one(out, path, tree->value);
1490 r = print_rec(out, tree->children, path, pr_hidden);
1502 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1507 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1508 if (TREE_HIDDEN(tree) && ! pr_hidden)
1511 path = path_of_tree(tree);
1514 r = print_one(out, path, tree->value);
1517 r = print_rec(out, tree->children, path, pr_hidden);
1529 int dump_tree(FILE *out, struct tree *tree) {
1533 if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR)
1536 result = print_tree(out, p, 1);
1541 static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
1542 const char *pathin) {
1546 prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
1551 prop = xmlSetProp(elem, BAD_CAST "file",
1552 BAD_CAST tree->span->filename->str);
1557 if (pathin != NULL) {
1558 prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
1562 if (tree->value != NULL) {
1563 value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
1564 BAD_CAST tree->value);
1573 static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
1574 const char *pathin) {
1578 elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
1581 r = to_xml_one(elem, start, pathin);
1585 list_for_each(tree, start->children) {
1586 if (TREE_HIDDEN(tree))
1588 r = to_xml_rec(elem, tree, NULL);
1598 static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
1604 *xml = xmlNewNode(NULL, BAD_CAST "augeas");
1607 expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
1611 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1612 if (TREE_HIDDEN(tree))
1614 path = path_of_tree(tree);
1617 r = to_xml_rec(*xml, tree, path);
1630 int aug_to_xml(const struct augeas *aug, const char *pathin,
1631 xmlNode **xmldoc, unsigned int flags) {
1637 ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
1638 ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
1640 if (pathin == NULL || strlen(pathin) == 1) {
1644 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1646 result = tree_to_xml(p, xmldoc, pathin);
1647 ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
1659 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
1665 if (pathin == NULL || strlen(pathin) == 0) {
1669 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1672 result = print_tree(out, p, 0);
1682 void aug_close(struct augeas *aug) {
1686 /* There's no point in bothering with api_entry/api_exit here */
1687 free_tree(aug->origin);
1688 unref(aug->modules, module);
1689 free((void *) aug->root);
1690 free(aug->modpathz);
1691 free_symtab(aug->symtab);
1692 unref(aug->error->info, info);
1693 free(aug->error->details);
1698 int __aug_load_module_file(struct augeas *aug, const char *filename) {
1700 int r = load_module_file(aug, filename);
1705 int tree_equal(const struct tree *t1, const struct tree *t2) {
1706 while (t1 != NULL && t2 != NULL) {
1707 if (!streqv(t1->label, t2->label))
1709 if (!streqv(t1->value, t2->value))
1711 if (! tree_equal(t1->children, t2->children))
1720 * Error reporting API
1722 int aug_error(struct augeas *aug) {
1723 return aug->error->code;
1726 const char *aug_error_message(struct augeas *aug) {
1727 aug_errcode_t errcode = aug->error->code;
1729 if (errcode >= ARRAY_CARDINALITY(errcodes))
1730 errcode = AUG_EINTERNAL;
1731 return errcodes[errcode];
1734 const char *aug_error_minor_message(struct augeas *aug) {
1735 return aug->error->minor_details;
1738 const char *aug_error_details(struct augeas *aug) {
1739 return aug->error->details;
1744 * indent-tabs-mode: nil