3b786c96b4767155bbca74b05cc7776db34391f8
[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-2011 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 #include <libxml/tree.h>
37
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
47 #define TREE_HIDDEN(tree) ((tree)->label == NULL)
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 };
83
84 static void tree_mark_dirty(struct tree *tree) {
85     do {
86         tree->dirty = 1;
87         tree = tree->parent;
88     } while (tree != tree->parent && !tree->dirty);
89     tree->dirty = 1;
90 }
91
92 void tree_clean(struct tree *tree) {
93     if (tree->dirty) {
94         list_for_each(c, tree->children)
95             tree_clean(c);
96     }
97     tree->dirty = 0;
98 }
99
100 struct tree *tree_child(struct tree *tree, const char *label) {
101     if (tree == NULL)
102         return NULL;
103
104     list_for_each(child, tree->children) {
105         if (streqv(label, child->label))
106             return child;
107     }
108     return NULL;
109 }
110
111 struct tree *tree_child_cr(struct tree *tree, const char *label) {
112     static struct tree *child = NULL;
113
114     if (tree == NULL)
115         return NULL;
116
117     child = tree_child(tree, label);
118     if (child == NULL) {
119         char *l = strdup(label);
120         if (l == NULL)
121             return NULL;
122         child = tree_append(tree, l, NULL);
123     }
124     return child;
125 }
126
127 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
128     va_list ap;
129
130     va_start(ap, n);
131     for (int i=0; i < n; i++) {
132         const char *l = va_arg(ap, const char *);
133         tree = tree_child_cr(tree, l);
134     }
135     va_end(ap);
136     return tree;
137 }
138
139 struct tree *tree_find(struct augeas *aug, const char *path) {
140     struct pathx *p = NULL;
141     struct tree *result = NULL;
142     int r;
143
144     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
145     ERR_BAIL(aug);
146
147     r = pathx_find_one(p, &result);
148     BUG_ON(r > 1, aug,
149            "Multiple matches for %s when only one was expected",
150            path);
151  done:
152     free_pathx(p);
153     return result;
154  error:
155     result = NULL;
156     goto done;
157 }
158
159 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
160     struct pathx *p = NULL;
161     struct tree *result = NULL;
162     int r;
163
164     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
165     ERR_BAIL(aug);
166
167     r = pathx_expand_tree(p, &result);
168     ERR_BAIL(aug);
169     ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
170  error:
171     free_pathx(p);
172     return result;
173 }
174
175 void tree_store_value(struct tree *tree, char **value) {
176     if (streqv(tree->value, *value)) {
177         free(*value);
178         *value = NULL;
179         return;
180     }
181     if (tree->value != NULL) {
182         free(tree->value);
183         tree->value = NULL;
184     }
185     if (*value != NULL) {
186         tree->value = *value;
187         *value = NULL;
188     }
189     tree_mark_dirty(tree);
190 }
191
192 int tree_set_value(struct tree *tree, const char *value) {
193     char *v = NULL;
194
195     if (streqv(tree->value, value))
196         return 0;
197     if (value != NULL) {
198         v = strdup(value);
199         if (v == NULL)
200             return -1;
201     }
202     tree_store_value(tree, &v);
203     return 0;
204 }
205
206 static void store_error(const struct augeas *aug, const char *label, const char *value,
207                  int nentries, ...) {
208     va_list ap;
209     struct tree *tree;
210
211     ensure(nentries % 2 == 0, aug);
212     tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
213     if (tree == NULL)
214         return;
215
216     tree_set_value(tree, value);
217
218     va_start(ap, nentries);
219     for (int i=0; i < nentries; i += 2) {
220         char *l = va_arg(ap, char *);
221         char *v = va_arg(ap, char *);
222         struct tree *t = tree_child_cr(tree, l);
223         if (t != NULL)
224             tree_set_value(t, v);
225     }
226     va_end(ap);
227  error:
228     return;
229 }
230
231 /* Report pathx errors in /augeas/pathx/error */
232 static void store_pathx_error(const struct augeas *aug) {
233     if (aug->error->code != AUG_EPATHX)
234         return;
235
236     store_error(aug, s_pathx, aug->error->minor_details,
237                 2, s_pos, aug->error->details);
238 }
239
240 struct pathx *pathx_aug_parse(const struct augeas *aug,
241                               struct tree *tree,
242                               struct tree *root_ctx,
243                               const char *path, bool need_nodeset) {
244     struct pathx *result;
245     struct error *err = err_of_aug(aug);
246
247     if (tree == NULL)
248         tree = aug->origin;
249
250     pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
251     return result;
252 }
253
254 /* Find the tree stored in AUGEAS_CONTEXT */
255 struct tree *tree_root_ctx(const struct augeas *aug) {
256     struct pathx *p = NULL;
257     struct tree *match = NULL;
258     const char *ctx_path;
259     int r;
260
261     p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
262     ERR_BAIL(aug);
263
264     r = pathx_find_one(p, &match);
265     ERR_THROW(r > 1, aug, AUG_EMMATCH,
266               "There are %d nodes matching %s, expecting one",
267               r, AUGEAS_CONTEXT);
268
269     if (match == NULL || match->value == NULL || *match->value == '\0')
270         goto error;
271
272     /* Clean via augrun's helper to ensure it's valid */
273     ctx_path = cleanpath(match->value);
274     free_pathx(p);
275
276     p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
277     ERR_BAIL(aug);
278
279     r = pathx_find_one(p, &match);
280     ERR_THROW(r > 1, aug, AUG_EMMATCH,
281               "There are %d nodes matching the context %s, expecting one",
282               r, ctx_path);
283
284  done:
285     free_pathx(p);
286     return match;
287  error:
288     match = NULL;
289     goto done;
290 }
291
292 struct tree *tree_append(struct tree *parent,
293                          char *label, char *value) {
294     struct tree *result = make_tree(label, value, parent, NULL);
295     if (result != NULL)
296         list_append(parent->children, result);
297     return result;
298 }
299
300 static struct tree *tree_append_s(struct tree *parent,
301                                   const char *l0, char *v) {
302     struct tree *result;
303     char *l = strdup(l0);
304
305     if (l == NULL)
306         return NULL;
307     result = tree_append(parent, l, v);
308     if (result == NULL)
309         free(l);
310     return result;
311 }
312
313 static struct tree *tree_from_transform(struct augeas *aug,
314                                         const char *modname,
315                                         struct transform *xfm) {
316     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
317     struct tree *load = NULL, *txfm = NULL, *t;
318     char *v = NULL;
319     int r;
320
321     ERR_NOMEM(meta == NULL, aug);
322
323     load = tree_child_cr(meta, s_load);
324     ERR_NOMEM(load == NULL, aug);
325
326     if (modname == NULL)
327         modname = "_";
328
329     txfm = tree_append_s(load, modname, NULL);
330     ERR_NOMEM(txfm == NULL, aug);
331
332     r = asprintf(&v, "@%s", modname);
333     ERR_NOMEM(r < 0, aug);
334
335     t = tree_append_s(txfm, "lens", v);
336     ERR_NOMEM(t == NULL, aug);
337     v = NULL;
338
339     list_for_each(f, xfm->filter) {
340         const char *l = f->include ? strdup("incl") : strdup("excl");
341         v = strdup(f->glob->str);
342         ERR_NOMEM(v == NULL, aug);
343         t = tree_append_s(txfm, l, v);
344         ERR_NOMEM(t == NULL, aug);
345     }
346     return txfm;
347  error:
348     free(v);
349     tree_unlink(txfm);
350     return NULL;
351 }
352
353 /* Save user locale and switch to C locale */
354 #if HAVE_USELOCALE
355 static void save_locale(struct augeas *aug) {
356     if (aug->c_locale == NULL) {
357         aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
358         ERR_NOMEM(aug->c_locale == NULL, aug);
359     }
360
361     aug->user_locale = uselocale(aug->c_locale);
362  error:
363     return;
364 }
365 #else
366 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
367 #endif
368
369 #if HAVE_USELOCALE
370 static void restore_locale(struct augeas *aug) {
371     uselocale(aug->user_locale);
372     aug->user_locale = NULL;
373 }
374 #else
375 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
376 #endif
377
378 /* Clean up old error messages every time we enter through the public
379  * API. Since we make internal calls through the public API, we keep a
380  * count of how many times a public API call was made, and only reset when
381  * that count is 0. That requires that all public functions enclose their
382  * work within a matching pair of api_entry/api_exit calls.
383  */
384 void api_entry(const struct augeas *aug) {
385     struct error *err = ((struct augeas *) aug)->error;
386
387     ((struct augeas *) aug)->api_entries += 1;
388
389     if (aug->api_entries > 1)
390         return;
391
392     reset_error(err);
393     save_locale((struct augeas *) aug);
394 }
395
396 void api_exit(const struct augeas *aug) {
397     assert(aug->api_entries > 0);
398     ((struct augeas *) aug)->api_entries -= 1;
399     if (aug->api_entries == 0) {
400         store_pathx_error(aug);
401         restore_locale((struct augeas *) aug);
402     }
403 }
404
405 static int init_root(struct augeas *aug, const char *root0) {
406     if (root0 == NULL)
407         root0 = getenv(AUGEAS_ROOT_ENV);
408     if (root0 == NULL || root0[0] == '\0')
409         root0 = "/";
410
411     aug->root = strdup(root0);
412     if (aug->root == NULL)
413         return -1;
414
415     if (aug->root[strlen(aug->root)-1] != SEP) {
416         if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
417             return -1;
418         strcat((char *) aug->root, "/");
419     }
420     return 0;
421 }
422
423 static int init_loadpath(struct augeas *aug, const char *loadpath) {
424     int r;
425
426     aug->modpathz = NULL;
427     aug->nmodpath = 0;
428     if (loadpath != NULL) {
429         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
430                          loadpath, PATH_SEP_CHAR);
431         if (r != 0)
432             return -1;
433     }
434     char *env = getenv(AUGEAS_LENS_ENV);
435     if (env != NULL) {
436         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
437                          env, PATH_SEP_CHAR);
438         if (r != 0)
439             return -1;
440     }
441     if (!(aug->flags & AUG_NO_STDINC)) {
442         r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
443         if (r != 0)
444             return -1;
445         r = argz_add(&aug->modpathz, &aug->nmodpath,
446                      AUGEAS_LENS_DIST_DIR);
447         if (r != 0)
448             return -1;
449     }
450     /* Clean up trailing slashes */
451     if (aug->nmodpath > 0) {
452         argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
453         char *s, *t;
454         const char *e = aug->modpathz + strlen(aug->modpathz);
455         for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
456             char *p = s;
457             if (*p == '/') {
458                 while (*p == '/') p += 1;
459                 if (*p == '\0' || *p == PATH_SEP_CHAR)
460                     s = p;
461             }
462             if (t != s)
463                 *t++ = *s;
464             else
465                 t += 1;
466         }
467         if (t != s) {
468             *t = '\0';
469         }
470         s = aug->modpathz;
471         aug->modpathz = NULL;
472         r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
473                             &aug->nmodpath);
474         free(s);
475         if (r != 0)
476             return -1;
477     }
478     return 0;
479 }
480
481 static void init_save_mode(struct augeas *aug) {
482     const char *v = AUG_SAVE_OVERWRITE_TEXT;
483
484     if (aug->flags & AUG_SAVE_NEWFILE) {
485         v = AUG_SAVE_NEWFILE_TEXT;
486     } else if (aug->flags & AUG_SAVE_BACKUP) {
487         v = AUG_SAVE_BACKUP_TEXT;
488     } else if (aug->flags & AUG_SAVE_NOOP) {
489         v = AUG_SAVE_NOOP_TEXT;
490     }
491
492     aug_set(aug, AUGEAS_META_SAVE_MODE, v);
493 }
494
495 struct augeas *aug_init(const char *root, const char *loadpath,
496                         unsigned int flags) {
497     struct augeas *result;
498     struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
499     int r;
500     bool close_on_error = true;
501
502     if (tree_root == NULL)
503         return NULL;
504
505     if (ALLOC(result) < 0)
506         goto error;
507     if (ALLOC(result->error) < 0)
508         goto error;
509     if (make_ref(result->error->info) < 0)
510         goto error;
511     result->error->info->error = result->error;
512     result->error->info->filename = dup_string("(unknown file)");
513     if (result->error->info->filename == NULL)
514         goto error;
515     result->error->aug = result;
516
517     result->origin = make_tree_origin(tree_root);
518     if (result->origin == NULL) {
519         free_tree(tree_root);
520         goto error;
521     }
522
523     api_entry(result);
524
525     result->flags = flags;
526
527     r = init_root(result, root);
528     ERR_NOMEM(r < 0, result);
529
530     result->origin->children->label = strdup(s_augeas);
531
532     /* We are now initialized enough that we can dare return RESULT even
533      * when we encounter errors if the caller so wishes */
534     close_on_error = !(flags & AUG_NO_ERR_CLOSE);
535
536     r = init_loadpath(result, loadpath);
537     ERR_NOMEM(r < 0, result);
538
539     /* We report the root dir in AUGEAS_META_ROOT, but we only use the
540        value we store internally, to avoid any problems with
541        AUGEAS_META_ROOT getting changed. */
542     aug_set(result, AUGEAS_META_ROOT, result->root);
543     ERR_BAIL(result);
544
545     /* Set the default path context */
546     aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
547     ERR_BAIL(result);
548
549     for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
550         aug_set(result, static_nodes[i][0], static_nodes[i][1]);
551         ERR_BAIL(result);
552     }
553
554     init_save_mode(result);
555     ERR_BAIL(result);
556
557     const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
558     aug_set(result, AUGEAS_SPAN_OPTION, v);
559     ERR_BAIL(result);
560
561     if (interpreter_init(result) == -1)
562         goto error;
563
564     list_for_each(modl, result->modules) {
565         struct transform *xform = modl->autoload;
566         if (xform == NULL)
567             continue;
568         tree_from_transform(result, modl->name, xform);
569         ERR_BAIL(result);
570     }
571     if (!(result->flags & AUG_NO_LOAD))
572         if (aug_load(result) < 0)
573             goto error;
574
575     api_exit(result);
576     return result;
577
578  error:
579     if (close_on_error) {
580         aug_close(result);
581         result = NULL;
582     }
583     if (result != NULL && result->api_entries > 0)
584         api_exit(result);
585     return result;
586 }
587
588 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
589     if (tree == NULL)
590         return;
591
592     pathx_symtab_remove_descendants(aug->symtab, tree);
593
594     while (tree->children != NULL)
595         tree_unlink(tree->children);
596 }
597
598 static void tree_mark_files(struct tree *tree) {
599     if (tree_child(tree, "path") != NULL) {
600         tree_mark_dirty(tree);
601     } else {
602         list_for_each(c, tree->children) {
603             tree_mark_files(c);
604         }
605     }
606 }
607
608 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
609     struct tree *p;
610
611     if (!tree->dirty)
612         return;
613
614     if ((p = tree_child(tree, "path")) != NULL) {
615         aug_rm(aug, p->value);
616         tree_unlink(tree);
617     } else {
618         struct tree *c = tree->children;
619         while (c != NULL) {
620             struct tree *next = c->next;
621             tree_rm_dirty_files(aug, c);
622             c = next;
623         }
624     }
625 }
626
627 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
628                                  struct tree *protect) {
629     if (! tree->dirty)
630         return;
631
632     struct tree *c = tree->children;
633     while (c != NULL) {
634         struct tree *next = c->next;
635         tree_rm_dirty_leaves(aug, c, protect);
636         c = next;
637     }
638
639     if (tree != protect && tree->children == NULL)
640         tree_unlink(tree);
641 }
642
643 int aug_load(struct augeas *aug) {
644     const char *option = NULL;
645     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
646     struct tree *meta_files = tree_child_cr(meta, s_files);
647     struct tree *files = tree_child_cr(aug->origin, s_files);
648     struct tree *load = tree_child_cr(meta, s_load);
649     struct tree *vars = tree_child_cr(meta, s_vars);
650
651     api_entry(aug);
652
653     ERR_NOMEM(load == NULL, aug);
654
655     /* To avoid unnecessary loads of files, we reload an existing file in
656      * several steps:
657      * (1) mark all file nodes under /augeas/files as dirty (and only those)
658      * (2) process all files matched by a lens; we check (in
659      *     transform_load) if the file has been modified. If it has, we
660      *     reparse it. Either way, we clear the dirty flag. We also need to
661      *     reread the file if part or all of it has been modified in the
662      *     tree but not been saved yet
663      * (3) remove all files from the tree that still have a dirty entry
664      *     under /augeas/files. Those files are not processed by any lens
665      *     anymore
666      * (4) Remove entries from /augeas/files and /files that correspond
667      *     to directories without any files of interest
668      */
669
670     /* update flags according to option value */
671     if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
672         if (strcmp(option, AUG_ENABLE) == 0) {
673             aug->flags |= AUG_ENABLE_SPAN;
674         } else {
675             aug->flags &= ~AUG_ENABLE_SPAN;
676         }
677     }
678
679     tree_clean(meta_files);
680     tree_mark_files(meta_files);
681
682     list_for_each(xfm, load->children) {
683         if (transform_validate(aug, xfm) == 0)
684             transform_load(aug, xfm);
685     }
686
687     /* This makes it possible to spot 'directories' that are now empty
688      * because we removed their file contents */
689     tree_clean(files);
690
691     tree_rm_dirty_files(aug, meta_files);
692     tree_rm_dirty_leaves(aug, meta_files, meta_files);
693     tree_rm_dirty_leaves(aug, files, files);
694
695     tree_clean(aug->origin);
696
697     list_for_each(v, vars->children) {
698         aug_defvar(aug, v->label, v->value);
699         ERR_BAIL(aug);
700     }
701
702     api_exit(aug);
703     return 0;
704  error:
705     api_exit(aug);
706     return -1;
707 }
708
709 static int find_one_node(struct pathx *p, struct tree **match) {
710     struct error *err = err_of_pathx(p);
711     int r = pathx_find_one(p, match);
712
713     if (r == 1)
714         return 0;
715
716     if (r == 0) {
717         report_error(err, AUG_ENOMATCH, NULL);
718     } else {
719         /* r > 1 */
720         report_error(err, AUG_EMMATCH, NULL);
721     }
722
723     return -1;
724 }
725
726 int aug_get(const struct augeas *aug, const char *path, const char **value) {
727     struct pathx *p = NULL;
728     struct tree *match;
729     int r;
730
731     api_entry(aug);
732
733     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
734     ERR_BAIL(aug);
735
736     if (value != NULL)
737         *value = NULL;
738
739     r = pathx_find_one(p, &match);
740     ERR_BAIL(aug);
741     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
742               r, path);
743
744     if (r == 1 && value != NULL)
745         *value = match->value;
746     free_pathx(p);
747
748     api_exit(aug);
749     return r;
750  error:
751     free_pathx(p);
752     api_exit(aug);
753     return -1;
754 }
755
756 static void record_var_meta(struct augeas *aug, const char *name,
757                             const char *expr) {
758     /* Record the definition of the variable */
759     struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
760     ERR_NOMEM(tree == NULL, aug);
761     if (expr == NULL) {
762         tree = tree_child(tree, name);
763         if (tree != NULL)
764             tree_unlink(tree);
765     } else {
766         tree = tree_child_cr(tree, name);
767         ERR_NOMEM(tree == NULL, aug);
768         tree_set_value(tree, expr);
769     }
770  error:
771     return;
772 }
773
774 int aug_defvar(augeas *aug, const char *name, const char *expr) {
775     struct pathx *p = NULL;
776     int result = -1;
777
778     api_entry(aug);
779
780     if (expr == NULL) {
781         result = pathx_symtab_undefine(&(aug->symtab), name);
782     } else {
783         p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
784         ERR_BAIL(aug);
785         result = pathx_symtab_define(&(aug->symtab), name, p);
786     }
787     ERR_BAIL(aug);
788
789     record_var_meta(aug, name, expr);
790     ERR_BAIL(aug);
791  error:
792     free_pathx(p);
793     api_exit(aug);
794     return result;
795 }
796
797 int aug_defnode(augeas *aug, const char *name, const char *expr,
798                 const char *value, int *created) {
799     struct pathx *p;
800     int result = -1;
801     int r, cr;
802     struct tree *tree;
803
804     api_entry(aug);
805
806     if (expr == NULL)
807         goto error;
808     if (created == NULL)
809         created = &cr;
810
811     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
812     ERR_BAIL(aug);
813
814     if (pathx_first(p) == NULL) {
815         r = pathx_expand_tree(p, &tree);
816         if (r < 0)
817             goto done;
818         *created = 1;
819     } else {
820         *created = 0;
821     }
822
823     if (*created) {
824         r = tree_set_value(tree, value);
825         if (r < 0)
826             goto done;
827         result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
828         char *e = path_of_tree(tree);
829         ERR_NOMEM(e == NULL, aug)
830         record_var_meta(aug, name, e);
831         free(e);
832         ERR_BAIL(aug);
833     } else {
834         result = pathx_symtab_define(&(aug->symtab), name, p);
835         record_var_meta(aug, name, expr);
836         ERR_BAIL(aug);
837     }
838
839  done:
840     free_pathx(p);
841     api_exit(aug);
842     return result;
843  error:
844     api_exit(aug);
845     return -1;
846 }
847
848 struct tree *tree_set(struct pathx *p, const char *value) {
849     struct tree *tree;
850     int r;
851
852     r = pathx_expand_tree(p, &tree);
853     if (r == -1)
854         return NULL;
855
856     r = tree_set_value(tree, value);
857     if (r < 0)
858         return NULL;
859     return tree;
860 }
861
862 int aug_set(struct augeas *aug, const char *path, const char *value) {
863     struct pathx *p;
864     int result;
865
866     api_entry(aug);
867
868     /* Get-out clause, in case context is broken */
869     struct tree *root_ctx = NULL;
870     if (STRNEQ(path, AUGEAS_CONTEXT))
871         root_ctx = tree_root_ctx(aug);
872
873     p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
874     ERR_BAIL(aug);
875
876     result = tree_set(p, value) == NULL ? -1 : 0;
877     free_pathx(p);
878
879     api_exit(aug);
880     return result;
881  error:
882     api_exit(aug);
883     return -1;
884 }
885
886 int aug_setm(struct augeas *aug, const char *base,
887              const char *sub, const char *value) {
888     struct pathx *bx = NULL, *sx = NULL;
889     struct tree *bt, *st;
890     int result, r;
891
892     api_entry(aug);
893
894     bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
895     ERR_BAIL(aug);
896
897     if (sub != NULL && STREQ(sub, "."))
898         sub = NULL;
899
900     result = 0;
901     for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
902         if (sub != NULL) {
903             /* Handle subnodes of BT */
904             sx = pathx_aug_parse(aug, bt, NULL, sub, true);
905             ERR_BAIL(aug);
906             if (pathx_first(sx) != NULL) {
907                 /* Change existing subnodes matching SUB */
908                 for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
909                     r = tree_set_value(st, value);
910                     ERR_NOMEM(r < 0, aug);
911                     result += 1;
912                 }
913             } else {
914                 /* Create a new subnode matching SUB */
915                 r = pathx_expand_tree(sx, &st);
916                 if (r == -1)
917                     goto error;
918                 r = tree_set_value(st, value);
919                 ERR_NOMEM(r < 0, aug);
920                 result += 1;
921             }
922             free_pathx(sx);
923             sx = NULL;
924         } else {
925             /* Set nodes matching BT directly */
926             r = tree_set_value(bt, value);
927             ERR_NOMEM(r < 0, aug);
928             result += 1;
929         }
930     }
931
932  done:
933     api_exit(aug);
934     return result;
935  error:
936     result = -1;
937     goto done;
938 }
939
940 int tree_insert(struct pathx *p, const char *label, int before) {
941     struct tree *new = NULL, *match;
942
943     if (strchr(label, SEP) != NULL)
944         return -1;
945
946     if (find_one_node(p, &match) < 0)
947         goto error;
948
949     new = make_tree(strdup(label), NULL, match->parent, NULL);
950     if (new == NULL || new->label == NULL)
951         goto error;
952
953     if (before) {
954         list_insert_before(new, match, new->parent->children);
955     } else {
956         new->next = match->next;
957         match->next = new;
958     }
959     return 0;
960  error:
961     free_tree(new);
962     return -1;
963 }
964
965 int aug_insert(struct augeas *aug, const char *path, const char *label,
966                int before) {
967     struct pathx *p = NULL;
968     int result = -1;
969
970     api_entry(aug);
971
972     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
973     ERR_BAIL(aug);
974
975     result = tree_insert(p, label, before);
976  error:
977     free_pathx(p);
978     api_exit(aug);
979     return result;
980 }
981
982 struct tree *make_tree(char *label, char *value, struct tree *parent,
983                        struct tree *children) {
984     struct tree *tree;
985     if (ALLOC(tree) < 0)
986         return NULL;
987
988     tree->label = label;
989     tree->value = value;
990     tree->parent = parent;
991     tree->children = children;
992     list_for_each(c, tree->children)
993         c->parent = tree;
994     if (parent != NULL)
995         tree_mark_dirty(tree);
996     else
997         tree->dirty = 1;
998     return tree;
999 }
1000
1001 struct tree *make_tree_origin(struct tree *root) {
1002     struct tree *origin = NULL;
1003
1004     origin = make_tree(NULL, NULL, NULL, root);
1005     if (origin == NULL)
1006         return NULL;
1007
1008     origin->parent = origin;
1009     return origin;
1010 }
1011
1012 /* Free one tree node */
1013 static void free_tree_node(struct tree *tree) {
1014     if (tree == NULL)
1015         return;
1016
1017     if (tree->span != NULL)
1018         free_span(tree->span);
1019     free(tree->label);
1020     free(tree->value);
1021     free(tree);
1022 }
1023
1024 /* Recursively free the whole tree TREE and all its siblings */
1025 int free_tree(struct tree *tree) {
1026     int cnt = 0;
1027
1028     while (tree != NULL) {
1029         struct tree *del = tree;
1030         tree = del->next;
1031         cnt += free_tree(del->children);
1032         free_tree_node(del);
1033         cnt += 1;
1034     }
1035
1036     return cnt;
1037 }
1038
1039 int tree_unlink(struct tree *tree) {
1040     int result = 0;
1041
1042     assert (tree->parent != NULL);
1043     list_remove(tree, tree->parent->children);
1044     tree_mark_dirty(tree->parent);
1045     result = free_tree(tree->children) + 1;
1046     free_tree_node(tree);
1047     return result;
1048 }
1049
1050 int tree_rm(struct pathx *p) {
1051     struct tree *tree, **del;
1052     int cnt = 0, ndel = 0, i;
1053
1054     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1055         if (! TREE_HIDDEN(tree))
1056             ndel += 1;
1057     }
1058
1059     if (ndel == 0)
1060         return 0;
1061
1062     if (ALLOC_N(del, ndel) < 0) {
1063         free(del);
1064         return -1;
1065     }
1066
1067     for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1068         if (TREE_HIDDEN(tree))
1069             continue;
1070         pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1071         del[i] = tree;
1072         i += 1;
1073     }
1074
1075     for (i = 0; i < ndel; i++)
1076         cnt += tree_unlink(del[i]);
1077     free(del);
1078
1079     return cnt;
1080 }
1081
1082 int aug_rm(struct augeas *aug, const char *path) {
1083     struct pathx *p = NULL;
1084     int result;
1085
1086     api_entry(aug);
1087
1088     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1089     ERR_BAIL(aug);
1090
1091     result = tree_rm(p);
1092     free_pathx(p);
1093     ERR_BAIL(aug);
1094
1095     api_exit(aug);
1096     return result;
1097  error:
1098     api_exit(aug);
1099     return -1;
1100 }
1101
1102 int aug_span(struct augeas *aug, const char *path, char **filename,
1103         uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1104         uint *span_start, uint *span_end) {
1105     struct pathx *p = NULL;
1106     int result = -1;
1107     struct tree *tree = NULL;
1108     struct span *span;
1109
1110     api_entry(aug);
1111
1112     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1113     ERR_BAIL(aug);
1114
1115     tree = pathx_first(p);
1116     ERR_BAIL(aug);
1117
1118     ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1119     ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1120     ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1121
1122     span = tree->span;
1123
1124     if (label_start != NULL)
1125         *label_start = span->label_start;
1126
1127     if (label_end != NULL)
1128         *label_end = span->label_end;
1129
1130     if (value_start != NULL)
1131         *value_start = span->value_start;
1132
1133     if (value_end != NULL)
1134         *value_end = span->value_end;
1135
1136     if (span_start != NULL)
1137         *span_start = span->span_start;
1138
1139     if (span_end != NULL)
1140         *span_end = span->span_end;
1141
1142     /* We are safer here, make sure we have a filename */
1143     if (filename != NULL) {
1144         if (span->filename == NULL || span->filename->str == NULL) {
1145             *filename = strdup("");
1146         } else {
1147             *filename = strdup(span->filename->str);
1148         }
1149         ERR_NOMEM(*filename == NULL, aug);
1150     }
1151
1152     result = 0;
1153  error:
1154     free_pathx(p);
1155     api_exit(aug);
1156     return result;
1157 }
1158
1159 int tree_replace(struct augeas *aug, const char *path, struct tree *sub) {
1160     struct tree *parent;
1161     struct pathx *p = NULL;
1162     int r;
1163
1164     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1165     ERR_BAIL(aug);
1166
1167     r = tree_rm(p);
1168     if (r == -1)
1169         goto error;
1170
1171     parent = tree_set(p, NULL);
1172     if (parent == NULL)
1173         goto error;
1174
1175     list_append(parent->children, sub);
1176     list_for_each(s, sub) {
1177         s->parent = parent;
1178     }
1179     free_pathx(p);
1180     return 0;
1181  error:
1182     free_pathx(p);
1183     return -1;
1184 }
1185
1186 int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1187     struct pathx *s = NULL, *d = NULL;
1188     struct tree *ts, *td, *t;
1189     int r, ret;
1190
1191     api_entry(aug);
1192
1193     ret = -1;
1194     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1195     ERR_BAIL(aug);
1196
1197     d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1198     ERR_BAIL(aug);
1199
1200     r = find_one_node(s, &ts);
1201     if (r < 0)
1202         goto error;
1203
1204     r = pathx_expand_tree(d, &td);
1205     if (r == -1)
1206         goto error;
1207
1208     /* Don't move SRC into its own descendent */
1209     t = td;
1210     do {
1211         ERR_THROW(t == ts, aug, AUG_EMVDESC,
1212                   "destination %s is a descendant of %s", dst, src);
1213         t = t->parent;
1214     } while (t != aug->origin);
1215
1216     free_tree(td->children);
1217
1218     td->children = ts->children;
1219     list_for_each(c, td->children) {
1220         c->parent = td;
1221     }
1222     free(td->value);
1223     td->value = ts->value;
1224
1225     ts->value = NULL;
1226     ts->children = NULL;
1227
1228     tree_unlink(ts);
1229     tree_mark_dirty(td);
1230
1231     ret = 0;
1232  error:
1233     free_pathx(s);
1234     free_pathx(d);
1235     api_exit(aug);
1236     return ret;
1237 }
1238
1239 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1240     struct pathx *p = NULL;
1241     struct tree *tree;
1242     int cnt = 0;
1243
1244     api_entry(aug);
1245
1246     if (matches != NULL)
1247         *matches = NULL;
1248
1249     if (STREQ(pathin, "/")) {
1250         pathin = "/*";
1251     }
1252
1253     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1254     ERR_BAIL(aug);
1255
1256     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1257         if (! TREE_HIDDEN(tree))
1258             cnt += 1;
1259     }
1260     ERR_BAIL(aug);
1261
1262     if (matches == NULL)
1263         goto done;
1264
1265     if (ALLOC_N(*matches, cnt) < 0)
1266         goto error;
1267
1268     int i = 0;
1269     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1270         if (TREE_HIDDEN(tree))
1271             continue;
1272         (*matches)[i] = path_of_tree(tree);
1273         if ((*matches)[i] == NULL) {
1274             goto error;
1275         }
1276         i += 1;
1277     }
1278     ERR_BAIL(aug);
1279  done:
1280     free_pathx(p);
1281     api_exit(aug);
1282     return cnt;
1283
1284  error:
1285     if (matches != NULL) {
1286         if (*matches != NULL) {
1287             for (i=0; i < cnt; i++)
1288                 free((*matches)[i]);
1289             free(*matches);
1290         }
1291     }
1292     free_pathx(p);
1293     api_exit(aug);
1294     return -1;
1295 }
1296
1297 static int tree_save(struct augeas *aug, struct tree *tree,
1298                      const char *path) {
1299     int result = 0;
1300     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1301     struct tree *load = tree_child_cr(meta, s_load);
1302
1303     // FIXME: We need to detect subtrees that aren't saved by anything
1304
1305     if (load == NULL)
1306         return -1;
1307
1308     list_for_each(t, tree) {
1309         if (t->dirty) {
1310             char *tpath = NULL;
1311             struct tree *transform = NULL;
1312             if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1313                 result = -1;
1314                 continue;
1315             }
1316             list_for_each(xfm, load->children) {
1317                 if (transform_applies(xfm, tpath)) {
1318                     if (transform == NULL || transform == xfm) {
1319                         transform = xfm;
1320                     } else {
1321                         const char *filename =
1322                             tpath + strlen(AUGEAS_FILES_TREE) + 1;
1323                         transform_file_error(aug, "mxfm_save", filename,
1324                            "Lenses %s and %s could be used to save this file",
1325                                              xfm_lens_name(transform),
1326                                              xfm_lens_name(xfm));
1327                         ERR_REPORT(aug, AUG_EMXFM,
1328                                    "Path %s transformable by lens %s and %s",
1329                                    tpath,
1330                                    xfm_lens_name(transform),
1331                                    xfm_lens_name(xfm));
1332                         result = -1;
1333                     }
1334                 }
1335             }
1336             if (transform != NULL) {
1337                 int r = transform_save(aug, transform, tpath, t);
1338                 if (r == -1)
1339                     result = -1;
1340             } else {
1341                 if (tree_save(aug, t->children, tpath) == -1)
1342                     result = -1;
1343             }
1344             free(tpath);
1345         }
1346     }
1347     return result;
1348 }
1349
1350 /* Reset the flags based on what is set in the tree. */
1351 static int update_save_flags(struct augeas *aug) {
1352     const char *savemode ;
1353
1354     aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1355     if (savemode == NULL)
1356         return -1;
1357
1358     aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1359     if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1360         aug->flags |= AUG_SAVE_NEWFILE;
1361     } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1362         aug->flags |= AUG_SAVE_BACKUP;
1363     } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1364         aug->flags |= AUG_SAVE_NOOP ;
1365     } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1366         return -1;
1367     }
1368
1369     return 0;
1370 }
1371
1372 static int unlink_removed_files(struct augeas *aug,
1373                                 struct tree *files, struct tree *meta) {
1374     /* Find all nodes that correspond to a file and might have to be
1375      * unlinked. A node corresponds to a file if it has a child labelled
1376      * 'path', and we only consider it if there are no errors associated
1377      * with it */
1378     static const char *const file_nodes =
1379         "descendant-or-self::*[path][count(error) = 0]";
1380
1381     int result = 0;
1382
1383     if (! files->dirty)
1384         return 0;
1385
1386     for (struct tree *tm = meta->children; tm != NULL;) {
1387         struct tree *tf = tree_child(files, tm->label);
1388         struct tree *next = tm->next;
1389         if (tf == NULL) {
1390             /* Unlink all files in tm */
1391             struct pathx *px = NULL;
1392             if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1393                             aug->symtab, NULL, &px) != PATHX_NOERROR) {
1394                 result = -1;
1395                 continue;
1396             }
1397             for (struct tree *t = pathx_first(px);
1398                  t != NULL;
1399                  t = pathx_next(px)) {
1400                 remove_file(aug, t);
1401             }
1402             free_pathx(px);
1403         } else if (tf->dirty && ! tree_child(tm, "path")) {
1404             if (unlink_removed_files(aug, tf, tm) < 0)
1405                 result = -1;
1406         }
1407         tm = next;
1408     }
1409     return result;
1410 }
1411
1412 int aug_save(struct augeas *aug) {
1413     int ret = 0;
1414     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1415     struct tree *meta_files = tree_child_cr(meta, s_files);
1416     struct tree *files = tree_child_cr(aug->origin, s_files);
1417     struct tree *load = tree_child_cr(meta, s_load);
1418
1419     api_entry(aug);
1420
1421     if (update_save_flags(aug) < 0)
1422         goto error;
1423
1424     if (files == NULL || meta == NULL || load == NULL)
1425         goto error;
1426
1427     aug_rm(aug, AUGEAS_EVENTS_SAVED);
1428
1429     list_for_each(xfm, load->children)
1430         transform_validate(aug, xfm);
1431
1432     if (files->dirty) {
1433         list_for_each(t, files->children) {
1434             if (tree_save(aug, t, AUGEAS_FILES_TREE) == -1)
1435                 ret = -1;
1436         }
1437         /* Remove files whose entire subtree was removed. */
1438         if (meta_files != NULL) {
1439             if (unlink_removed_files(aug, files, meta_files) < 0)
1440                 ret = -1;
1441         }
1442     }
1443     if (!(aug->flags & AUG_SAVE_NOOP)) {
1444         tree_clean(aug->origin);
1445     }
1446
1447     api_exit(aug);
1448     return ret;
1449  error:
1450     api_exit(aug);
1451     return -1;
1452 }
1453
1454 static int print_one(FILE *out, const char *path, const char *value) {
1455     int r;
1456
1457     r = fprintf(out, "%s", path);
1458     if (r < 0)
1459         return -1;
1460     if (value != NULL) {
1461         char *val = escape(value, -1, STR_ESCAPES);
1462         r = fprintf(out, " = \"%s\"", val);
1463         free(val);
1464         if (r < 0)
1465             return -1;
1466     }
1467     r = fputc('\n', out);
1468     if (r == EOF)
1469         return -1;
1470     return 0;
1471 }
1472
1473 /* PATH is the path up to TREE's parent */
1474 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1475                      int pr_hidden) {
1476     int r;
1477     char *path = NULL;
1478
1479     list_for_each(tree, start) {
1480         if (TREE_HIDDEN(tree) && ! pr_hidden)
1481             continue;
1482
1483         path = path_expand(tree, ppath);
1484         if (path == NULL)
1485             goto error;
1486
1487         r = print_one(out, path, tree->value);
1488         if (r < 0)
1489             goto error;
1490         r = print_rec(out, tree->children, path, pr_hidden);
1491         free(path);
1492         path = NULL;
1493         if (r < 0)
1494             goto error;
1495     }
1496     return 0;
1497  error:
1498     free(path);
1499     return -1;
1500 }
1501
1502 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1503     char *path = NULL;
1504     struct tree *tree;
1505     int r;
1506
1507     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1508         if (TREE_HIDDEN(tree) && ! pr_hidden)
1509             continue;
1510
1511         path = path_of_tree(tree);
1512         if (path == NULL)
1513             goto error;
1514         r = print_one(out, path, tree->value);
1515         if (r < 0)
1516             goto error;
1517         r = print_rec(out, tree->children, path, pr_hidden);
1518         if (r < 0)
1519             goto error;
1520         free(path);
1521         path = NULL;
1522     }
1523     return 0;
1524  error:
1525     free(path);
1526     return -1;
1527 }
1528
1529 int dump_tree(FILE *out, struct tree *tree) {
1530     struct pathx *p;
1531     int result;
1532
1533     if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR)
1534         return -1;
1535
1536     result = print_tree(out, p, 1);
1537     free_pathx(p);
1538     return result;
1539 }
1540
1541 static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
1542                       const char *pathin) {
1543     xmlNodePtr value;
1544     xmlAttrPtr prop;
1545
1546     prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
1547     if (prop == NULL)
1548         goto error;
1549
1550     if (tree->span) {
1551         prop = xmlSetProp(elem, BAD_CAST "file",
1552                           BAD_CAST tree->span->filename->str);
1553         if (prop == NULL)
1554             goto error;
1555     }
1556
1557     if (pathin != NULL) {
1558         prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
1559         if (prop == NULL)
1560             goto error;
1561     }
1562     if (tree->value != NULL) {
1563         value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
1564                                 BAD_CAST tree->value);
1565         if (value == NULL)
1566             goto error;
1567     }
1568     return 0;
1569  error:
1570     return -1;
1571 }
1572
1573 static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
1574                       const char *pathin) {
1575     int r;
1576     xmlNodePtr elem;
1577
1578     elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
1579     if (elem == NULL)
1580         goto error;
1581     r = to_xml_one(elem, start, pathin);
1582     if (r < 0)
1583         goto error;
1584
1585     list_for_each(tree, start->children) {
1586         if (TREE_HIDDEN(tree))
1587             continue;
1588         r = to_xml_rec(elem, tree, NULL);
1589         if (r < 0)
1590             goto error;
1591     }
1592
1593     return 0;
1594  error:
1595     return -1;
1596 }
1597
1598 static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
1599     char *path = NULL;
1600     struct tree *tree;
1601     xmlAttrPtr expr;
1602     int r;
1603
1604     *xml = xmlNewNode(NULL, BAD_CAST "augeas");
1605     if (*xml == NULL)
1606         goto error;
1607     expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
1608     if (expr == NULL)
1609         goto error;
1610
1611     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1612         if (TREE_HIDDEN(tree))
1613             continue;
1614         path = path_of_tree(tree);
1615         if (path == NULL)
1616             goto error;
1617         r = to_xml_rec(*xml, tree, path);
1618         if (r < 0)
1619             goto error;
1620         FREE(path);
1621     }
1622     return 0;
1623  error:
1624     free(path);
1625     xmlFree(*xml);
1626     *xml = NULL;
1627     return -1;
1628 }
1629
1630 int aug_to_xml(const struct augeas *aug, const char *pathin,
1631                xmlNode **xmldoc, unsigned int flags) {
1632     struct pathx *p;
1633     int result;
1634
1635     api_entry(aug);
1636
1637     ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
1638     ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
1639
1640     if (pathin == NULL || strlen(pathin) == 1) {
1641         pathin = "/*";
1642     }
1643
1644     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1645     ERR_BAIL(aug);
1646     result = tree_to_xml(p, xmldoc, pathin);
1647     ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
1648     free_pathx(p);
1649     api_exit(aug);
1650
1651     return result;
1652  error:
1653     if (xmldoc !=NULL)
1654         *xmldoc = NULL;
1655     api_exit(aug);
1656     return -1;
1657 }
1658
1659 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
1660     struct pathx *p;
1661     int result;
1662
1663     api_entry(aug);
1664
1665     if (pathin == NULL || strlen(pathin) == 0) {
1666         pathin = "/*";
1667     }
1668
1669     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1670     ERR_BAIL(aug);
1671
1672     result = print_tree(out, p, 0);
1673     free_pathx(p);
1674
1675     api_exit(aug);
1676     return result;
1677  error:
1678     api_exit(aug);
1679     return -1;
1680 }
1681
1682 void aug_close(struct augeas *aug) {
1683     if (aug == NULL)
1684         return;
1685
1686     /* There's no point in bothering with api_entry/api_exit here */
1687     free_tree(aug->origin);
1688     unref(aug->modules, module);
1689     free((void *) aug->root);
1690     free(aug->modpathz);
1691     free_symtab(aug->symtab);
1692     unref(aug->error->info, info);
1693     free(aug->error->details);
1694     free(aug->error);
1695     free(aug);
1696 }
1697
1698 int __aug_load_module_file(struct augeas *aug, const char *filename) {
1699     api_entry(aug);
1700     int r = load_module_file(aug, filename);
1701     api_exit(aug);
1702     return r;
1703 }
1704
1705 int tree_equal(const struct tree *t1, const struct tree *t2) {
1706     while (t1 != NULL && t2 != NULL) {
1707         if (!streqv(t1->label, t2->label))
1708             return 0;
1709         if (!streqv(t1->value, t2->value))
1710             return 0;
1711         if (! tree_equal(t1->children, t2->children))
1712             return 0;
1713         t1 = t1->next;
1714         t2 = t2->next;
1715     }
1716     return t1 == t2;
1717 }
1718
1719 /*
1720  * Error reporting API
1721  */
1722 int aug_error(struct augeas *aug) {
1723     return aug->error->code;
1724 }
1725
1726 const char *aug_error_message(struct augeas *aug) {
1727     aug_errcode_t errcode = aug->error->code;
1728
1729     if (errcode >= ARRAY_CARDINALITY(errcodes))
1730         errcode = AUG_EINTERNAL;
1731     return errcodes[errcode];
1732 }
1733
1734 const char *aug_error_minor_message(struct augeas *aug) {
1735     return aug->error->minor_details;
1736 }
1737
1738 const char *aug_error_details(struct augeas *aug) {
1739     return aug->error->details;
1740 }
1741
1742 /*
1743  * Local variables:
1744  *  indent-tabs-mode: nil
1745  *  c-indent-level: 4
1746  *  c-basic-offset: 4
1747  *  tab-width: 4
1748  * End:
1749  */