Imported Upstream version 1.8.0
[platform/upstream/augeas.git] / src / augeas.c
1 /*
2  * augeas.c: the core data structure for storing key/value pairs
3  *
4  * Copyright (C) 2007-2017 David Lutterkort
5  *
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.
10  *
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.
15  *
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
19  *
20  * Author: David Lutterkort <dlutter@redhat.com>
21  */
22
23 #include <config.h>
24 #include "augeas.h"
25 #include "internal.h"
26 #include "memory.h"
27 #include "syntax.h"
28 #include "transform.h"
29 #include "errcode.h"
30
31 #include <fnmatch.h>
32 #include <argz.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <locale.h>
36
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";
48
49 #define AUGEAS_META_PATHX_FUNC AUGEAS_META_TREE "/version/pathx/functions"
50
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 }
66 };
67
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 */
84 };
85
86 static void tree_mark_dirty(struct tree *tree) {
87     do {
88         tree->dirty = 1;
89         tree = tree->parent;
90     } while (tree != tree->parent && !tree->dirty);
91     tree->dirty = 1;
92 }
93
94 void tree_clean(struct tree *tree) {
95     if (tree->dirty) {
96         list_for_each(c, tree->children)
97             tree_clean(c);
98     }
99     tree->dirty = 0;
100 }
101
102 struct tree *tree_child(struct tree *tree, const char *label) {
103     if (tree == NULL)
104         return NULL;
105
106     list_for_each(child, tree->children) {
107         if (streqv(label, child->label))
108             return child;
109     }
110     return NULL;
111 }
112
113 struct tree *tree_child_cr(struct tree *tree, const char *label) {
114     static struct tree *child = NULL;
115
116     if (tree == NULL)
117         return NULL;
118
119     child = tree_child(tree, label);
120     if (child == NULL) {
121         char *l = strdup(label);
122         if (l == NULL)
123             return NULL;
124         child = tree_append(tree, l, NULL);
125     }
126     return child;
127 }
128
129 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
130     va_list ap;
131
132     va_start(ap, 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);
136     }
137     va_end(ap);
138     return tree;
139 }
140
141 static struct tree *tree_fpath_int(struct augeas *aug, const char *fpath,
142                                    bool create) {
143     int r;
144     char *steps = NULL, *step = NULL;
145     size_t nsteps = 0;
146     struct tree *result = NULL;
147
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))) {
152         if (create) {
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);
156         } else {
157             /* Lookup only */
158             result = tree_child(result, step);
159             if (result == NULL)
160                 goto done;
161         }
162     }
163  done:
164     free(steps);
165     return result;
166  error:
167     result = NULL;
168     goto done;
169 }
170
171 struct tree *tree_fpath(struct augeas *aug, const char *fpath) {
172     return tree_fpath_int(aug, fpath, false);
173 }
174
175 struct tree *tree_fpath_cr(struct augeas *aug, const char *fpath) {
176     return tree_fpath_int(aug, fpath, true);
177 }
178
179 struct tree *tree_find(struct augeas *aug, const char *path) {
180     struct pathx *p = NULL;
181     struct tree *result = NULL;
182     int r;
183
184     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
185     ERR_BAIL(aug);
186
187     r = pathx_find_one(p, &result);
188     BUG_ON(r > 1, aug,
189            "Multiple matches for %s when only one was expected",
190            path);
191  done:
192     free_pathx(p);
193     return result;
194  error:
195     result = NULL;
196     goto done;
197 }
198
199 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
200     struct pathx *p = NULL;
201     struct tree *result = NULL;
202     int r;
203
204     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
205     ERR_BAIL(aug);
206
207     r = pathx_expand_tree(p, &result);
208     ERR_BAIL(aug);
209     ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
210  error:
211     free_pathx(p);
212     return result;
213 }
214
215 void tree_store_value(struct tree *tree, char **value) {
216     if (streqv(tree->value, *value)) {
217         free(*value);
218         *value = NULL;
219         return;
220     }
221     if (tree->value != NULL) {
222         free(tree->value);
223         tree->value = NULL;
224     }
225     if (*value != NULL) {
226         tree->value = *value;
227         *value = NULL;
228     }
229     tree_mark_dirty(tree);
230 }
231
232 int tree_set_value(struct tree *tree, const char *value) {
233     char *v = NULL;
234
235     if (streqv(tree->value, value))
236         return 0;
237     if (value != NULL) {
238         v = strdup(value);
239         if (v == NULL)
240             return -1;
241     }
242     tree_store_value(tree, &v);
243     return 0;
244 }
245
246 static void store_error(const struct augeas *aug, const char *label, const char *value,
247                  int nentries, ...) {
248     va_list ap;
249     struct tree *tree;
250
251     ensure(nentries % 2 == 0, aug);
252     tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
253     if (tree == NULL)
254         return;
255
256     tree_set_value(tree, value);
257
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);
263         if (t != NULL)
264             tree_set_value(t, v);
265     }
266     va_end(ap);
267  error:
268     return;
269 }
270
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)
274         return;
275
276     store_error(aug, s_pathx, aug->error->minor_details,
277                 2, s_pos, aug->error->details);
278 }
279
280 struct pathx *pathx_aug_parse(const struct augeas *aug,
281                               struct tree *tree,
282                               struct tree *root_ctx,
283                               const char *path, bool need_nodeset) {
284     struct pathx *result;
285     struct error *err = err_of_aug(aug);
286
287     if (tree == NULL)
288         tree = aug->origin;
289
290     pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
291     return result;
292 }
293
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;
299     int r;
300
301     p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
302     ERR_BAIL(aug);
303
304     r = pathx_find_one(p, &match);
305     ERR_THROW(r > 1, aug, AUG_EMMATCH,
306               "There are %d nodes matching %s, expecting one",
307               r, AUGEAS_CONTEXT);
308
309     if (match == NULL || match->value == NULL || *match->value == '\0')
310         goto error;
311
312     /* Clean via augrun's helper to ensure it's valid */
313     ctx_path = cleanpath(match->value);
314     free_pathx(p);
315
316     p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
317     ERR_BAIL(aug);
318
319     if (pathx_first(p) == NULL) {
320         r = pathx_expand_tree(p, &match);
321         if (r < 0)
322             goto done;
323         r = tree_set_value(match, NULL);
324         if (r < 0)
325             goto done;
326     } else {
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",
330                   r, ctx_path);
331     }
332
333  done:
334     free_pathx(p);
335     return match;
336  error:
337     match = NULL;
338     goto done;
339 }
340
341 struct tree *tree_append(struct tree *parent,
342                          char *label, char *value) {
343     struct tree *result = make_tree(label, value, parent, NULL);
344     if (result != NULL)
345         list_append(parent->children, result);
346     return result;
347 }
348
349 static struct tree *tree_append_s(struct tree *parent,
350                                   const char *l0, char *v) {
351     struct tree *result;
352     char *l;
353
354     if (l0 == NULL) {
355         return NULL;
356     } else {
357       l = strdup(l0);
358     }
359     result = tree_append(parent, l, v);
360     if (result == NULL)
361         free(l);
362     return result;
363 }
364
365 static struct tree *tree_from_transform(struct augeas *aug,
366                                         const char *modname,
367                                         struct transform *xfm) {
368     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
369     struct tree *load = NULL, *txfm = NULL, *t;
370     char *v = NULL;
371     int r;
372
373     ERR_NOMEM(meta == NULL, aug);
374
375     load = tree_child_cr(meta, s_load);
376     ERR_NOMEM(load == NULL, aug);
377
378     if (modname == NULL)
379         modname = "_";
380
381     txfm = tree_append_s(load, modname, NULL);
382     ERR_NOMEM(txfm == NULL, aug);
383
384     r = asprintf(&v, "@%s", modname);
385     ERR_NOMEM(r < 0, aug);
386
387     t = tree_append_s(txfm, s_lens, v);
388     ERR_NOMEM(t == NULL, aug);
389     v = NULL;
390
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);
397     }
398     return txfm;
399  error:
400     free(v);
401     tree_unlink(aug, txfm);
402     return NULL;
403 }
404
405 /* Save user locale and switch to C locale */
406 #if HAVE_USELOCALE
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);
411     }
412
413     aug->user_locale = uselocale(aug->c_locale);
414  error:
415     return;
416 }
417 #else
418 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
419 #endif
420
421 #if HAVE_USELOCALE
422 static void restore_locale(struct augeas *aug) {
423     uselocale(aug->user_locale);
424     aug->user_locale = NULL;
425 }
426 #else
427 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
428 #endif
429
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.
435  */
436 void api_entry(const struct augeas *aug) {
437     struct error *err = ((struct augeas *) aug)->error;
438
439     ((struct augeas *) aug)->api_entries += 1;
440
441     if (aug->api_entries > 1)
442         return;
443
444     reset_error(err);
445     save_locale((struct augeas *) aug);
446 }
447
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);
454     }
455 }
456
457 static int init_root(struct augeas *aug, const char *root0) {
458     if (root0 == NULL)
459         root0 = getenv(AUGEAS_ROOT_ENV);
460     if (root0 == NULL || root0[0] == '\0')
461         root0 = "/";
462
463     aug->root = strdup(root0);
464     if (aug->root == NULL)
465         return -1;
466
467     if (aug->root[strlen(aug->root)-1] != SEP) {
468         if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
469             return -1;
470         strcat((char *) aug->root, "/");
471     }
472     return 0;
473 }
474
475 static int init_loadpath(struct augeas *aug, const char *loadpath) {
476     int r;
477
478     aug->modpathz = NULL;
479     aug->nmodpath = 0;
480     if (loadpath != NULL) {
481         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
482                          loadpath, PATH_SEP_CHAR);
483         if (r != 0)
484             return -1;
485     }
486     char *env = getenv(AUGEAS_LENS_ENV);
487     if (env != NULL) {
488         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
489                          env, PATH_SEP_CHAR);
490         if (r != 0)
491             return -1;
492     }
493     if (!(aug->flags & AUG_NO_STDINC)) {
494         r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
495         if (r != 0)
496             return -1;
497         r = argz_add(&aug->modpathz, &aug->nmodpath,
498                      AUGEAS_LENS_DIST_DIR);
499         if (r != 0)
500             return -1;
501     }
502     /* Clean up trailing slashes */
503     if (aug->nmodpath > 0) {
504         argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
505         char *s, *t;
506         const char *e = aug->modpathz + strlen(aug->modpathz);
507         for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
508             char *p = s;
509             if (*p == '/') {
510                 while (*p == '/') p += 1;
511                 if (*p == '\0' || *p == PATH_SEP_CHAR)
512                     s = p;
513             }
514             if (t != s)
515                 *t++ = *s;
516             else
517                 t += 1;
518         }
519         if (t != s) {
520             *t = '\0';
521         }
522         s = aug->modpathz;
523         aug->modpathz = NULL;
524         r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
525                             &aug->nmodpath);
526         free(s);
527         if (r != 0)
528             return -1;
529     }
530     return 0;
531 }
532
533 static void init_save_mode(struct augeas *aug) {
534     const char *v = AUG_SAVE_OVERWRITE_TEXT;
535
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;
542     }
543
544     aug_set(aug, AUGEAS_META_SAVE_MODE, v);
545 }
546
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);
551     int r;
552     bool close_on_error = true;
553
554     if (tree_root == NULL)
555         return NULL;
556
557     if (ALLOC(result) < 0)
558         goto error;
559     if (ALLOC(result->error) < 0)
560         goto error;
561     if (make_ref(result->error->info) < 0)
562         goto error;
563     result->error->info->error = result->error;
564     result->error->info->filename = dup_string("(unknown file)");
565     if (result->error->info->filename == NULL)
566         goto error;
567     result->error->aug = result;
568
569     result->origin = make_tree_origin(tree_root);
570     if (result->origin == NULL) {
571         free_tree(tree_root);
572         goto error;
573     }
574
575     api_entry(result);
576
577     result->flags = flags;
578
579     r = init_root(result, root);
580     ERR_NOMEM(r < 0, result);
581
582     result->origin->children->label = strdup(s_augeas);
583
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);
587
588     r = init_loadpath(result, loadpath);
589     ERR_NOMEM(r < 0, result);
590
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);
595     ERR_BAIL(result);
596
597     /* Set the default path context */
598     aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
599     ERR_BAIL(result);
600
601     for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
602         aug_set(result, static_nodes[i][0], static_nodes[i][1]);
603         ERR_BAIL(result);
604     }
605
606     init_save_mode(result);
607     ERR_BAIL(result);
608
609     const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
610     aug_set(result, AUGEAS_SPAN_OPTION, v);
611     ERR_BAIL(result);
612
613     if (interpreter_init(result) == -1)
614         goto error;
615
616     list_for_each(modl, result->modules) {
617         struct transform *xform = modl->autoload;
618         if (xform == NULL)
619             continue;
620         tree_from_transform(result, modl->name, xform);
621         ERR_BAIL(result);
622     }
623     if (!(result->flags & AUG_NO_LOAD))
624         if (aug_load(result) < 0)
625             goto error;
626
627     api_exit(result);
628     return result;
629
630  error:
631     if (close_on_error) {
632         aug_close(result);
633         result = NULL;
634     }
635     if (result != NULL && result->api_entries > 0)
636         api_exit(result);
637     return result;
638 }
639
640 /* Free one tree node */
641 static void free_tree_node(struct tree *tree) {
642     if (tree == NULL)
643         return;
644
645     if (tree->span != NULL)
646         free_span(tree->span);
647     free(tree->label);
648     free(tree->value);
649     free(tree);
650 }
651
652 /* Only unlink; assume we know TREE is not in the symtab */
653 static int tree_unlink_raw(struct tree *tree) {
654     int result = 0;
655
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);
661     return result;
662 }
663
664 int tree_unlink(struct augeas *aug, struct tree *tree) {
665     if (tree == NULL)
666         return 0;
667     pathx_symtab_remove_descendants(aug->symtab, tree);
668     return tree_unlink_raw(tree);
669 }
670
671 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
672     if (tree == NULL)
673         return;
674
675     pathx_symtab_remove_descendants(aug->symtab, tree);
676
677     while (tree->children != NULL)
678         tree_unlink_raw(tree->children);
679 }
680
681 static void tree_mark_files(struct tree *tree) {
682     if (tree_child(tree, "path") != NULL) {
683         tree_mark_dirty(tree);
684     } else {
685         list_for_each(c, tree->children) {
686             tree_mark_files(c);
687         }
688     }
689 }
690
691 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
692     struct tree *p;
693
694     if (!tree->dirty)
695         return;
696
697     if (tree->file && ((p = tree_child(tree, "path")) != NULL)) {
698         tree_unlink(aug, tree_fpath(aug, p->value));
699         tree_unlink(aug, tree);
700     } else {
701         struct tree *c = tree->children;
702         while (c != NULL) {
703             struct tree *next = c->next;
704             tree_rm_dirty_files(aug, c);
705             c = next;
706         }
707     }
708 }
709
710 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
711                                  struct tree *protect) {
712     if (! tree->dirty)
713         return;
714
715     struct tree *c = tree->children;
716     while (c != NULL) {
717         struct tree *next = c->next;
718         tree_rm_dirty_leaves(aug, c, protect);
719         c = next;
720     }
721
722     if (tree != protect && tree->children == NULL)
723         tree_unlink(aug, tree);
724 }
725
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);
733
734     api_entry(aug);
735
736     ERR_NOMEM(load == NULL, aug);
737
738     /* To avoid unnecessary loads of files, we reload an existing file in
739      * several steps:
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
748      *     anymore
749      * (4) Remove entries from /augeas/files and /files that correspond
750      *     to directories without any files of interest
751      */
752
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;
757         } else {
758             aug->flags &= ~AUG_ENABLE_SPAN;
759         }
760     }
761
762     tree_clean(meta_files);
763     tree_mark_files(meta_files);
764
765     list_for_each(xfm, load->children) {
766         if (transform_validate(aug, xfm) == 0)
767             transform_load(aug, xfm, NULL);
768     }
769
770     /* This makes it possible to spot 'directories' that are now empty
771      * because we removed their file contents */
772     tree_clean(files);
773
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);
777
778     tree_clean(aug->origin);
779
780     list_for_each(v, vars->children) {
781         aug_defvar(aug, v->label, v->value);
782         ERR_BAIL(aug);
783     }
784
785     api_exit(aug);
786     return 0;
787  error:
788     api_exit(aug);
789     return -1;
790 }
791
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);
795
796     if (r == 1)
797         return 0;
798
799     if (r == 0) {
800         report_error(err, AUG_ENOMATCH, NULL);
801     } else {
802         /* r > 1 */
803         report_error(err, AUG_EMMATCH, NULL);
804     }
805
806     return -1;
807 }
808
809 int aug_get(const struct augeas *aug, const char *path, const char **value) {
810     struct pathx *p = NULL;
811     struct tree *match;
812     int r;
813
814     if (value != NULL)
815         *value = NULL;
816
817     api_entry(aug);
818
819     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
820     ERR_BAIL(aug);
821
822     r = pathx_find_one(p, &match);
823     ERR_BAIL(aug);
824     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
825               r, path);
826
827     if (r == 1 && value != NULL)
828         *value = match->value;
829     free_pathx(p);
830
831     api_exit(aug);
832     return r;
833  error:
834     free_pathx(p);
835     api_exit(aug);
836     return -1;
837 }
838
839 int aug_label(const struct augeas *aug, const char *path, const char **label) {
840     struct pathx *p = NULL;
841     struct tree *match;
842     int r;
843
844     api_entry(aug);
845
846     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
847     ERR_BAIL(aug);
848
849     if (label != NULL)
850         *label = NULL;
851
852     r = pathx_find_one(p, &match);
853     ERR_BAIL(aug);
854     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
855               r, path);
856
857     if (r == 1 && label != NULL)
858         *label = match->label;
859     free_pathx(p);
860
861     api_exit(aug);
862     return r;
863  error:
864     free_pathx(p);
865     api_exit(aug);
866     return -1;
867 }
868
869 static void record_var_meta(struct augeas *aug, const char *name,
870                             const char *expr) {
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);
874     if (expr == NULL) {
875         tree_unlink(aug, tree_child(tree, name));
876     } else {
877         tree = tree_child_cr(tree, name);
878         ERR_NOMEM(tree == NULL, aug);
879         tree_set_value(tree, expr);
880     }
881  error:
882     return;
883 }
884
885 int aug_defvar(augeas *aug, const char *name, const char *expr) {
886     struct pathx *p = NULL;
887     int result = -1;
888
889     api_entry(aug);
890
891     if (expr == NULL) {
892         result = pathx_symtab_undefine(&(aug->symtab), name);
893     } else {
894         p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
895         ERR_BAIL(aug);
896         result = pathx_symtab_define(&(aug->symtab), name, p);
897     }
898     ERR_BAIL(aug);
899
900     record_var_meta(aug, name, expr);
901     ERR_BAIL(aug);
902  error:
903     free_pathx(p);
904     api_exit(aug);
905     return result;
906 }
907
908 int aug_defnode(augeas *aug, const char *name, const char *expr,
909                 const char *value, int *created) {
910     struct pathx *p = NULL;
911     int result = -1;
912     int r, cr;
913     struct tree *tree;
914
915     api_entry(aug);
916
917     if (expr == NULL)
918         goto error;
919     if (created == NULL)
920         created = &cr;
921
922     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
923     ERR_BAIL(aug);
924
925     if (pathx_first(p) == NULL) {
926         r = pathx_expand_tree(p, &tree);
927         if (r < 0)
928             goto done;
929         *created = 1;
930     } else {
931         *created = 0;
932     }
933
934     if (*created) {
935         r = tree_set_value(tree, value);
936         if (r < 0)
937             goto done;
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);
942         free(e);
943         ERR_BAIL(aug);
944     } else {
945         result = pathx_symtab_define(&(aug->symtab), name, p);
946         record_var_meta(aug, name, expr);
947         ERR_BAIL(aug);
948     }
949
950  done:
951  error:
952     free_pathx(p);
953     api_exit(aug);
954     return result;
955 }
956
957 struct tree *tree_set(struct pathx *p, const char *value) {
958     struct tree *tree;
959     int r;
960
961     r = pathx_expand_tree(p, &tree);
962     if (r == -1)
963         return NULL;
964
965     r = tree_set_value(tree, value);
966     if (r < 0)
967         return NULL;
968     return tree;
969 }
970
971 int aug_set(struct augeas *aug, const char *path, const char *value) {
972     struct pathx *p = NULL;
973     int result = -1;
974
975     api_entry(aug);
976
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);
981
982     p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
983     ERR_BAIL(aug);
984
985     result = tree_set(p, value) == NULL ? -1 : 0;
986  error:
987     free_pathx(p);
988     api_exit(aug);
989     return result;
990 }
991
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;
996     int result, r;
997
998     api_entry(aug);
999
1000     bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
1001     ERR_BAIL(aug);
1002
1003     if (sub != NULL && STREQ(sub, "."))
1004         sub = NULL;
1005
1006     result = 0;
1007     for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
1008         if (sub != NULL) {
1009             /* Handle subnodes of BT */
1010             sx = pathx_aug_parse(aug, bt, NULL, sub, true);
1011             ERR_BAIL(aug);
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);
1017                     result += 1;
1018                 }
1019             } else {
1020                 /* Create a new subnode matching SUB */
1021                 r = pathx_expand_tree(sx, &st);
1022                 if (r == -1)
1023                     goto error;
1024                 r = tree_set_value(st, value);
1025                 ERR_NOMEM(r < 0, aug);
1026                 result += 1;
1027             }
1028             free_pathx(sx);
1029             sx = NULL;
1030         } else {
1031             /* Set nodes matching BT directly */
1032             r = tree_set_value(bt, value);
1033             ERR_NOMEM(r < 0, aug);
1034             result += 1;
1035         }
1036     }
1037
1038  done:
1039     free_pathx(bx);
1040     free_pathx(sx);
1041     api_exit(aug);
1042     return result;
1043  error:
1044     result = -1;
1045     goto done;
1046 }
1047
1048 int tree_insert(struct pathx *p, const char *label, int before) {
1049     struct tree *new = NULL, *match;
1050
1051     if (strchr(label, SEP) != NULL)
1052         return -1;
1053
1054     if (find_one_node(p, &match) < 0)
1055         goto error;
1056
1057     new = make_tree(strdup(label), NULL, match->parent, NULL);
1058     if (new == NULL || new->label == NULL)
1059         goto error;
1060
1061     if (before) {
1062         list_insert_before(new, match, new->parent->children);
1063     } else {
1064         new->next = match->next;
1065         match->next = new;
1066     }
1067     return 0;
1068  error:
1069     free_tree(new);
1070     return -1;
1071 }
1072
1073 int aug_insert(struct augeas *aug, const char *path, const char *label,
1074                int before) {
1075     struct pathx *p = NULL;
1076     int result = -1;
1077
1078     api_entry(aug);
1079
1080     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1081     ERR_BAIL(aug);
1082
1083     result = tree_insert(p, label, before);
1084  error:
1085     free_pathx(p);
1086     api_exit(aug);
1087     return result;
1088 }
1089
1090 struct tree *make_tree(char *label, char *value, struct tree *parent,
1091                        struct tree *children) {
1092     struct tree *tree;
1093     if (ALLOC(tree) < 0)
1094         return NULL;
1095
1096     tree->label = label;
1097     tree->value = value;
1098     tree->parent = parent;
1099     tree->children = children;
1100     list_for_each(c, tree->children)
1101         c->parent = tree;
1102     if (parent != NULL)
1103         tree_mark_dirty(tree);
1104     else
1105         tree->dirty = 1;
1106     return tree;
1107 }
1108
1109 struct tree *make_tree_origin(struct tree *root) {
1110     struct tree *origin = NULL;
1111
1112     origin = make_tree(NULL, NULL, NULL, root);
1113     if (origin == NULL)
1114         return NULL;
1115
1116     origin->parent = origin;
1117     return origin;
1118 }
1119
1120 /* Recursively free the whole tree TREE and all its siblings */
1121 int free_tree(struct tree *tree) {
1122     int cnt = 0;
1123
1124     while (tree != NULL) {
1125         struct tree *del = tree;
1126         tree = del->next;
1127         cnt += free_tree(del->children);
1128         free_tree_node(del);
1129         cnt += 1;
1130     }
1131
1132     return cnt;
1133 }
1134
1135 int tree_rm(struct pathx *p) {
1136     struct tree *tree, **del;
1137     int cnt = 0, ndel = 0, i;
1138
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))
1142             ndel += 1;
1143     }
1144
1145     if (ndel == 0)
1146         return 0;
1147
1148     if (ALLOC_N(del, ndel) < 0) {
1149         free(del);
1150         return -1;
1151     }
1152
1153     for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1154         if (TREE_HIDDEN(tree))
1155             continue;
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 */
1164         int live = 1;
1165         for (struct tree *t = tree; live && ! ROOT_P(t); t = t->parent) {
1166             if (t->added)
1167                 live = 0;
1168         }
1169         if (live) {
1170             del[i] = tree;
1171             i += 1;
1172             tree->added = 1;
1173         }
1174     }
1175     /* ndel now means: the number of trees we are actually going to delete */
1176     ndel = i;
1177
1178     for (i = 0; i < ndel; i++) {
1179         if (del[i] != NULL) {
1180             cnt += tree_unlink_raw(del[i]);
1181         }
1182     }
1183     free(del);
1184
1185     return cnt;
1186 }
1187
1188 int aug_rm(struct augeas *aug, const char *path) {
1189     struct pathx *p = NULL;
1190     int result = -1;
1191
1192     api_entry(aug);
1193
1194     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1195     ERR_BAIL(aug);
1196
1197     result = tree_rm(p);
1198
1199  error:
1200     free_pathx(p);
1201     api_exit(aug);
1202     return result;
1203 }
1204
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;
1209     int result = -1;
1210     struct tree *tree = NULL;
1211     struct span *span;
1212
1213     api_entry(aug);
1214
1215     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1216     ERR_BAIL(aug);
1217
1218     tree = pathx_first(p);
1219     ERR_BAIL(aug);
1220
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);
1224
1225     span = tree->span;
1226
1227     if (label_start != NULL)
1228         *label_start = span->label_start;
1229
1230     if (label_end != NULL)
1231         *label_end = span->label_end;
1232
1233     if (value_start != NULL)
1234         *value_start = span->value_start;
1235
1236     if (value_end != NULL)
1237         *value_end = span->value_end;
1238
1239     if (span_start != NULL)
1240         *span_start = span->span_start;
1241
1242     if (span_end != NULL)
1243         *span_end = span->span_end;
1244
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("");
1249         } else {
1250             *filename = strdup(span->filename->str);
1251         }
1252         ERR_NOMEM(*filename == NULL, aug);
1253     }
1254
1255     result = 0;
1256  error:
1257     free_pathx(p);
1258     api_exit(aug);
1259     return result;
1260 }
1261
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;
1265     int r, ret;
1266
1267     api_entry(aug);
1268
1269     ret = -1;
1270     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1271     ERR_BAIL(aug);
1272
1273     d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1274     ERR_BAIL(aug);
1275
1276     r = find_one_node(s, &ts);
1277     if (r < 0)
1278         goto error;
1279
1280     r = pathx_expand_tree(d, &td);
1281     if (r == -1)
1282         goto error;
1283
1284     /* Don't move SRC into its own descendent */
1285     t = td;
1286     do {
1287         ERR_THROW(t == ts, aug, AUG_EMVDESC,
1288                   "destination %s is a descendant of %s", dst, src);
1289         t = t->parent;
1290     } while (t != aug->origin);
1291
1292     free_tree(td->children);
1293
1294     td->children = ts->children;
1295     list_for_each(c, td->children) {
1296         c->parent = td;
1297     }
1298     free(td->value);
1299     td->value = ts->value;
1300
1301     ts->value = NULL;
1302     ts->children = NULL;
1303
1304     tree_unlink(aug, ts);
1305     tree_mark_dirty(td);
1306
1307     ret = 0;
1308  error:
1309     free_pathx(s);
1310     free_pathx(d);
1311     api_exit(aug);
1312     return ret;
1313 }
1314
1315 static void tree_copy_rec(struct tree *src, struct tree *dst) {
1316   struct tree *n;
1317   char *value;
1318
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);
1323   }
1324 }
1325
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;
1329     int r, ret;
1330
1331     api_entry(aug);
1332
1333     ret = -1;
1334     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1335     ERR_BAIL(aug);
1336
1337     d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1338     ERR_BAIL(aug);
1339
1340     r = find_one_node(s, &ts);
1341     if (r < 0)
1342         goto error;
1343
1344     r = pathx_expand_tree(d, &td);
1345     if (r == -1)
1346         goto error;
1347
1348     /* Don't copy SRC into its own descendent */
1349     t = td;
1350     do {
1351         ERR_THROW(t == ts, aug, AUG_ECPDESC,
1352                   "destination %s is a descendant of %s", dst, src);
1353         t = t->parent;
1354     } while (t != aug->origin);
1355
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);
1361
1362     ret = 0;
1363  error:
1364     free_pathx(s);
1365     free_pathx(d);
1366     api_exit(aug);
1367     return ret;
1368 }
1369
1370 int aug_rename(struct augeas *aug, const char *src, const char *lbl) {
1371     struct pathx *s = NULL;
1372     struct tree *ts;
1373     int ret;
1374     int count = 0;
1375
1376     api_entry(aug);
1377
1378     ret = -1;
1379     ERR_THROW(strchr(lbl, '/') != NULL, aug, AUG_ELABEL,
1380               "Label %s contains a /", lbl);
1381
1382     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1383     ERR_BAIL(aug);
1384
1385     for (ts = pathx_first(s); ts != NULL; ts = pathx_next(s)) {
1386         free(ts->label);
1387         ts->label = strdup(lbl);
1388         tree_mark_dirty(ts);
1389         count ++;
1390     }
1391
1392     free_pathx(s);
1393     api_exit(aug);
1394     return count;
1395  error:
1396     free_pathx(s);
1397     api_exit(aug);
1398     return ret;
1399 }
1400
1401 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1402     struct pathx *p = NULL;
1403     struct tree *tree;
1404     int cnt = 0;
1405
1406     api_entry(aug);
1407
1408     if (matches != NULL)
1409         *matches = NULL;
1410
1411     if (STREQ(pathin, "/")) {
1412         pathin = "/*";
1413     }
1414
1415     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1416     ERR_BAIL(aug);
1417
1418     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1419         if (! TREE_HIDDEN(tree))
1420             cnt += 1;
1421     }
1422     ERR_BAIL(aug);
1423
1424     if (matches == NULL)
1425         goto done;
1426
1427     if (ALLOC_N(*matches, cnt) < 0)
1428         goto error;
1429
1430     int i = 0;
1431     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1432         if (TREE_HIDDEN(tree))
1433             continue;
1434         (*matches)[i] = path_of_tree(tree);
1435         if ((*matches)[i] == NULL) {
1436             goto error;
1437         }
1438         i += 1;
1439     }
1440     ERR_BAIL(aug);
1441  done:
1442     free_pathx(p);
1443     api_exit(aug);
1444     return cnt;
1445
1446  error:
1447     if (matches != NULL) {
1448         if (*matches != NULL) {
1449             for (i=0; i < cnt; i++)
1450                 free((*matches)[i]);
1451             free(*matches);
1452         }
1453     }
1454     free_pathx(p);
1455     api_exit(aug);
1456     return -1;
1457 }
1458
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) {
1463     int result = 0;
1464     struct lens *l1 = xfm_lens(aug, xfm1, NULL);
1465     struct lens *l2 = xfm_lens(aug, xfm2, NULL);
1466     if (l1 != l2) {
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",
1474                    path,
1475                    xfm_lens_name(xfm1),
1476                    xfm_lens_name(xfm2));
1477         result = -1;
1478     }
1479     return result;
1480 }
1481
1482 static int tree_save(struct augeas *aug, struct tree *tree,
1483                      const char *path) {
1484     int result = 0;
1485     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1486     struct tree *load = tree_child_cr(meta, s_load);
1487
1488     // FIXME: We need to detect subtrees that aren't saved by anything
1489
1490     if (load == NULL)
1491         return -1;
1492
1493     list_for_each(t, tree) {
1494         if (t->dirty) {
1495             char *tpath = NULL;
1496             struct tree *transform = NULL;
1497             if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1498                 result = -1;
1499                 continue;
1500             }
1501             list_for_each(xfm, load->children) {
1502                 if (transform_applies(xfm, tpath)) {
1503                     if (transform == NULL || transform == xfm) {
1504                         transform = xfm;
1505                     } else {
1506                         result = check_save_dup(aug, tpath, transform, xfm);
1507                     }
1508                 }
1509             }
1510             if (transform != NULL) {
1511                 int r = transform_save(aug, transform, tpath, t);
1512                 if (r == -1)
1513                     result = -1;
1514             } else {
1515                 if (tree_save(aug, t->children, tpath) == -1)
1516                     result = -1;
1517             }
1518             free(tpath);
1519         }
1520     }
1521     return result;
1522 }
1523
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 ;
1527
1528     aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1529     if (savemode == NULL)
1530         return -1;
1531
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)) {
1540         return -1;
1541     }
1542
1543     return 0;
1544 }
1545
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
1551      * with it */
1552     static const char *const file_nodes =
1553         "descendant-or-self::*[path][count(error) = 0]";
1554
1555     int result = 0;
1556
1557     if (! files->dirty)
1558         return 0;
1559
1560     for (struct tree *tm = meta->children; tm != NULL;) {
1561         struct tree *tf = tree_child(files, tm->label);
1562         struct tree *next = tm->next;
1563         if (tf == NULL) {
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) {
1568                 result = -1;
1569                 free_pathx(px);
1570                 continue;
1571             }
1572             for (struct tree *t = pathx_first(px);
1573                  t != NULL;
1574                  t = pathx_next(px)) {
1575                 if (remove_file(aug, t) < 0)
1576                     result = -1;
1577             }
1578             free_pathx(px);
1579         } else if (tf->dirty && ! tree_child(tm, "path")) {
1580             if (unlink_removed_files(aug, tf, tm) < 0)
1581                 result = -1;
1582         }
1583         tm = next;
1584     }
1585     return result;
1586 }
1587
1588 int aug_save(struct augeas *aug) {
1589     int ret = 0;
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);
1594
1595     api_entry(aug);
1596
1597     if (update_save_flags(aug) < 0)
1598         goto error;
1599
1600     if (files == NULL || meta == NULL || load == NULL)
1601         goto error;
1602
1603     aug_rm(aug, AUGEAS_EVENTS_SAVED);
1604
1605     list_for_each(xfm, load->children)
1606         transform_validate(aug, xfm);
1607
1608     if (files->dirty) {
1609         if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
1610             ret = -1;
1611
1612         /* Remove files whose entire subtree was removed. */
1613         if (meta_files != NULL) {
1614             if (unlink_removed_files(aug, files, meta_files) < 0)
1615                 ret = -1;
1616         }
1617     }
1618     if (!(aug->flags & AUG_SAVE_NOOP)) {
1619         tree_clean(aug->origin);
1620     }
1621
1622     api_exit(aug);
1623     return ret;
1624  error:
1625     api_exit(aug);
1626     return -1;
1627 }
1628
1629 static int print_one(FILE *out, const char *path, const char *value) {
1630     int r;
1631
1632     r = fprintf(out, "%s", path);
1633     if (r < 0)
1634         return -1;
1635     if (value != NULL) {
1636         char *val = escape(value, -1, STR_ESCAPES);
1637         r = fprintf(out, " = \"%s\"", val);
1638         free(val);
1639         if (r < 0)
1640             return -1;
1641     }
1642     r = fputc('\n', out);
1643     if (r == EOF)
1644         return -1;
1645     return 0;
1646 }
1647
1648 /* PATH is the path up to TREE's parent */
1649 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1650                      int pr_hidden) {
1651     int r;
1652     char *path = NULL;
1653
1654     list_for_each(tree, start) {
1655         if (TREE_HIDDEN(tree) && ! pr_hidden)
1656             continue;
1657
1658         path = path_expand(tree, ppath);
1659         if (path == NULL)
1660             goto error;
1661
1662         r = print_one(out, path, tree->value);
1663         if (r < 0)
1664             goto error;
1665         r = print_rec(out, tree->children, path, pr_hidden);
1666         free(path);
1667         path = NULL;
1668         if (r < 0)
1669             goto error;
1670     }
1671     return 0;
1672  error:
1673     free(path);
1674     return -1;
1675 }
1676
1677 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1678     char *path = NULL;
1679     struct tree *tree;
1680     int r;
1681
1682     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1683         if (TREE_HIDDEN(tree) && ! pr_hidden)
1684             continue;
1685
1686         path = path_of_tree(tree);
1687         if (path == NULL)
1688             goto error;
1689         r = print_one(out, path, tree->value);
1690         if (r < 0)
1691             goto error;
1692         r = print_rec(out, tree->children, path, pr_hidden);
1693         if (r < 0)
1694             goto error;
1695         free(path);
1696         path = NULL;
1697     }
1698     return 0;
1699  error:
1700     free(path);
1701     return -1;
1702 }
1703
1704 int dump_tree(FILE *out, struct tree *tree) {
1705     struct pathx *p;
1706     int result;
1707
1708     if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR) {
1709         free_pathx(p);
1710         return -1;
1711     }
1712
1713     result = print_tree(out, p, 1);
1714     free_pathx(p);
1715     return result;
1716 }
1717
1718 int aug_text_store(augeas *aug, const char *lens, const char *node,
1719                    const char *path) {
1720
1721     struct pathx *p;
1722     const char *src;
1723     int result = -1, r;
1724
1725     api_entry(aug);
1726
1727     /* Validate PATH is syntactically correct */
1728     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1729     free_pathx(p);
1730     ERR_BAIL(aug);
1731
1732     r = aug_get(aug, node, &src);
1733     ERR_BAIL(aug);
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);
1738
1739     result = text_store(aug, lens, path, src);
1740  error:
1741     api_exit(aug);
1742     return result;
1743 }
1744
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;
1749     const char *src;
1750     char *out = NULL;
1751     struct tree *tree_out;
1752     int r;
1753
1754     api_entry(aug);
1755
1756     tree = tree_find(aug, path);
1757     ERR_BAIL(aug);
1758
1759     r = aug_get(aug, node_in, &src);
1760     ERR_BAIL(aug);
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);
1765
1766     r = text_retrieve(aug, lens, path, tree, src, &out);
1767     if (r < 0)
1768         goto error;
1769
1770     tree_out = tree_find_cr(aug, node_out);
1771     ERR_BAIL(aug);
1772
1773     tree_store_value(tree_out, &out);
1774
1775     api_exit(aug);
1776     return 0;
1777  error:
1778     free(out);
1779     api_exit(aug);
1780     return -1;
1781 }
1782
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);
1787
1788     int r = 0, result = -1;
1789     struct tree *xfm = NULL, *lns = NULL, *t = NULL;
1790     const char *filter = NULL;
1791     char *p;
1792     int exists;
1793     char *lensname = NULL, *xfmname = NULL;
1794
1795     api_entry(aug);
1796
1797     ERR_NOMEM(meta == NULL || load == NULL, aug);
1798
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");
1801
1802     if ((p = strrchr(lens, '.'))) {
1803         lensname = strdup(lens);
1804         xfmname = strndup(lens, p - lens);
1805         ERR_NOMEM(lensname == NULL || xfmname == NULL, aug);
1806     } else {
1807         r = xasprintf(&lensname, "%s.lns", lens);
1808         xfmname = strdup(lens);
1809         ERR_NOMEM(r < 0 || xfmname == NULL, aug);
1810     }
1811
1812     xfm = tree_child_cr(load, xfmname);
1813     ERR_NOMEM(xfm == NULL, aug);
1814
1815     lns = tree_child_cr(xfm, s_lens);
1816     ERR_NOMEM(lns == NULL, aug);
1817
1818     tree_store_value(lns, &lensname);
1819
1820     exists = 0;
1821
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)) {
1826             exists = 1;
1827             break;
1828         }
1829     }
1830     if (! exists) {
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);
1835     }
1836
1837     result = 0;
1838  error:
1839     free(lensname);
1840     free(xfmname);
1841     api_exit(aug);
1842     return result;
1843 }
1844
1845 int aug_escape_name(augeas *aug, const char *in, char **out) {
1846     int result = -1;
1847
1848     api_entry(aug);
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");
1851
1852     result = pathx_escape_name(in, out);
1853     ERR_NOMEM(result < 0, aug);
1854  error:
1855     api_exit(aug);
1856     return result;
1857 }
1858
1859 int aug_load_file(struct augeas *aug, const char *file) {
1860     int result = -1, r;
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;
1864     bool found = false;
1865
1866     api_entry(aug);
1867
1868     ERR_NOMEM(load == NULL, aug);
1869
1870     list_for_each(xfm, load->children)  {
1871         if (filter_matches(xfm, file)) {
1872             transform_load(aug, xfm, file);
1873             found = true;
1874             break;
1875         }
1876     }
1877
1878     ERR_THROW(!found, aug, AUG_ENOLENS,
1879               "can not determine lens to load file %s", file);
1880
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);
1885
1886     struct tree *t = tree_fpath(aug, tree_path);
1887     if (t != NULL) {
1888         tree_clean(t);
1889     }
1890
1891     result = 0;
1892 error:
1893     api_exit(aug);
1894     free(tree_path);
1895     return result;
1896 }
1897
1898 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
1899     struct pathx *p;
1900     int result = -1;
1901
1902     api_entry(aug);
1903
1904     if (pathin == NULL || strlen(pathin) == 0) {
1905         pathin = "/*";
1906     }
1907
1908     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1909     ERR_BAIL(aug);
1910
1911     result = print_tree(out, p, 0);
1912  error:
1913     free_pathx(p);
1914     api_exit(aug);
1915     return result;
1916 }
1917
1918 int aug_source(const augeas *aug, const char *path, char **file_path) {
1919     int result = -1, r;
1920     struct pathx *p = NULL;
1921     struct tree *match;
1922
1923     api_entry(aug);
1924
1925     ARG_CHECK(file_path == NULL, aug,
1926               "aug_source_file: FILE_PATH must not be NULL");
1927     *file_path = NULL;
1928
1929     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1930     ERR_BAIL(aug);
1931
1932     r = pathx_find_one(p, &match);
1933     ERR_BAIL(aug);
1934     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
1935               r, path);
1936     ERR_THROW(r == 0, aug, AUG_ENOMATCH, "There is no node matching %s",
1937               path);
1938     while (!(ROOT_P(match) || match->file))
1939         match = match->parent;
1940
1941     if (match->file) {
1942         *file_path = path_of_tree(match);
1943         ERR_NOMEM(file_path == NULL, aug);
1944     }
1945
1946     result = 0;
1947  error:
1948     free_pathx(p);
1949     api_exit(aug);
1950     return result;
1951 }
1952
1953 void aug_close(struct augeas *aug) {
1954     if (aug == NULL)
1955         return;
1956
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;
1964     }
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);
1970     free(aug->error);
1971     free(aug);
1972 }
1973
1974 int __aug_load_module_file(struct augeas *aug, const char *filename) {
1975     api_entry(aug);
1976     int r = load_module_file(aug, filename, NULL);
1977     api_exit(aug);
1978     return r;
1979 }
1980
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))
1984             return 0;
1985         if (!streqv(t1->value, t2->value))
1986             return 0;
1987         if (! tree_equal(t1->children, t2->children))
1988             return 0;
1989         t1 = t1->next;
1990         t2 = t2->next;
1991     }
1992     return t1 == t2;
1993 }
1994
1995 /*
1996  * Error reporting API
1997  */
1998 int aug_error(struct augeas *aug) {
1999     return aug->error->code;
2000 }
2001
2002 const char *aug_error_message(struct augeas *aug) {
2003     aug_errcode_t errcode = aug->error->code;
2004
2005     if (errcode >= ARRAY_CARDINALITY(errcodes))
2006         errcode = AUG_EINTERNAL;
2007     return errcodes[errcode];
2008 }
2009
2010 const char *aug_error_minor_message(struct augeas *aug) {
2011     return aug->error->minor_details;
2012 }
2013
2014 const char *aug_error_details(struct augeas *aug) {
2015     return aug->error->details;
2016 }
2017
2018 /*
2019  * Local variables:
2020  *  indent-tabs-mode: nil
2021  *  c-indent-level: 4
2022  *  c-basic-offset: 4
2023  *  tab-width: 4
2024  * End:
2025  */