2 * augeas.c: the core data structure for storing key/value pairs
4 * Copyright (C) 2007-2015 David Lutterkort
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Author: David Lutterkort <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";
46 static const char *const s_lens = "lens";
47 static const char *const s_excl = "excl";
48 static const char *const s_incl = "incl";
50 #define TREE_HIDDEN(tree) ((tree)->label == NULL)
52 #define AUGEAS_META_PATHX_FUNC AUGEAS_META_TREE "/version/pathx/functions"
54 static const char *const static_nodes[][2] = {
55 { AUGEAS_FILES_TREE, NULL },
56 { AUGEAS_META_TREE "/variables", NULL },
57 { AUGEAS_META_TREE "/version", PACKAGE_VERSION },
58 { AUGEAS_META_TREE "/version/save/mode[1]", AUG_SAVE_BACKUP_TEXT },
59 { AUGEAS_META_TREE "/version/save/mode[2]", AUG_SAVE_NEWFILE_TEXT },
60 { AUGEAS_META_TREE "/version/save/mode[3]", AUG_SAVE_NOOP_TEXT },
61 { AUGEAS_META_TREE "/version/save/mode[4]", AUG_SAVE_OVERWRITE_TEXT },
62 { AUGEAS_META_TREE "/version/defvar/expr", NULL },
63 { AUGEAS_META_PATHX_FUNC "/count", NULL },
64 { AUGEAS_META_PATHX_FUNC "/glob", NULL },
65 { AUGEAS_META_PATHX_FUNC "/label", NULL },
66 { AUGEAS_META_PATHX_FUNC "/last", NULL },
67 { AUGEAS_META_PATHX_FUNC "/position", NULL },
68 { AUGEAS_META_PATHX_FUNC "/regexp", NULL }
71 static const char *const errcodes[] = {
72 "No error", /* AUG_NOERROR */
73 "Cannot allocate memory", /* AUG_ENOMEM */
74 "Internal error (please file a bug)", /* AUG_EINTERNAL */
75 "Invalid path expression", /* AUG_EPATHX */
76 "No match for path expression", /* AUG_ENOMATCH */
77 "Too many matches for path expression", /* AUG_EMMATCH */
78 "Syntax error in lens definition", /* AUG_ESYNTAX */
79 "Lens not found", /* AUG_ENOLENS */
80 "Multiple transforms", /* AUG_EMXFM */
81 "Node has no span info", /* AUG_ENOSPAN */
82 "Cannot move node into its descendant", /* AUG_EMVDESC */
83 "Failed to execute command", /* AUG_ECMDRUN */
84 "Invalid argument in function call", /* AUG_EBADARG */
85 "Invalid label", /* AUG_ELABEL */
86 "Cannot copy node into its descendant" /* AUG_ECPDESC */
89 static void tree_mark_dirty(struct tree *tree) {
93 } while (tree != tree->parent && !tree->dirty);
97 void tree_clean(struct tree *tree) {
99 list_for_each(c, tree->children)
105 struct tree *tree_child(struct tree *tree, const char *label) {
109 list_for_each(child, tree->children) {
110 if (streqv(label, child->label))
116 struct tree *tree_child_cr(struct tree *tree, const char *label) {
117 static struct tree *child = NULL;
122 child = tree_child(tree, label);
124 char *l = strdup(label);
127 child = tree_append(tree, l, NULL);
132 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
136 for (int i=0; i < n; i++) {
137 const char *l = va_arg(ap, const char *);
138 tree = tree_child_cr(tree, l);
144 static struct tree *tree_fpath_int(struct augeas *aug, const char *fpath,
147 char *steps = NULL, *step = NULL;
149 struct tree *result = NULL;
151 r = argz_create_sep(fpath, '/', &steps, &nsteps);
152 ERR_NOMEM(r < 0, aug);
153 result = aug->origin;
154 while ((step = argz_next(steps, nsteps, step))) {
156 result = tree_child_cr(result, step);
157 ERR_THROW(result == NULL, aug, AUG_ENOMEM,
158 "while searching %s: can not create %s", fpath, step);
161 result = tree_child(result, step);
174 struct tree *tree_fpath(struct augeas *aug, const char *fpath) {
175 return tree_fpath_int(aug, fpath, false);
178 struct tree *tree_fpath_cr(struct augeas *aug, const char *fpath) {
179 return tree_fpath_int(aug, fpath, true);
182 struct tree *tree_find(struct augeas *aug, const char *path) {
183 struct pathx *p = NULL;
184 struct tree *result = NULL;
187 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
190 r = pathx_find_one(p, &result);
192 "Multiple matches for %s when only one was expected",
202 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
203 struct pathx *p = NULL;
204 struct tree *result = NULL;
207 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
210 r = pathx_expand_tree(p, &result);
212 ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
218 void tree_store_value(struct tree *tree, char **value) {
219 if (streqv(tree->value, *value)) {
224 if (tree->value != NULL) {
228 if (*value != NULL) {
229 tree->value = *value;
232 tree_mark_dirty(tree);
235 int tree_set_value(struct tree *tree, const char *value) {
238 if (streqv(tree->value, value))
245 tree_store_value(tree, &v);
249 static void store_error(const struct augeas *aug, const char *label, const char *value,
254 ensure(nentries % 2 == 0, aug);
255 tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
259 tree_set_value(tree, value);
261 va_start(ap, nentries);
262 for (int i=0; i < nentries; i += 2) {
263 char *l = va_arg(ap, char *);
264 char *v = va_arg(ap, char *);
265 struct tree *t = tree_child_cr(tree, l);
267 tree_set_value(t, v);
274 /* Report pathx errors in /augeas/pathx/error */
275 static void store_pathx_error(const struct augeas *aug) {
276 if (aug->error->code != AUG_EPATHX)
279 store_error(aug, s_pathx, aug->error->minor_details,
280 2, s_pos, aug->error->details);
283 struct pathx *pathx_aug_parse(const struct augeas *aug,
285 struct tree *root_ctx,
286 const char *path, bool need_nodeset) {
287 struct pathx *result;
288 struct error *err = err_of_aug(aug);
293 pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
297 /* Find the tree stored in AUGEAS_CONTEXT */
298 struct tree *tree_root_ctx(const struct augeas *aug) {
299 struct pathx *p = NULL;
300 struct tree *match = NULL;
301 const char *ctx_path;
304 p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
307 r = pathx_find_one(p, &match);
308 ERR_THROW(r > 1, aug, AUG_EMMATCH,
309 "There are %d nodes matching %s, expecting one",
312 if (match == NULL || match->value == NULL || *match->value == '\0')
315 /* Clean via augrun's helper to ensure it's valid */
316 ctx_path = cleanpath(match->value);
319 p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
322 if (pathx_first(p) == NULL) {
323 r = pathx_expand_tree(p, &match);
326 r = tree_set_value(match, NULL);
330 r = pathx_find_one(p, &match);
331 ERR_THROW(r > 1, aug, AUG_EMMATCH,
332 "There are %d nodes matching the context %s, expecting one",
344 struct tree *tree_append(struct tree *parent,
345 char *label, char *value) {
346 struct tree *result = make_tree(label, value, parent, NULL);
348 list_append(parent->children, result);
352 static struct tree *tree_append_s(struct tree *parent,
353 const char *l0, char *v) {
362 result = tree_append(parent, l, v);
368 static struct tree *tree_from_transform(struct augeas *aug,
370 struct transform *xfm) {
371 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
372 struct tree *load = NULL, *txfm = NULL, *t;
376 ERR_NOMEM(meta == NULL, aug);
378 load = tree_child_cr(meta, s_load);
379 ERR_NOMEM(load == NULL, aug);
384 txfm = tree_append_s(load, modname, NULL);
385 ERR_NOMEM(txfm == NULL, aug);
387 r = asprintf(&v, "@%s", modname);
388 ERR_NOMEM(r < 0, aug);
390 t = tree_append_s(txfm, s_lens, v);
391 ERR_NOMEM(t == NULL, aug);
394 list_for_each(f, xfm->filter) {
395 const char *l = f->include ? s_incl : s_excl;
396 v = strdup(f->glob->str);
397 ERR_NOMEM(v == NULL, aug);
398 t = tree_append_s(txfm, l, v);
399 ERR_NOMEM(t == NULL, aug);
404 tree_unlink(aug, txfm);
408 /* Save user locale and switch to C locale */
410 static void save_locale(struct augeas *aug) {
411 if (aug->c_locale == NULL) {
412 aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
413 ERR_NOMEM(aug->c_locale == NULL, aug);
416 aug->user_locale = uselocale(aug->c_locale);
421 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
425 static void restore_locale(struct augeas *aug) {
426 uselocale(aug->user_locale);
427 aug->user_locale = NULL;
430 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
433 /* Clean up old error messages every time we enter through the public
434 * API. Since we make internal calls through the public API, we keep a
435 * count of how many times a public API call was made, and only reset when
436 * that count is 0. That requires that all public functions enclose their
437 * work within a matching pair of api_entry/api_exit calls.
439 void api_entry(const struct augeas *aug) {
440 struct error *err = ((struct augeas *) aug)->error;
442 ((struct augeas *) aug)->api_entries += 1;
444 if (aug->api_entries > 1)
448 save_locale((struct augeas *) aug);
451 void api_exit(const struct augeas *aug) {
452 assert(aug->api_entries > 0);
453 ((struct augeas *) aug)->api_entries -= 1;
454 if (aug->api_entries == 0) {
455 store_pathx_error(aug);
456 restore_locale((struct augeas *) aug);
460 static int init_root(struct augeas *aug, const char *root0) {
462 root0 = getenv(AUGEAS_ROOT_ENV);
463 if (root0 == NULL || root0[0] == '\0')
466 aug->root = strdup(root0);
467 if (aug->root == NULL)
470 if (aug->root[strlen(aug->root)-1] != SEP) {
471 if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
473 strcat((char *) aug->root, "/");
478 static int init_loadpath(struct augeas *aug, const char *loadpath) {
481 aug->modpathz = NULL;
483 if (loadpath != NULL) {
484 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
485 loadpath, PATH_SEP_CHAR);
489 char *env = getenv(AUGEAS_LENS_ENV);
491 r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
496 if (!(aug->flags & AUG_NO_STDINC)) {
497 r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
500 r = argz_add(&aug->modpathz, &aug->nmodpath,
501 AUGEAS_LENS_DIST_DIR);
505 /* Clean up trailing slashes */
506 if (aug->nmodpath > 0) {
507 argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
509 const char *e = aug->modpathz + strlen(aug->modpathz);
510 for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
513 while (*p == '/') p += 1;
514 if (*p == '\0' || *p == PATH_SEP_CHAR)
526 aug->modpathz = NULL;
527 r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
536 static void init_save_mode(struct augeas *aug) {
537 const char *v = AUG_SAVE_OVERWRITE_TEXT;
539 if (aug->flags & AUG_SAVE_NEWFILE) {
540 v = AUG_SAVE_NEWFILE_TEXT;
541 } else if (aug->flags & AUG_SAVE_BACKUP) {
542 v = AUG_SAVE_BACKUP_TEXT;
543 } else if (aug->flags & AUG_SAVE_NOOP) {
544 v = AUG_SAVE_NOOP_TEXT;
547 aug_set(aug, AUGEAS_META_SAVE_MODE, v);
550 struct augeas *aug_init(const char *root, const char *loadpath,
551 unsigned int flags) {
552 struct augeas *result;
553 struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
555 bool close_on_error = true;
557 if (tree_root == NULL)
560 if (ALLOC(result) < 0)
562 if (ALLOC(result->error) < 0)
564 if (make_ref(result->error->info) < 0)
566 result->error->info->error = result->error;
567 result->error->info->filename = dup_string("(unknown file)");
568 if (result->error->info->filename == NULL)
570 result->error->aug = result;
572 result->origin = make_tree_origin(tree_root);
573 if (result->origin == NULL) {
574 free_tree(tree_root);
580 result->flags = flags;
582 r = init_root(result, root);
583 ERR_NOMEM(r < 0, result);
585 result->origin->children->label = strdup(s_augeas);
587 /* We are now initialized enough that we can dare return RESULT even
588 * when we encounter errors if the caller so wishes */
589 close_on_error = !(flags & AUG_NO_ERR_CLOSE);
591 r = init_loadpath(result, loadpath);
592 ERR_NOMEM(r < 0, result);
594 /* We report the root dir in AUGEAS_META_ROOT, but we only use the
595 value we store internally, to avoid any problems with
596 AUGEAS_META_ROOT getting changed. */
597 aug_set(result, AUGEAS_META_ROOT, result->root);
600 /* Set the default path context */
601 aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
604 for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
605 aug_set(result, static_nodes[i][0], static_nodes[i][1]);
609 init_save_mode(result);
612 const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
613 aug_set(result, AUGEAS_SPAN_OPTION, v);
616 if (interpreter_init(result) == -1)
619 list_for_each(modl, result->modules) {
620 struct transform *xform = modl->autoload;
623 tree_from_transform(result, modl->name, xform);
626 if (!(result->flags & AUG_NO_LOAD))
627 if (aug_load(result) < 0)
634 if (close_on_error) {
638 if (result != NULL && result->api_entries > 0)
643 /* Free one tree node */
644 static void free_tree_node(struct tree *tree) {
648 if (tree->span != NULL)
649 free_span(tree->span);
655 /* Only unlink; assume we know TREE is not in the symtab */
656 static int tree_unlink_raw(struct tree *tree) {
659 assert (tree->parent != NULL);
660 list_remove(tree, tree->parent->children);
661 tree_mark_dirty(tree->parent);
662 result = free_tree(tree->children) + 1;
663 free_tree_node(tree);
667 int tree_unlink(struct augeas *aug, struct tree *tree) {
670 pathx_symtab_remove_descendants(aug->symtab, tree);
671 return tree_unlink_raw(tree);
674 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
678 pathx_symtab_remove_descendants(aug->symtab, tree);
680 while (tree->children != NULL)
681 tree_unlink_raw(tree->children);
684 static void tree_mark_files(struct tree *tree) {
685 if (tree_child(tree, "path") != NULL) {
686 tree_mark_dirty(tree);
688 list_for_each(c, tree->children) {
694 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
700 if ((p = tree_child(tree, "path")) != NULL) {
701 tree_unlink(aug, tree_fpath(aug, p->value));
702 tree_unlink(aug, tree);
704 struct tree *c = tree->children;
706 struct tree *next = c->next;
707 tree_rm_dirty_files(aug, c);
713 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
714 struct tree *protect) {
718 struct tree *c = tree->children;
720 struct tree *next = c->next;
721 tree_rm_dirty_leaves(aug, c, protect);
725 if (tree != protect && tree->children == NULL)
726 tree_unlink(aug, tree);
729 int aug_load(struct augeas *aug) {
730 const char *option = NULL;
731 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
732 struct tree *meta_files = tree_child_cr(meta, s_files);
733 struct tree *files = tree_child_cr(aug->origin, s_files);
734 struct tree *load = tree_child_cr(meta, s_load);
735 struct tree *vars = tree_child_cr(meta, s_vars);
739 ERR_NOMEM(load == NULL, aug);
741 /* To avoid unnecessary loads of files, we reload an existing file in
743 * (1) mark all file nodes under /augeas/files as dirty (and only those)
744 * (2) process all files matched by a lens; we check (in
745 * transform_load) if the file has been modified. If it has, we
746 * reparse it. Either way, we clear the dirty flag. We also need to
747 * reread the file if part or all of it has been modified in the
748 * tree but not been saved yet
749 * (3) remove all files from the tree that still have a dirty entry
750 * under /augeas/files. Those files are not processed by any lens
752 * (4) Remove entries from /augeas/files and /files that correspond
753 * to directories without any files of interest
756 /* update flags according to option value */
757 if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
758 if (strcmp(option, AUG_ENABLE) == 0) {
759 aug->flags |= AUG_ENABLE_SPAN;
761 aug->flags &= ~AUG_ENABLE_SPAN;
765 tree_clean(meta_files);
766 tree_mark_files(meta_files);
768 list_for_each(xfm, load->children) {
769 if (transform_validate(aug, xfm) == 0)
770 transform_load(aug, xfm);
773 /* This makes it possible to spot 'directories' that are now empty
774 * because we removed their file contents */
777 tree_rm_dirty_files(aug, meta_files);
778 tree_rm_dirty_leaves(aug, meta_files, meta_files);
779 tree_rm_dirty_leaves(aug, files, files);
781 tree_clean(aug->origin);
783 list_for_each(v, vars->children) {
784 aug_defvar(aug, v->label, v->value);
795 static int find_one_node(struct pathx *p, struct tree **match) {
796 struct error *err = err_of_pathx(p);
797 int r = pathx_find_one(p, match);
803 report_error(err, AUG_ENOMATCH, NULL);
806 report_error(err, AUG_EMMATCH, NULL);
812 int aug_get(const struct augeas *aug, const char *path, const char **value) {
813 struct pathx *p = NULL;
822 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
825 r = pathx_find_one(p, &match);
827 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
830 if (r == 1 && value != NULL)
831 *value = match->value;
842 int aug_label(const struct augeas *aug, const char *path, const char **label) {
843 struct pathx *p = NULL;
849 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
855 r = pathx_find_one(p, &match);
857 ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
860 if (r == 1 && label != NULL)
861 *label = match->label;
872 static void record_var_meta(struct augeas *aug, const char *name,
874 /* Record the definition of the variable */
875 struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
876 ERR_NOMEM(tree == NULL, aug);
878 tree_unlink(aug, tree_child(tree, name));
880 tree = tree_child_cr(tree, name);
881 ERR_NOMEM(tree == NULL, aug);
882 tree_set_value(tree, expr);
888 int aug_defvar(augeas *aug, const char *name, const char *expr) {
889 struct pathx *p = NULL;
895 result = pathx_symtab_undefine(&(aug->symtab), name);
897 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
899 result = pathx_symtab_define(&(aug->symtab), name, p);
903 record_var_meta(aug, name, expr);
911 int aug_defnode(augeas *aug, const char *name, const char *expr,
912 const char *value, int *created) {
925 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
928 if (pathx_first(p) == NULL) {
929 r = pathx_expand_tree(p, &tree);
938 r = tree_set_value(tree, value);
941 result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
942 char *e = path_of_tree(tree);
943 ERR_NOMEM(e == NULL, aug)
944 record_var_meta(aug, name, e);
948 result = pathx_symtab_define(&(aug->symtab), name, p);
949 record_var_meta(aug, name, expr);
962 struct tree *tree_set(struct pathx *p, const char *value) {
966 r = pathx_expand_tree(p, &tree);
970 r = tree_set_value(tree, value);
976 int aug_set(struct augeas *aug, const char *path, const char *value) {
982 /* Get-out clause, in case context is broken */
983 struct tree *root_ctx = NULL;
984 if (STRNEQ(path, AUGEAS_CONTEXT))
985 root_ctx = tree_root_ctx(aug);
987 p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
990 result = tree_set(p, value) == NULL ? -1 : 0;
1000 int aug_setm(struct augeas *aug, const char *base,
1001 const char *sub, const char *value) {
1002 struct pathx *bx = NULL, *sx = NULL;
1003 struct tree *bt, *st;
1008 bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
1011 if (sub != NULL && STREQ(sub, "."))
1015 for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
1017 /* Handle subnodes of BT */
1018 sx = pathx_aug_parse(aug, bt, NULL, sub, true);
1020 if (pathx_first(sx) != NULL) {
1021 /* Change existing subnodes matching SUB */
1022 for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
1023 r = tree_set_value(st, value);
1024 ERR_NOMEM(r < 0, aug);
1028 /* Create a new subnode matching SUB */
1029 r = pathx_expand_tree(sx, &st);
1032 r = tree_set_value(st, value);
1033 ERR_NOMEM(r < 0, aug);
1039 /* Set nodes matching BT directly */
1040 r = tree_set_value(bt, value);
1041 ERR_NOMEM(r < 0, aug);
1054 int tree_insert(struct pathx *p, const char *label, int before) {
1055 struct tree *new = NULL, *match;
1057 if (strchr(label, SEP) != NULL)
1060 if (find_one_node(p, &match) < 0)
1063 new = make_tree(strdup(label), NULL, match->parent, NULL);
1064 if (new == NULL || new->label == NULL)
1068 list_insert_before(new, match, new->parent->children);
1070 new->next = match->next;
1079 int aug_insert(struct augeas *aug, const char *path, const char *label,
1081 struct pathx *p = NULL;
1086 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1089 result = tree_insert(p, label, before);
1096 struct tree *make_tree(char *label, char *value, struct tree *parent,
1097 struct tree *children) {
1099 if (ALLOC(tree) < 0)
1102 tree->label = label;
1103 tree->value = value;
1104 tree->parent = parent;
1105 tree->children = children;
1106 list_for_each(c, tree->children)
1109 tree_mark_dirty(tree);
1115 struct tree *make_tree_origin(struct tree *root) {
1116 struct tree *origin = NULL;
1118 origin = make_tree(NULL, NULL, NULL, root);
1122 origin->parent = origin;
1126 /* Recursively free the whole tree TREE and all its siblings */
1127 int free_tree(struct tree *tree) {
1130 while (tree != NULL) {
1131 struct tree *del = tree;
1133 cnt += free_tree(del->children);
1134 free_tree_node(del);
1141 int tree_rm(struct pathx *p) {
1142 struct tree *tree, **del;
1143 int cnt = 0, ndel = 0, i;
1145 /* set ndel to the number of trees we could possibly delete */
1146 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1147 if (! TREE_HIDDEN(tree))
1154 if (ALLOC_N(del, ndel) < 0) {
1159 for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1160 if (TREE_HIDDEN(tree))
1162 pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1163 /* Collect the tree nodes that actually need to be deleted in
1164 del. Mark the root of every subtree we are going to free by
1165 setting tree->added. Only add a node to del if none of its
1166 ancestors would have been freed by the time we get to freeing
1167 that node; this avoids double frees for situations where the
1168 path expression matches both /node and /node/child as unlinking
1169 /node implicitly unlinks /node/child */
1171 for (struct tree *t = tree; live && ! ROOT_P(t); t = t->parent) {
1181 /* ndel now means: the number of trees we are actually going to delete */
1184 for (i = 0; i < ndel; i++) {
1185 if (del[i] != NULL) {
1186 cnt += tree_unlink_raw(del[i]);
1194 int aug_rm(struct augeas *aug, const char *path) {
1195 struct pathx *p = NULL;
1200 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1203 result = tree_rm(p);
1214 int aug_span(struct augeas *aug, const char *path, char **filename,
1215 uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1216 uint *span_start, uint *span_end) {
1217 struct pathx *p = NULL;
1219 struct tree *tree = NULL;
1224 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1227 tree = pathx_first(p);
1230 ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1231 ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1232 ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1236 if (label_start != NULL)
1237 *label_start = span->label_start;
1239 if (label_end != NULL)
1240 *label_end = span->label_end;
1242 if (value_start != NULL)
1243 *value_start = span->value_start;
1245 if (value_end != NULL)
1246 *value_end = span->value_end;
1248 if (span_start != NULL)
1249 *span_start = span->span_start;
1251 if (span_end != NULL)
1252 *span_end = span->span_end;
1254 /* We are safer here, make sure we have a filename */
1255 if (filename != NULL) {
1256 if (span->filename == NULL || span->filename->str == NULL) {
1257 *filename = strdup("");
1259 *filename = strdup(span->filename->str);
1261 ERR_NOMEM(*filename == NULL, aug);
1271 int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1272 struct pathx *s = NULL, *d = NULL;
1273 struct tree *ts, *td, *t;
1279 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1282 d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1285 r = find_one_node(s, &ts);
1289 r = pathx_expand_tree(d, &td);
1293 /* Don't move SRC into its own descendent */
1296 ERR_THROW(t == ts, aug, AUG_EMVDESC,
1297 "destination %s is a descendant of %s", dst, src);
1299 } while (t != aug->origin);
1301 free_tree(td->children);
1303 td->children = ts->children;
1304 list_for_each(c, td->children) {
1308 td->value = ts->value;
1311 ts->children = NULL;
1313 tree_unlink(aug, ts);
1314 tree_mark_dirty(td);
1324 static void tree_copy_rec(struct tree *src, struct tree *dst) {
1328 list_for_each(c, src->children) {
1329 value = c->value == NULL ? NULL : strdup(c->value);
1330 n = tree_append_s(dst, c->label, value);
1331 tree_copy_rec(c, n);
1335 int aug_cp(struct augeas *aug, const char *src, const char *dst) {
1336 struct pathx *s = NULL, *d = NULL;
1337 struct tree *ts, *td, *t;
1343 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1346 d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1349 r = find_one_node(s, &ts);
1353 r = pathx_expand_tree(d, &td);
1357 /* Don't copy SRC into its own descendent */
1360 ERR_THROW(t == ts, aug, AUG_ECPDESC,
1361 "destination %s is a descendant of %s", dst, src);
1363 } while (t != aug->origin);
1365 tree_set_value(td, ts->value);
1366 free_tree(td->children);
1367 td->children = NULL;
1368 tree_copy_rec(ts, td);
1369 tree_mark_dirty(td);
1379 int aug_rename(struct augeas *aug, const char *src, const char *lbl) {
1380 struct pathx *s = NULL;
1388 ERR_THROW(strchr(lbl, '/') != NULL, aug, AUG_ELABEL,
1389 "Label %s contains a /", lbl);
1391 s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1394 for (ts = pathx_first(s); ts != NULL; ts = pathx_next(s)) {
1396 ts->label = strdup(lbl);
1397 tree_mark_dirty(ts);
1410 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1411 struct pathx *p = NULL;
1417 if (matches != NULL)
1420 if (STREQ(pathin, "/")) {
1424 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1427 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1428 if (! TREE_HIDDEN(tree))
1433 if (matches == NULL)
1436 if (ALLOC_N(*matches, cnt) < 0)
1440 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1441 if (TREE_HIDDEN(tree))
1443 (*matches)[i] = path_of_tree(tree);
1444 if ((*matches)[i] == NULL) {
1456 if (matches != NULL) {
1457 if (*matches != NULL) {
1458 for (i=0; i < cnt; i++)
1459 free((*matches)[i]);
1468 static int tree_save(struct augeas *aug, struct tree *tree,
1471 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1472 struct tree *load = tree_child_cr(meta, s_load);
1474 // FIXME: We need to detect subtrees that aren't saved by anything
1479 list_for_each(t, tree) {
1482 struct tree *transform = NULL;
1483 if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1487 list_for_each(xfm, load->children) {
1488 if (transform_applies(xfm, tpath)) {
1489 if (transform == NULL || transform == xfm) {
1492 const char *filename =
1493 tpath + strlen(AUGEAS_FILES_TREE) + 1;
1494 transform_file_error(aug, "mxfm_save", filename,
1495 "Lenses %s and %s could be used to save this file",
1496 xfm_lens_name(transform),
1497 xfm_lens_name(xfm));
1498 ERR_REPORT(aug, AUG_EMXFM,
1499 "Path %s transformable by lens %s and %s",
1501 xfm_lens_name(transform),
1502 xfm_lens_name(xfm));
1507 if (transform != NULL) {
1508 int r = transform_save(aug, transform, tpath, t);
1512 if (tree_save(aug, t->children, tpath) == -1)
1521 /* Reset the flags based on what is set in the tree. */
1522 static int update_save_flags(struct augeas *aug) {
1523 const char *savemode ;
1525 aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1526 if (savemode == NULL)
1529 aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1530 if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1531 aug->flags |= AUG_SAVE_NEWFILE;
1532 } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1533 aug->flags |= AUG_SAVE_BACKUP;
1534 } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1535 aug->flags |= AUG_SAVE_NOOP ;
1536 } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1543 static int unlink_removed_files(struct augeas *aug,
1544 struct tree *files, struct tree *meta) {
1545 /* Find all nodes that correspond to a file and might have to be
1546 * unlinked. A node corresponds to a file if it has a child labelled
1547 * 'path', and we only consider it if there are no errors associated
1549 static const char *const file_nodes =
1550 "descendant-or-self::*[path][count(error) = 0]";
1557 for (struct tree *tm = meta->children; tm != NULL;) {
1558 struct tree *tf = tree_child(files, tm->label);
1559 struct tree *next = tm->next;
1561 /* Unlink all files in tm */
1562 struct pathx *px = NULL;
1563 if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1564 aug->symtab, NULL, &px) != PATHX_NOERROR) {
1568 for (struct tree *t = pathx_first(px);
1570 t = pathx_next(px)) {
1571 if (remove_file(aug, t) < 0)
1575 } else if (tf->dirty && ! tree_child(tm, "path")) {
1576 if (unlink_removed_files(aug, tf, tm) < 0)
1584 int aug_save(struct augeas *aug) {
1586 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1587 struct tree *meta_files = tree_child_cr(meta, s_files);
1588 struct tree *files = tree_child_cr(aug->origin, s_files);
1589 struct tree *load = tree_child_cr(meta, s_load);
1593 if (update_save_flags(aug) < 0)
1596 if (files == NULL || meta == NULL || load == NULL)
1599 aug_rm(aug, AUGEAS_EVENTS_SAVED);
1601 list_for_each(xfm, load->children)
1602 transform_validate(aug, xfm);
1605 if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
1608 /* Remove files whose entire subtree was removed. */
1609 if (meta_files != NULL) {
1610 if (unlink_removed_files(aug, files, meta_files) < 0)
1614 if (!(aug->flags & AUG_SAVE_NOOP)) {
1615 tree_clean(aug->origin);
1625 static int print_one(FILE *out, const char *path, const char *value) {
1628 r = fprintf(out, "%s", path);
1631 if (value != NULL) {
1632 char *val = escape(value, -1, STR_ESCAPES);
1633 r = fprintf(out, " = \"%s\"", val);
1638 r = fputc('\n', out);
1644 /* PATH is the path up to TREE's parent */
1645 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1650 list_for_each(tree, start) {
1651 if (TREE_HIDDEN(tree) && ! pr_hidden)
1654 path = path_expand(tree, ppath);
1658 r = print_one(out, path, tree->value);
1661 r = print_rec(out, tree->children, path, pr_hidden);
1673 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1678 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1679 if (TREE_HIDDEN(tree) && ! pr_hidden)
1682 path = path_of_tree(tree);
1685 r = print_one(out, path, tree->value);
1688 r = print_rec(out, tree->children, path, pr_hidden);
1700 int dump_tree(FILE *out, struct tree *tree) {
1704 if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR)
1707 result = print_tree(out, p, 1);
1712 static int to_xml_span(xmlNodePtr elem, const char *pfor, int start, int end) {
1716 xmlNodePtr span_elem;
1718 span_elem = xmlNewChild(elem, NULL, BAD_CAST "span", NULL);
1719 if (span_elem == NULL)
1722 prop = xmlSetProp(span_elem, BAD_CAST "for", BAD_CAST pfor);
1726 /* Format and set the start property */
1727 r = xasprintf(&buf, "%d", start);
1731 prop = xmlSetProp(span_elem, BAD_CAST "start", BAD_CAST buf);
1736 /* Format and set the end property */
1737 r = xasprintf(&buf, "%d", end);
1741 prop = xmlSetProp(span_elem, BAD_CAST "end", BAD_CAST buf);
1749 static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
1750 const char *pathin) {
1755 prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
1760 struct span *span = tree->span;
1762 prop = xmlSetProp(elem, BAD_CAST "file",
1763 BAD_CAST span->filename->str);
1767 r = to_xml_span(elem, "label", span->label_start, span->label_end);
1771 r = to_xml_span(elem, "value", span->value_start, span->value_end);
1775 r = to_xml_span(elem, "node", span->span_start, span->span_end);
1780 if (pathin != NULL) {
1781 prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
1785 if (tree->value != NULL) {
1786 value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
1787 BAD_CAST tree->value);
1796 static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
1797 const char *pathin) {
1801 elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
1804 r = to_xml_one(elem, start, pathin);
1808 list_for_each(tree, start->children) {
1809 if (TREE_HIDDEN(tree))
1811 r = to_xml_rec(elem, tree, NULL);
1821 static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
1827 *xml = xmlNewNode(NULL, BAD_CAST "augeas");
1830 expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
1834 for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1835 if (TREE_HIDDEN(tree))
1837 path = path_of_tree(tree);
1840 r = to_xml_rec(*xml, tree, path);
1853 int aug_text_store(augeas *aug, const char *lens, const char *node,
1862 /* Validate PATH is syntactically correct */
1863 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1867 r = aug_get(aug, node, &src);
1869 ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1870 "Source node %s does not exist", node);
1871 ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1872 "Source node %s has a NULL value", node);
1874 result = text_store(aug, lens, path, src);
1880 int aug_text_retrieve(struct augeas *aug, const char *lens,
1881 const char *node_in, const char *path,
1882 const char *node_out) {
1883 struct tree *tree = NULL;
1886 struct tree *tree_out;
1891 tree = tree_find(aug, path);
1894 r = aug_get(aug, node_in, &src);
1896 ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1897 "Source node %s does not exist", node_in);
1898 ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1899 "Source node %s has a NULL value", node_in);
1901 r = text_retrieve(aug, lens, path, tree, src, &out);
1905 tree_out = tree_find_cr(aug, node_out);
1908 tree_store_value(tree_out, &out);
1918 int aug_to_xml(const struct augeas *aug, const char *pathin,
1919 xmlNode **xmldoc, unsigned int flags) {
1925 ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
1926 ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
1928 if (pathin == NULL || strlen(pathin) == 0 || strcmp(pathin, "/") == 0) {
1932 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1934 result = tree_to_xml(p, xmldoc, pathin);
1935 ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
1947 int aug_transform(struct augeas *aug, const char *lens,
1948 const char *file, int excl) {
1949 struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1950 struct tree *load = tree_child_cr(meta, s_load);
1952 int r = 0, result = -1;
1953 struct tree *xfm = NULL, *lns = NULL, *t = NULL;
1954 const char *filter = NULL;
1957 char *lensname = NULL, *xfmname = NULL;
1961 ERR_NOMEM(meta == NULL || load == NULL, aug);
1963 ARG_CHECK(STREQ("", lens), aug, "aug_transform: LENS must not be empty");
1964 ARG_CHECK(STREQ("", file), aug, "aug_transform: FILE must not be empty");
1966 if ((p = strrchr(lens, '.'))) {
1967 lensname = strdup(lens);
1968 xfmname = strndup(lens, p - lens);
1969 ERR_NOMEM(lensname == NULL || xfmname == NULL, aug);
1971 r = xasprintf(&lensname, "%s.lns", lens);
1972 xfmname = strdup(lens);
1973 ERR_NOMEM(r < 0 || xfmname == NULL, aug);
1976 xfm = tree_child_cr(load, xfmname);
1977 ERR_NOMEM(xfm == NULL, aug);
1979 lns = tree_child_cr(xfm, s_lens);
1980 ERR_NOMEM(lns == NULL, aug);
1982 tree_store_value(lns, &lensname);
1986 filter = excl ? s_excl : s_incl;
1987 list_for_each(c, xfm->children) {
1988 if (c->value != NULL && STREQ(c->value, file)
1989 && streqv(c->label, filter)) {
1995 t = tree_append_s(xfm, filter, NULL);
1996 ERR_NOMEM(t == NULL, aug);
1997 r = tree_set_value(t, file);
1998 ERR_NOMEM(r < 0, aug);
2009 int aug_escape_name(augeas *aug, const char *in, char **out) {
2013 ARG_CHECK(in == NULL, aug, "aug_escape_name: IN must not be NULL");
2014 ARG_CHECK(out == NULL, aug, "aug_escape_name: OUT must not be NULL");
2016 result = pathx_escape_name(in, out);
2017 ERR_NOMEM(result < 0, aug);
2023 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
2029 if (pathin == NULL || strlen(pathin) == 0) {
2033 p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
2036 result = print_tree(out, p, 0);
2046 void aug_close(struct augeas *aug) {
2050 /* There's no point in bothering with api_entry/api_exit here */
2051 free_tree(aug->origin);
2052 unref(aug->modules, module);
2053 if (aug->error->exn != NULL) {
2054 aug->error->exn->ref = 0;
2055 free_value(aug->error->exn);
2056 aug->error->exn = NULL;
2058 free((void *) aug->root);
2059 free(aug->modpathz);
2060 free_symtab(aug->symtab);
2061 unref(aug->error->info, info);
2062 free(aug->error->details);
2067 int __aug_load_module_file(struct augeas *aug, const char *filename) {
2069 int r = load_module_file(aug, filename, NULL);
2074 int tree_equal(const struct tree *t1, const struct tree *t2) {
2075 while (t1 != NULL && t2 != NULL) {
2076 if (!streqv(t1->label, t2->label))
2078 if (!streqv(t1->value, t2->value))
2080 if (! tree_equal(t1->children, t2->children))
2089 * Error reporting API
2091 int aug_error(struct augeas *aug) {
2092 return aug->error->code;
2095 const char *aug_error_message(struct augeas *aug) {
2096 aug_errcode_t errcode = aug->error->code;
2098 if (errcode >= ARRAY_CARDINALITY(errcodes))
2099 errcode = AUG_EINTERNAL;
2100 return errcodes[errcode];
2103 const char *aug_error_minor_message(struct augeas *aug) {
2104 return aug->error->minor_details;
2107 const char *aug_error_details(struct augeas *aug) {
2108 return aug->error->details;
2113 * indent-tabs-mode: nil