Coverage Report

Created: 2023-09-23 08:17

/src/augeas/src/augeas.c
Line
Count
Source (jump to first uncovered line)
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 "/modified", NULL },
65
    { AUGEAS_META_PATHX_FUNC "/position", NULL },
66
    { AUGEAS_META_PATHX_FUNC "/regexp", NULL }
67
};
68
69
static const char *const errcodes[] = {
70
    "No error",                                         /* AUG_NOERROR */
71
    "Cannot allocate memory",                           /* AUG_ENOMEM */
72
    "Internal error (please file a bug)",               /* AUG_EINTERNAL */
73
    "Invalid path expression",                          /* AUG_EPATHX */
74
    "No match for path expression",                     /* AUG_ENOMATCH */
75
    "Too many matches for path expression",             /* AUG_EMMATCH */
76
    "Syntax error in lens definition",                  /* AUG_ESYNTAX */
77
    "Lens not found",                                   /* AUG_ENOLENS */
78
    "Multiple transforms",                              /* AUG_EMXFM */
79
    "Node has no span info",                            /* AUG_ENOSPAN */
80
    "Cannot move node into its descendant",             /* AUG_EMVDESC */
81
    "Failed to execute command",                        /* AUG_ECMDRUN */
82
    "Invalid argument in function call",                /* AUG_EBADARG */
83
    "Invalid label",                                    /* AUG_ELABEL */
84
    "Cannot copy node into its descendant",             /* AUG_ECPDESC */
85
    "Cannot access file"                                /* AUG_EFILEACCESS */
86
};
87
88
65.2k
static void tree_mark_dirty(struct tree *tree) {
89
65.2k
    tree->dirty = 1;
90
303k
    while (tree != tree->parent ) {
91
238k
        if ( tree->file ) {
92
0
           tree->dirty = 1;
93
0
           break;
94
0
        }
95
238k
        tree = tree->parent;
96
238k
    }
97
65.2k
}
98
99
44.1k
void tree_clean(struct tree *tree) {
100
44.1k
    if ( tree->file && ! tree->dirty )
101
0
        return;
102
44.1k
    list_for_each(c, tree->children)
103
39.6k
        tree_clean(c);
104
44.1k
    tree->dirty = 0;
105
44.1k
}
106
107
16.4k
struct tree *tree_child(struct tree *tree, const char *label) {
108
16.4k
    if (tree == NULL)
109
0
        return NULL;
110
111
43.9k
    list_for_each(child, tree->children) {
112
43.9k
        if (streqv(label, child->label))
113
7.61k
            return child;
114
43.9k
    }
115
8.82k
    return NULL;
116
16.4k
}
117
118
14.9k
struct tree *tree_child_cr(struct tree *tree, const char *label) {
119
14.9k
    static struct tree *child = NULL;
120
121
14.9k
    if (tree == NULL)
122
0
        return NULL;
123
124
14.9k
    child = tree_child(tree, label);
125
14.9k
    if (child == NULL) {
126
7.29k
        char *l = strdup(label);
127
7.29k
        if (l == NULL)
128
0
            return NULL;
129
7.29k
        child = tree_append(tree, l, NULL);
130
7.29k
    }
131
14.9k
    return child;
132
14.9k
}
133
134
1.68k
struct tree *tree_path_cr(struct tree *tree, int n, ...) {
135
1.68k
    va_list ap;
136
137
1.68k
    va_start(ap, n);
138
6.63k
    for (int i=0; i < n; i++) {
139
4.95k
        const char *l = va_arg(ap, const char *);
140
4.95k
        tree = tree_child_cr(tree, l);
141
4.95k
    }
142
1.68k
    va_end(ap);
143
1.68k
    return tree;
144
1.68k
}
145
146
static struct tree *tree_fpath_int(struct augeas *aug, const char *fpath,
147
11
                                   bool create) {
148
11
    int r;
149
11
    char *steps = NULL, *step = NULL;
150
11
    size_t nsteps = 0;
151
11
    struct tree *result = NULL;
152
153
11
    r = argz_create_sep(fpath, '/', &steps, &nsteps);
154
11
    ERR_NOMEM(r < 0, aug);
155
11
    result = aug->origin;
156
674
    while ((step = argz_next(steps, nsteps, step))) {
157
663
        if (create) {
158
663
            result = tree_child_cr(result, step);
159
663
            ERR_THROW(result == NULL, aug, AUG_ENOMEM,
160
663
                      "while searching %s: can not create %s", fpath, step);
161
663
        } else {
162
            /* Lookup only */
163
0
            result = tree_child(result, step);
164
0
            if (result == NULL)
165
0
                goto done;
166
0
        }
167
663
    }
168
11
 done:
169
11
    free(steps);
170
11
    return result;
171
0
 error:
172
0
    result = NULL;
173
0
    goto done;
174
11
}
175
176
0
struct tree *tree_fpath(struct augeas *aug, const char *fpath) {
177
0
    return tree_fpath_int(aug, fpath, false);
178
0
}
179
180
11
struct tree *tree_fpath_cr(struct augeas *aug, const char *fpath) {
181
11
    return tree_fpath_int(aug, fpath, true);
182
11
}
183
184
0
struct tree *tree_find(struct augeas *aug, const char *path) {
185
0
    struct pathx *p = NULL;
186
0
    struct tree *result = NULL;
187
0
    int r;
188
189
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
190
0
    ERR_BAIL(aug);
191
192
0
    r = pathx_find_one(p, &result);
193
0
    BUG_ON(r > 1, aug,
194
0
           "Multiple matches for %s when only one was expected",
195
0
           path);
196
0
 done:
197
0
    free_pathx(p);
198
0
    return result;
199
0
 error:
200
0
    result = NULL;
201
0
    goto done;
202
0
}
203
204
0
struct tree *tree_find_cr(struct augeas *aug, const char *path) {
205
0
    struct pathx *p = NULL;
206
0
    struct tree *result = NULL;
207
0
    int r;
208
209
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
210
0
    ERR_BAIL(aug);
211
212
0
    r = pathx_expand_tree(p, &result);
213
0
    ERR_BAIL(aug);
214
0
    ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
215
0
 error:
216
0
    free_pathx(p);
217
0
    return result;
218
0
}
219
220
19.2k
void tree_store_value(struct tree *tree, char **value) {
221
19.2k
    if (streqv(tree->value, *value)) {
222
0
        free(*value);
223
0
        *value = NULL;
224
0
        return;
225
0
    }
226
19.2k
    if (tree->value != NULL) {
227
898
        free(tree->value);
228
898
        tree->value = NULL;
229
898
    }
230
19.2k
    if (*value != NULL) {
231
19.2k
        tree->value = *value;
232
19.2k
        *value = NULL;
233
19.2k
    }
234
19.2k
    tree_mark_dirty(tree);
235
19.2k
}
236
237
43.0k
int tree_set_value(struct tree *tree, const char *value) {
238
43.0k
    char *v = NULL;
239
240
43.0k
    if (streqv(tree->value, value))
241
23.8k
        return 0;
242
19.2k
    if (value != NULL) {
243
19.2k
        v = strdup(value);
244
19.2k
        if (v == NULL)
245
0
            return -1;
246
19.2k
    }
247
19.2k
    tree_store_value(tree, &v);
248
19.2k
    return 0;
249
19.2k
}
250
251
static void store_error(const struct augeas *aug, const char *label, const char *value,
252
1.58k
                 int nentries, ...) {
253
1.58k
    va_list ap;
254
1.58k
    struct tree *tree;
255
256
1.58k
    ensure(nentries % 2 == 0, aug);
257
1.58k
    tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
258
1.58k
    if (tree == NULL)
259
0
        return;
260
261
1.58k
    tree_set_value(tree, value);
262
263
1.58k
    va_start(ap, nentries);
264
3.17k
    for (int i=0; i < nentries; i += 2) {
265
1.58k
        char *l = va_arg(ap, char *);
266
1.58k
        char *v = va_arg(ap, char *);
267
1.58k
        struct tree *t = tree_child_cr(tree, l);
268
1.58k
        if (t != NULL)
269
1.58k
            tree_set_value(t, v);
270
1.58k
    }
271
1.58k
    va_end(ap);
272
1.58k
 error:
273
1.58k
    return;
274
1.58k
}
275
276
/* Report pathx errors in /augeas/pathx/error */
277
5.83k
static void store_pathx_error(const struct augeas *aug) {
278
5.83k
    if (aug->error->code != AUG_EPATHX)
279
4.24k
        return;
280
281
1.58k
    store_error(aug, s_pathx, aug->error->minor_details,
282
1.58k
                2, s_pos, aug->error->details);
283
1.58k
}
284
285
struct pathx *pathx_aug_parse(const struct augeas *aug,
286
                              struct tree *tree,
287
                              struct tree *root_ctx,
288
103k
                              const char *path, bool need_nodeset) {
289
103k
    struct pathx *result;
290
103k
    struct error *err = err_of_aug(aug);
291
292
103k
    if (tree == NULL)
293
0
        tree = aug->origin;
294
295
103k
    pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
296
103k
    return result;
297
103k
}
298
299
/* Find the tree stored in AUGEAS_CONTEXT */
300
34.3k
struct tree *tree_root_ctx(const struct augeas *aug) {
301
34.3k
    struct pathx *p = NULL;
302
34.3k
    struct tree *match = NULL;
303
34.3k
    const char *ctx_path;
304
34.3k
    int r;
305
306
34.3k
    p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
307
34.3k
    ERR_BAIL(aug);
308
309
34.3k
    r = pathx_find_one(p, &match);
310
34.3k
    ERR_THROW(r > 1, aug, AUG_EMMATCH,
311
34.3k
              "There are %d nodes matching %s, expecting one",
312
0
              r, AUGEAS_CONTEXT);
313
314
34.3k
    if (match == NULL || match->value == NULL || *match->value == '\0')
315
1.68k
        goto error;
316
317
    /* Clean via augrun's helper to ensure it's valid */
318
32.6k
    ctx_path = cleanpath(match->value);
319
32.6k
    free_pathx(p);
320
321
32.6k
    p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
322
32.6k
    ERR_BAIL(aug);
323
324
32.6k
    if (pathx_first(p) == NULL) {
325
1.68k
        r = pathx_expand_tree(p, &match);
326
1.68k
        if (r < 0)
327
0
            goto done;
328
1.68k
        r = tree_set_value(match, NULL);
329
1.68k
        if (r < 0)
330
0
            goto done;
331
30.9k
    } else {
332
30.9k
        r = pathx_find_one(p, &match);
333
30.9k
        ERR_THROW(r > 1, aug, AUG_EMMATCH,
334
30.9k
                  "There are %d nodes matching the context %s, expecting one",
335
30.9k
                  r, ctx_path);
336
30.9k
    }
337
338
34.3k
 done:
339
34.3k
    free_pathx(p);
340
34.3k
    return match;
341
1.68k
 error:
342
1.68k
    match = NULL;
343
1.68k
    goto done;
344
32.6k
}
345
346
struct tree *tree_append(struct tree *parent,
347
7.29k
                         char *label, char *value) {
348
7.29k
    struct tree *result = make_tree(label, value, parent, NULL);
349
7.29k
    if (result != NULL)
350
7.29k
        list_append(parent->children, result);
351
0
    return result;
352
7.29k
}
353
354
static struct tree *tree_append_s(struct tree *parent,
355
0
                                  const char *l0, char *v) {
356
0
    struct tree *result;
357
0
    char *l;
358
359
0
    if (l0 == NULL) {
360
0
        return NULL;
361
0
    } else {
362
0
      l = strdup(l0);
363
0
    }
364
0
    result = tree_append(parent, l, v);
365
0
    if (result == NULL)
366
0
        free(l);
367
0
    return result;
368
0
}
369
370
static struct tree *tree_from_transform(struct augeas *aug,
371
                                        const char *modname,
372
0
                                        struct transform *xfm) {
373
0
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
374
0
    struct tree *load = NULL, *txfm = NULL, *t;
375
0
    char *v = NULL;
376
0
    int r;
377
378
0
    ERR_NOMEM(meta == NULL, aug);
379
380
0
    load = tree_child_cr(meta, s_load);
381
0
    ERR_NOMEM(load == NULL, aug);
382
383
0
    if (modname == NULL)
384
0
        modname = "_";
385
386
0
    txfm = tree_append_s(load, modname, NULL);
387
0
    ERR_NOMEM(txfm == NULL, aug);
388
389
0
    r = asprintf(&v, "@%s", modname);
390
0
    ERR_NOMEM(r < 0, aug);
391
392
0
    t = tree_append_s(txfm, s_lens, v);
393
0
    ERR_NOMEM(t == NULL, aug);
394
0
    v = NULL;
395
396
0
    list_for_each(f, xfm->filter) {
397
0
        const char *l = f->include ? s_incl : s_excl;
398
0
        v = strdup(f->glob->str);
399
0
        ERR_NOMEM(v == NULL, aug);
400
0
        t = tree_append_s(txfm, l, v);
401
0
        ERR_NOMEM(t == NULL, aug);
402
0
    }
403
0
    return txfm;
404
0
 error:
405
0
    free(v);
406
0
    tree_unlink(aug, txfm);
407
0
    return NULL;
408
0
}
409
410
/* Save user locale and switch to C locale */
411
#if HAVE_USELOCALE
412
5.83k
static void save_locale(struct augeas *aug) {
413
5.83k
    if (aug->c_locale == NULL) {
414
1.68k
        aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
415
1.68k
        ERR_NOMEM(aug->c_locale == NULL, aug);
416
1.68k
    }
417
418
5.83k
    aug->user_locale = uselocale(aug->c_locale);
419
5.83k
 error:
420
5.83k
    return;
421
5.83k
}
422
#else
423
static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
424
#endif
425
426
#if HAVE_USELOCALE
427
5.83k
static void restore_locale(struct augeas *aug) {
428
5.83k
    uselocale(aug->user_locale);
429
5.83k
    aug->user_locale = NULL;
430
5.83k
}
431
#else
432
static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
433
#endif
434
435
/* Clean up old error messages every time we enter through the public
436
 * API. Since we make internal calls through the public API, we keep a
437
 * count of how many times a public API call was made, and only reset when
438
 * that count is 0. That requires that all public functions enclose their
439
 * work within a matching pair of api_entry/api_exit calls.
440
 */
441
40.9k
void api_entry(const struct augeas *aug) {
442
40.9k
    struct error *err = ((struct augeas *) aug)->error;
443
444
40.9k
    ((struct augeas *) aug)->api_entries += 1;
445
446
40.9k
    if (aug->api_entries > 1)
447
35.0k
        return;
448
449
5.83k
    reset_error(err);
450
5.83k
    save_locale((struct augeas *) aug);
451
5.83k
}
452
453
40.9k
void api_exit(const struct augeas *aug) {
454
40.9k
    assert(aug->api_entries > 0);
455
40.9k
    ((struct augeas *) aug)->api_entries -= 1;
456
40.9k
    if (aug->api_entries == 0) {
457
5.83k
        store_pathx_error(aug);
458
5.83k
        restore_locale((struct augeas *) aug);
459
5.83k
    }
460
40.9k
}
461
462
1.68k
static int init_root(struct augeas *aug, const char *root0) {
463
1.68k
    if (root0 == NULL)
464
1.52k
        root0 = getenv(AUGEAS_ROOT_ENV);
465
1.68k
    if (root0 == NULL || root0[0] == '\0')
466
1.52k
        root0 = "/";
467
468
1.68k
    aug->root = strdup(root0);
469
1.68k
    if (aug->root == NULL)
470
0
        return -1;
471
472
1.68k
    if (aug->root[strlen(aug->root)-1] != SEP) {
473
157
        if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
474
0
            return -1;
475
157
        strcat((char *) aug->root, "/");
476
157
    }
477
1.68k
    return 0;
478
1.68k
}
479
480
1.68k
static int init_loadpath(struct augeas *aug, const char *loadpath) {
481
1.68k
    int r;
482
483
1.68k
    aug->modpathz = NULL;
484
1.68k
    aug->nmodpath = 0;
485
1.68k
    if (loadpath != NULL) {
486
0
        r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
487
0
                         loadpath, PATH_SEP_CHAR);
488
0
        if (r != 0)
489
0
            return -1;
490
0
    }
491
1.68k
    char *env = getenv(AUGEAS_LENS_ENV);
492
1.68k
    if (env != NULL) {
493
0
        r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
494
0
                         env, PATH_SEP_CHAR);
495
0
        if (r != 0)
496
0
            return -1;
497
0
    }
498
1.68k
    if (!(aug->flags & AUG_NO_STDINC)) {
499
1.52k
        r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
500
1.52k
        if (r != 0)
501
0
            return -1;
502
1.52k
        r = argz_add(&aug->modpathz, &aug->nmodpath,
503
1.52k
                     AUGEAS_LENS_DIST_DIR);
504
1.52k
        if (r != 0)
505
0
            return -1;
506
1.52k
    }
507
    /* Clean up trailing slashes */
508
1.68k
    if (aug->nmodpath > 0) {
509
1.52k
        argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
510
1.52k
        char *s, *t;
511
1.52k
        const char *e = aug->modpathz + strlen(aug->modpathz);
512
102k
        for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
513
100k
            char *p = s;
514
100k
            if (*p == '/') {
515
33.5k
                while (*p == '/') p += 1;
516
16.7k
                if (*p == '\0' || *p == PATH_SEP_CHAR)
517
0
                    s = p;
518
16.7k
            }
519
100k
            if (t != s)
520
0
                *t++ = *s;
521
100k
            else
522
100k
                t += 1;
523
100k
        }
524
1.52k
        if (t != s) {
525
0
            *t = '\0';
526
0
        }
527
1.52k
        s = aug->modpathz;
528
1.52k
        aug->modpathz = NULL;
529
1.52k
        r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
530
1.52k
                            &aug->nmodpath);
531
1.52k
        free(s);
532
1.52k
        if (r != 0)
533
0
            return -1;
534
1.52k
    }
535
1.68k
    return 0;
536
1.68k
}
537
538
1.68k
static void init_save_mode(struct augeas *aug) {
539
1.68k
    const char *v = AUG_SAVE_OVERWRITE_TEXT;
540
541
1.68k
    if (aug->flags & AUG_SAVE_NEWFILE) {
542
0
        v = AUG_SAVE_NEWFILE_TEXT;
543
1.68k
    } else if (aug->flags & AUG_SAVE_BACKUP) {
544
0
        v = AUG_SAVE_BACKUP_TEXT;
545
1.68k
    } else if (aug->flags & AUG_SAVE_NOOP) {
546
0
        v = AUG_SAVE_NOOP_TEXT;
547
0
    }
548
549
1.68k
    aug_set(aug, AUGEAS_META_SAVE_MODE, v);
550
1.68k
}
551
552
struct augeas *aug_init(const char *root, const char *loadpath,
553
1.68k
                        unsigned int flags) {
554
1.68k
    struct augeas *result;
555
1.68k
    struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
556
1.68k
    int r;
557
1.68k
    bool close_on_error = true;
558
559
1.68k
    if (tree_root == NULL)
560
0
        return NULL;
561
562
1.68k
    if (ALLOC(result) < 0)
563
0
        goto error;
564
1.68k
    if (ALLOC(result->error) < 0)
565
0
        goto error;
566
1.68k
    if (make_ref(result->error->info) < 0)
567
0
        goto error;
568
1.68k
    result->error->info->error = result->error;
569
1.68k
    result->error->info->filename = dup_string("(unknown file)");
570
1.68k
    if (result->error->info->filename == NULL)
571
0
        goto error;
572
1.68k
    result->error->aug = result;
573
574
1.68k
    result->origin = make_tree_origin(tree_root);
575
1.68k
    if (result->origin == NULL) {
576
0
        free_tree(tree_root);
577
0
        goto error;
578
0
    }
579
580
1.68k
    api_entry(result);
581
582
1.68k
    result->flags = flags;
583
584
1.68k
    r = init_root(result, root);
585
1.68k
    ERR_NOMEM(r < 0, result);
586
587
1.68k
    result->origin->children->label = strdup(s_augeas);
588
589
    /* We are now initialized enough that we can dare return RESULT even
590
     * when we encounter errors if the caller so wishes */
591
1.68k
    close_on_error = !(flags & AUG_NO_ERR_CLOSE);
592
593
1.68k
    r = init_loadpath(result, loadpath);
594
1.68k
    ERR_NOMEM(r < 0, result);
595
596
    /* We report the root dir in AUGEAS_META_ROOT, but we only use the
597
       value we store internally, to avoid any problems with
598
       AUGEAS_META_ROOT getting changed. */
599
1.68k
    aug_set(result, AUGEAS_META_ROOT, result->root);
600
1.68k
    ERR_BAIL(result);
601
602
    /* Set the default path context */
603
1.68k
    aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
604
1.68k
    ERR_BAIL(result);
605
606
26.9k
    for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
607
25.2k
        aug_set(result, static_nodes[i][0], static_nodes[i][1]);
608
25.2k
        ERR_BAIL(result);
609
25.2k
    }
610
611
1.68k
    init_save_mode(result);
612
1.68k
    ERR_BAIL(result);
613
614
1.68k
    const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
615
1.68k
    aug_set(result, AUGEAS_SPAN_OPTION, v);
616
1.68k
    ERR_BAIL(result);
617
618
1.68k
    if (interpreter_init(result) == -1)
619
0
        goto error;
620
621
3.36k
    list_for_each(modl, result->modules) {
622
3.36k
        struct transform *xform = modl->autoload;
623
3.36k
        if (xform == NULL)
624
3.36k
            continue;
625
0
        tree_from_transform(result, modl->name, xform);
626
0
        ERR_BAIL(result);
627
0
    }
628
1.68k
    if (!(result->flags & AUG_NO_LOAD))
629
1.52k
        if (aug_load(result) < 0)
630
0
            goto error;
631
632
1.68k
    api_exit(result);
633
1.68k
    return result;
634
635
0
 error:
636
0
    if (close_on_error) {
637
0
        aug_close(result);
638
0
        result = NULL;
639
0
    }
640
0
    if (result != NULL && result->api_entries > 0)
641
0
        api_exit(result);
642
0
    return result;
643
1.68k
}
644
645
/* Free one tree node */
646
49.3k
static void free_tree_node(struct tree *tree) {
647
49.3k
    if (tree == NULL)
648
0
        return;
649
650
49.3k
    if (tree->span != NULL)
651
0
        free_span(tree->span);
652
49.3k
    free(tree->label);
653
49.3k
    free(tree->value);
654
49.3k
    free(tree);
655
49.3k
}
656
657
/* Only unlink; assume we know TREE is not in the symtab */
658
0
static int tree_unlink_raw(struct tree *tree) {
659
0
    int result = 0;
660
661
0
    assert (tree->parent != NULL);
662
0
    list_remove(tree, tree->parent->children);
663
0
    tree_mark_dirty(tree->parent);
664
0
    result = free_tree(tree->children) + 1;
665
0
    free_tree_node(tree);
666
0
    return result;
667
0
}
668
669
0
int tree_unlink(struct augeas *aug, struct tree *tree) {
670
0
    if (tree == NULL)
671
0
        return 0;
672
0
    pathx_symtab_remove_descendants(aug->symtab, tree);
673
0
    return tree_unlink_raw(tree);
674
0
}
675
676
0
void tree_unlink_children(struct augeas *aug, struct tree *tree) {
677
0
    if (tree == NULL)
678
0
        return;
679
680
0
    pathx_symtab_remove_descendants(aug->symtab, tree);
681
682
0
    while (tree->children != NULL)
683
0
        tree_unlink_raw(tree->children);
684
0
}
685
686
1.52k
static void tree_mark_files(struct tree *tree) {
687
1.52k
    if (tree_child(tree, "path") != NULL) {
688
0
        tree_mark_dirty(tree);
689
1.52k
    } else {
690
1.52k
        list_for_each(c, tree->children) {
691
0
            tree_mark_files(c);
692
0
        }
693
1.52k
    }
694
1.52k
}
695
696
1.52k
static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
697
1.52k
    struct tree *p;
698
699
1.52k
    if (tree->file && !tree->dirty) {
700
0
        return;
701
1.52k
    } else if (tree->file && tree->dirty && ((p = tree_child(tree, "path")) != NULL)) {
702
0
        tree_unlink(aug, tree_fpath(aug, p->value));
703
0
        tree_unlink(aug, tree);
704
1.52k
    } else {
705
1.52k
        struct tree *c = tree->children;
706
1.52k
        while (c != NULL) {
707
0
            struct tree *next = c->next;
708
0
            tree_rm_dirty_files(aug, c);
709
0
            c = next;
710
0
        }
711
1.52k
    }
712
1.52k
}
713
714
static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
715
3.04k
                                 struct tree *protect) {
716
3.04k
    if (tree->file && !tree->dirty)
717
0
        return;
718
719
3.04k
    struct tree *c = tree->children;
720
3.04k
    while (c != NULL) {
721
0
        struct tree *next = c->next;
722
0
        tree_rm_dirty_leaves(aug, c, protect);
723
0
        c = next;
724
0
    }
725
726
3.04k
    if (tree != protect && tree->children == NULL)
727
0
        tree_unlink(aug, tree);
728
3.04k
}
729
730
1.52k
int aug_load(struct augeas *aug) {
731
1.52k
    const char *option = NULL;
732
1.52k
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
733
1.52k
    struct tree *meta_files = tree_child_cr(meta, s_files);
734
1.52k
    struct tree *files = tree_child_cr(aug->origin, s_files);
735
1.52k
    struct tree *load = tree_child_cr(meta, s_load);
736
1.52k
    struct tree *vars = tree_child_cr(meta, s_vars);
737
738
1.52k
    api_entry(aug);
739
740
1.52k
    ERR_NOMEM(load == NULL, aug);
741
742
    /* To avoid unnecessary loads of files, we reload an existing file in
743
     * several steps:
744
     * (1) mark all file nodes under /augeas/files as dirty (and only those)
745
     * (2) process all files matched by a lens; we check (in
746
     *     transform_load) if the file has been modified. If it has, we
747
     *     reparse it. Either way, we clear the dirty flag. We also need to
748
     *     reread the file if part or all of it has been modified in the
749
     *     tree but not been saved yet
750
     * (3) remove all files from the tree that still have a dirty entry
751
     *     under /augeas/files. Those files are not processed by any lens
752
     *     anymore
753
     * (4) Remove entries from /augeas/files and /files that correspond
754
     *     to directories without any files of interest
755
     */
756
757
    /* update flags according to option value */
758
1.52k
    if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
759
1.52k
        if (strcmp(option, AUG_ENABLE) == 0) {
760
0
            aug->flags |= AUG_ENABLE_SPAN;
761
1.52k
        } else {
762
1.52k
            aug->flags &= ~AUG_ENABLE_SPAN;
763
1.52k
        }
764
1.52k
    }
765
766
1.52k
    tree_clean(meta_files);
767
1.52k
    tree_mark_files(meta_files);
768
769
1.52k
    list_for_each(xfm, load->children) {
770
0
        if (transform_validate(aug, xfm) == 0)
771
0
            transform_load(aug, xfm, NULL);
772
0
    }
773
774
    /* This makes it possible to spot 'directories' that are now empty
775
     * because we removed their file contents */
776
1.52k
    tree_clean(files);
777
778
1.52k
    tree_rm_dirty_files(aug, meta_files);
779
1.52k
    tree_rm_dirty_leaves(aug, meta_files, meta_files);
780
1.52k
    tree_rm_dirty_leaves(aug, files, files);
781
782
1.52k
    tree_clean(aug->origin);
783
784
1.52k
    list_for_each(v, vars->children) {
785
0
        aug_defvar(aug, v->label, v->value);
786
0
        ERR_BAIL(aug);
787
0
    }
788
789
1.52k
    api_exit(aug);
790
1.52k
    return 0;
791
0
 error:
792
0
    api_exit(aug);
793
0
    return -1;
794
1.52k
}
795
796
0
static int find_one_node(struct pathx *p, struct tree **match) {
797
0
    struct error *err = err_of_pathx(p);
798
0
    int r = pathx_find_one(p, match);
799
800
0
    if (r == 1)
801
0
        return 0;
802
803
0
    if (r == 0) {
804
0
        report_error(err, AUG_ENOMATCH, NULL);
805
0
    } else {
806
        /* r > 1 */
807
0
        report_error(err, AUG_EMMATCH, NULL);
808
0
    }
809
810
0
    return -1;
811
0
}
812
813
1.74k
int aug_get(const struct augeas *aug, const char *path, const char **value) {
814
1.74k
    struct pathx *p = NULL;
815
1.74k
    struct tree *match;
816
1.74k
    int r;
817
818
1.74k
    if (value != NULL)
819
1.74k
        *value = NULL;
820
821
1.74k
    api_entry(aug);
822
823
1.74k
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
824
1.74k
    ERR_BAIL(aug);
825
826
1.66k
    r = pathx_find_one(p, &match);
827
1.66k
    ERR_BAIL(aug);
828
1.64k
    ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
829
1.64k
              r, path);
830
831
1.55k
    if (r == 1 && value != NULL)
832
1.54k
        *value = match->value;
833
1.55k
    free_pathx(p);
834
835
1.55k
    api_exit(aug);
836
1.55k
    return r;
837
188
 error:
838
188
    free_pathx(p);
839
188
    api_exit(aug);
840
188
    return -1;
841
1.64k
}
842
843
158
int aug_label(const struct augeas *aug, const char *path, const char **label) {
844
158
    struct pathx *p = NULL;
845
158
    struct tree *match;
846
158
    int r;
847
848
158
    api_entry(aug);
849
850
158
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
851
158
    ERR_BAIL(aug);
852
853
76
    if (label != NULL)
854
76
        *label = NULL;
855
856
76
    r = pathx_find_one(p, &match);
857
76
    ERR_BAIL(aug);
858
73
    ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
859
73
              r, path);
860
861
17
    if (r == 1 && label != NULL)
862
11
        *label = match->label;
863
17
    free_pathx(p);
864
865
17
    api_exit(aug);
866
17
    return r;
867
141
 error:
868
141
    free_pathx(p);
869
141
    api_exit(aug);
870
141
    return -1;
871
73
}
872
873
static void record_var_meta(struct augeas *aug, const char *name,
874
92
                            const char *expr) {
875
    /* Record the definition of the variable */
876
92
    struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
877
92
    ERR_NOMEM(tree == NULL, aug);
878
92
    if (expr == NULL) {
879
0
        tree_unlink(aug, tree_child(tree, name));
880
92
    } else {
881
92
        tree = tree_child_cr(tree, name);
882
92
        ERR_NOMEM(tree == NULL, aug);
883
92
        tree_set_value(tree, expr);
884
92
    }
885
92
 error:
886
92
    return;
887
92
}
888
889
158
int aug_defvar(augeas *aug, const char *name, const char *expr) {
890
158
    struct pathx *p = NULL;
891
158
    int result = -1;
892
893
158
    api_entry(aug);
894
895
158
    if (expr == NULL) {
896
0
        result = pathx_symtab_undefine(&(aug->symtab), name);
897
158
    } else {
898
158
        p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
899
158
        ERR_BAIL(aug);
900
94
        result = pathx_symtab_define(&(aug->symtab), name, p);
901
94
    }
902
94
    ERR_BAIL(aug);
903
904
92
    record_var_meta(aug, name, expr);
905
92
    ERR_BAIL(aug);
906
158
 error:
907
158
    free_pathx(p);
908
158
    api_exit(aug);
909
158
    return result;
910
92
}
911
912
int aug_defnode(augeas *aug, const char *name, const char *expr,
913
0
                const char *value, int *created) {
914
0
    struct pathx *p = NULL;
915
0
    int result = -1;
916
0
    int r, cr;
917
0
    struct tree *tree;
918
919
0
    api_entry(aug);
920
921
0
    if (expr == NULL)
922
0
        goto error;
923
0
    if (created == NULL)
924
0
        created = &cr;
925
926
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
927
0
    ERR_BAIL(aug);
928
929
0
    if (pathx_first(p) == NULL) {
930
0
        r = pathx_expand_tree(p, &tree);
931
0
        if (r < 0)
932
0
            goto done;
933
0
        *created = 1;
934
0
    } else {
935
0
        *created = 0;
936
0
    }
937
938
0
    if (*created) {
939
0
        r = tree_set_value(tree, value);
940
0
        if (r < 0)
941
0
            goto done;
942
0
        result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
943
0
        char *e = path_of_tree(tree);
944
0
        ERR_NOMEM(e == NULL, aug)
945
0
        record_var_meta(aug, name, e);
946
0
        free(e);
947
0
        ERR_BAIL(aug);
948
0
    } else {
949
0
        result = pathx_symtab_define(&(aug->symtab), name, p);
950
0
        record_var_meta(aug, name, expr);
951
0
        ERR_BAIL(aug);
952
0
    }
953
954
0
 done:
955
0
 error:
956
0
    free_pathx(p);
957
0
    api_exit(aug);
958
0
    return result;
959
0
}
960
961
31.9k
struct tree *tree_set(struct pathx *p, const char *value) {
962
31.9k
    struct tree *tree;
963
31.9k
    int r;
964
965
31.9k
    r = pathx_expand_tree(p, &tree);
966
31.9k
    if (r == -1)
967
0
        return NULL;
968
969
31.9k
    r = tree_set_value(tree, value);
970
31.9k
    if (r < 0)
971
0
        return NULL;
972
31.9k
    return tree;
973
31.9k
}
974
975
31.9k
int aug_set(struct augeas *aug, const char *path, const char *value) {
976
31.9k
    struct pathx *p = NULL;
977
31.9k
    int result = -1;
978
979
31.9k
    api_entry(aug);
980
981
    /* Get-out clause, in case context is broken */
982
31.9k
    struct tree *root_ctx = NULL;
983
31.9k
    if (STRNEQ(path, AUGEAS_CONTEXT))
984
30.2k
        root_ctx = tree_root_ctx(aug);
985
986
31.9k
    p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
987
31.9k
    ERR_BAIL(aug);
988
989
31.9k
    result = tree_set(p, value) == NULL ? -1 : 0;
990
31.9k
 error:
991
31.9k
    free_pathx(p);
992
31.9k
    api_exit(aug);
993
31.9k
    return result;
994
31.9k
}
995
996
int aug_setm(struct augeas *aug, const char *base,
997
158
             const char *sub, const char *value) {
998
158
    struct pathx *bx = NULL, *sx = NULL;
999
158
    struct tree *bt, *st;
1000
158
    int result, r;
1001
1002
158
    api_entry(aug);
1003
1004
158
    bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
1005
158
    ERR_BAIL(aug);
1006
1007
76
    if (sub != NULL && STREQ(sub, "."))
1008
0
        sub = NULL;
1009
1010
76
    result = 0;
1011
6.24k
    for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
1012
6.17k
        if (sub != NULL) {
1013
            /* Handle subnodes of BT */
1014
0
            sx = pathx_aug_parse(aug, bt, NULL, sub, true);
1015
0
            ERR_BAIL(aug);
1016
0
            if (pathx_first(sx) != NULL) {
1017
                /* Change existing subnodes matching SUB */
1018
0
                for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
1019
0
                    r = tree_set_value(st, value);
1020
0
                    ERR_NOMEM(r < 0, aug);
1021
0
                    result += 1;
1022
0
                }
1023
0
            } else {
1024
                /* Create a new subnode matching SUB */
1025
0
                r = pathx_expand_tree(sx, &st);
1026
0
                if (r == -1)
1027
0
                    goto error;
1028
0
                r = tree_set_value(st, value);
1029
0
                ERR_NOMEM(r < 0, aug);
1030
0
                result += 1;
1031
0
            }
1032
0
            free_pathx(sx);
1033
0
            sx = NULL;
1034
6.17k
        } else {
1035
            /* Set nodes matching BT directly */
1036
6.17k
            r = tree_set_value(bt, value);
1037
6.17k
            ERR_NOMEM(r < 0, aug);
1038
6.17k
            result += 1;
1039
6.17k
        }
1040
6.17k
    }
1041
1042
158
 done:
1043
158
    free_pathx(bx);
1044
158
    free_pathx(sx);
1045
158
    api_exit(aug);
1046
158
    return result;
1047
82
 error:
1048
82
    result = -1;
1049
82
    goto done;
1050
76
}
1051
1052
0
int tree_insert(struct pathx *p, const char *label, int before) {
1053
0
    struct tree *new = NULL, *match;
1054
1055
0
    if (strchr(label, SEP) != NULL)
1056
0
        return -1;
1057
1058
0
    if (find_one_node(p, &match) < 0)
1059
0
        goto error;
1060
1061
0
    new = make_tree(strdup(label), NULL, match->parent, NULL);
1062
0
    if (new == NULL || new->label == NULL)
1063
0
        goto error;
1064
1065
0
    if (before) {
1066
0
        list_insert_before(new, match, new->parent->children);
1067
0
    } else {
1068
0
        new->next = match->next;
1069
0
        match->next = new;
1070
0
    }
1071
0
    return 0;
1072
0
 error:
1073
0
    free_tree(new);
1074
0
    return -1;
1075
0
}
1076
1077
int aug_insert(struct augeas *aug, const char *path, const char *label,
1078
0
               int before) {
1079
0
    struct pathx *p = NULL;
1080
0
    int result = -1;
1081
1082
0
    api_entry(aug);
1083
1084
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1085
0
    ERR_BAIL(aug);
1086
1087
0
    result = tree_insert(p, label, before);
1088
0
 error:
1089
0
    free_pathx(p);
1090
0
    api_exit(aug);
1091
0
    return result;
1092
0
}
1093
1094
struct tree *make_tree(char *label, char *value, struct tree *parent,
1095
49.3k
                       struct tree *children) {
1096
49.3k
    struct tree *tree;
1097
49.3k
    if (ALLOC(tree) < 0)
1098
0
        return NULL;
1099
1100
49.3k
    tree->label = label;
1101
49.3k
    tree->value = value;
1102
49.3k
    tree->parent = parent;
1103
49.3k
    tree->children = children;
1104
49.3k
    list_for_each(c, tree->children)
1105
1.68k
        c->parent = tree;
1106
49.3k
    if (parent != NULL)
1107
45.9k
        tree_mark_dirty(tree);
1108
3.36k
    else
1109
3.36k
        tree->dirty = 1;
1110
49.3k
    return tree;
1111
49.3k
}
1112
1113
1.68k
struct tree *make_tree_origin(struct tree *root) {
1114
1.68k
    struct tree *origin = NULL;
1115
1116
1.68k
    origin = make_tree(NULL, NULL, NULL, root);
1117
1.68k
    if (origin == NULL)
1118
0
        return NULL;
1119
1120
1.68k
    origin->parent = origin;
1121
1.68k
    return origin;
1122
1.68k
}
1123
1124
/* Recursively free the whole tree TREE and all its siblings */
1125
51.0k
int free_tree(struct tree *tree) {
1126
51.0k
    int cnt = 0;
1127
1128
100k
    while (tree != NULL) {
1129
49.3k
        struct tree *del = tree;
1130
49.3k
        tree = del->next;
1131
49.3k
        cnt += free_tree(del->children);
1132
49.3k
        free_tree_node(del);
1133
49.3k
        cnt += 1;
1134
49.3k
    }
1135
1136
51.0k
    return cnt;
1137
51.0k
}
1138
1139
0
int tree_rm(struct pathx *p) {
1140
0
    struct tree *tree, **del;
1141
0
    int cnt = 0, ndel = 0, i;
1142
1143
    /* set ndel to the number of trees we could possibly delete */
1144
0
    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1145
0
        if (! TREE_HIDDEN(tree))
1146
0
            ndel += 1;
1147
0
    }
1148
1149
0
    if (ndel == 0)
1150
0
        return 0;
1151
1152
0
    if (ALLOC_N(del, ndel) < 0) {
1153
0
        free(del);
1154
0
        return -1;
1155
0
    }
1156
1157
0
    for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1158
0
        if (TREE_HIDDEN(tree))
1159
0
            continue;
1160
0
        pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1161
        /* Collect the tree nodes that actually need to be deleted in
1162
           del. Mark the root of every subtree we are going to free by
1163
           setting tree->added. Only add a node to del if none of its
1164
           ancestors would have been freed by the time we get to freeing
1165
           that node; this avoids double frees for situations where the
1166
           path expression matches both /node and /node/child as unlinking
1167
           /node implicitly unlinks /node/child */
1168
0
        int live = 1;
1169
0
        for (struct tree *t = tree; live && ! ROOT_P(t); t = t->parent) {
1170
0
            if (t->added)
1171
0
                live = 0;
1172
0
        }
1173
0
        if (live) {
1174
0
            del[i] = tree;
1175
0
            i += 1;
1176
0
            tree->added = 1;
1177
0
        }
1178
0
    }
1179
    /* ndel now means: the number of trees we are actually going to delete */
1180
0
    ndel = i;
1181
1182
0
    for (i = 0; i < ndel; i++) {
1183
0
        if (del[i] != NULL) {
1184
0
            cnt += tree_unlink_raw(del[i]);
1185
0
        }
1186
0
    }
1187
0
    free(del);
1188
1189
0
    return cnt;
1190
0
}
1191
1192
0
int aug_rm(struct augeas *aug, const char *path) {
1193
0
    struct pathx *p = NULL;
1194
0
    int result = -1;
1195
1196
0
    api_entry(aug);
1197
1198
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1199
0
    ERR_BAIL(aug);
1200
1201
0
    result = tree_rm(p);
1202
1203
0
 error:
1204
0
    free_pathx(p);
1205
0
    api_exit(aug);
1206
0
    return result;
1207
0
}
1208
1209
int aug_span(struct augeas *aug, const char *path, char **filename,
1210
        uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1211
0
        uint *span_start, uint *span_end) {
1212
0
    struct pathx *p = NULL;
1213
0
    int result = -1;
1214
0
    struct tree *tree = NULL;
1215
0
    struct span *span;
1216
1217
0
    api_entry(aug);
1218
1219
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1220
0
    ERR_BAIL(aug);
1221
1222
0
    tree = pathx_first(p);
1223
0
    ERR_BAIL(aug);
1224
1225
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1226
0
    ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1227
0
    ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1228
1229
0
    span = tree->span;
1230
1231
0
    if (label_start != NULL)
1232
0
        *label_start = span->label_start;
1233
1234
0
    if (label_end != NULL)
1235
0
        *label_end = span->label_end;
1236
1237
0
    if (value_start != NULL)
1238
0
        *value_start = span->value_start;
1239
1240
0
    if (value_end != NULL)
1241
0
        *value_end = span->value_end;
1242
1243
0
    if (span_start != NULL)
1244
0
        *span_start = span->span_start;
1245
1246
0
    if (span_end != NULL)
1247
0
        *span_end = span->span_end;
1248
1249
    /* We are safer here, make sure we have a filename */
1250
0
    if (filename != NULL) {
1251
0
        if (span->filename == NULL || span->filename->str == NULL) {
1252
0
            *filename = strdup("");
1253
0
        } else {
1254
0
            *filename = strdup(span->filename->str);
1255
0
        }
1256
0
        ERR_NOMEM(*filename == NULL, aug);
1257
0
    }
1258
1259
0
    result = 0;
1260
0
 error:
1261
0
    free_pathx(p);
1262
0
    api_exit(aug);
1263
0
    return result;
1264
0
}
1265
1266
0
int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1267
0
    struct pathx *s = NULL, *d = NULL;
1268
0
    struct tree *ts, *td, *t;
1269
0
    int r, ret;
1270
1271
0
    api_entry(aug);
1272
1273
0
    ret = -1;
1274
0
    s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1275
0
    ERR_BAIL(aug);
1276
1277
0
    d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1278
0
    ERR_BAIL(aug);
1279
1280
0
    r = find_one_node(s, &ts);
1281
0
    if (r < 0)
1282
0
        goto error;
1283
1284
0
    r = pathx_expand_tree(d, &td);
1285
0
    if (r == -1)
1286
0
        goto error;
1287
1288
    /* Don't move SRC into its own descendent */
1289
0
    t = td;
1290
0
    do {
1291
0
        ERR_THROW(t == ts, aug, AUG_EMVDESC,
1292
0
                  "destination %s is a descendant of %s", dst, src);
1293
0
        t = t->parent;
1294
0
    } while (t != aug->origin);
1295
1296
0
    free_tree(td->children);
1297
1298
0
    td->children = ts->children;
1299
0
    list_for_each(c, td->children) {
1300
0
        c->parent = td;
1301
0
    }
1302
0
    free(td->value);
1303
0
    td->value = ts->value;
1304
1305
0
    ts->value = NULL;
1306
0
    ts->children = NULL;
1307
1308
0
    tree_unlink(aug, ts);
1309
0
    tree_mark_dirty(td);
1310
1311
0
    ret = 0;
1312
0
 error:
1313
0
    free_pathx(s);
1314
0
    free_pathx(d);
1315
0
    api_exit(aug);
1316
0
    return ret;
1317
0
}
1318
1319
0
static void tree_copy_rec(struct tree *src, struct tree *dst) {
1320
0
  struct tree *n;
1321
0
  char *value;
1322
1323
0
  list_for_each(c, src->children) {
1324
0
    value = c->value == NULL ? NULL : strdup(c->value);
1325
0
    n = tree_append_s(dst, c->label, value);
1326
0
    tree_copy_rec(c, n);
1327
0
  }
1328
0
}
1329
1330
0
int aug_cp(struct augeas *aug, const char *src, const char *dst) {
1331
0
    struct pathx *s = NULL, *d = NULL;
1332
0
    struct tree *ts, *td, *t;
1333
0
    int r, ret;
1334
1335
0
    api_entry(aug);
1336
1337
0
    ret = -1;
1338
0
    s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1339
0
    ERR_BAIL(aug);
1340
1341
0
    d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1342
0
    ERR_BAIL(aug);
1343
1344
0
    r = find_one_node(s, &ts);
1345
0
    if (r < 0)
1346
0
        goto error;
1347
1348
0
    r = pathx_expand_tree(d, &td);
1349
0
    if (r == -1)
1350
0
        goto error;
1351
1352
    /* Don't copy SRC into its own descendent */
1353
0
    t = td;
1354
0
    do {
1355
0
        ERR_THROW(t == ts, aug, AUG_ECPDESC,
1356
0
                  "destination %s is a descendant of %s", dst, src);
1357
0
        t = t->parent;
1358
0
    } while (t != aug->origin);
1359
1360
0
    tree_set_value(td, ts->value);
1361
0
    free_tree(td->children);
1362
0
    td->children = NULL;
1363
0
    tree_copy_rec(ts, td);
1364
0
    tree_mark_dirty(td);
1365
1366
0
    ret = 0;
1367
0
 error:
1368
0
    free_pathx(s);
1369
0
    free_pathx(d);
1370
0
    api_exit(aug);
1371
0
    return ret;
1372
0
}
1373
1374
158
int aug_rename(struct augeas *aug, const char *src, const char *lbl) {
1375
158
    struct pathx *s = NULL;
1376
158
    struct tree *ts;
1377
158
    int ret;
1378
158
    int count = 0;
1379
1380
158
    api_entry(aug);
1381
1382
158
    ret = -1;
1383
158
    ERR_THROW(strchr(lbl, '/') != NULL, aug, AUG_ELABEL,
1384
158
              "Label %s contains a /", lbl);
1385
1386
9
    s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1387
9
    ERR_BAIL(aug);
1388
1389
0
    for (ts = pathx_first(s); ts != NULL; ts = pathx_next(s)) {
1390
0
        free(ts->label);
1391
0
        ts->label = strdup(lbl);
1392
0
        tree_mark_dirty(ts);
1393
0
        count ++;
1394
0
    }
1395
1396
0
    free_pathx(s);
1397
0
    api_exit(aug);
1398
0
    return count;
1399
158
 error:
1400
158
    free_pathx(s);
1401
158
    api_exit(aug);
1402
158
    return ret;
1403
9
}
1404
1405
1.52k
int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1406
1.52k
    struct pathx *p = NULL;
1407
1.52k
    struct tree *tree;
1408
1.52k
    int cnt = 0;
1409
1410
1.52k
    api_entry(aug);
1411
1412
1.52k
    if (matches != NULL)
1413
0
        *matches = NULL;
1414
1415
1.52k
    if (STREQ(pathin, "/")) {
1416
0
        pathin = "/*";
1417
0
    }
1418
1419
1.52k
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1420
1.52k
    ERR_BAIL(aug);
1421
1422
633
    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1423
177
        if (! TREE_HIDDEN(tree))
1424
176
            cnt += 1;
1425
177
    }
1426
456
    ERR_BAIL(aug);
1427
1428
456
    if (matches == NULL)
1429
456
        goto done;
1430
1431
0
    if (ALLOC_N(*matches, cnt) < 0)
1432
0
        goto error;
1433
1434
0
    int i = 0;
1435
0
    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1436
0
        if (TREE_HIDDEN(tree))
1437
0
            continue;
1438
0
        (*matches)[i] = path_of_tree(tree);
1439
0
        if ((*matches)[i] == NULL) {
1440
0
            goto error;
1441
0
        }
1442
0
        i += 1;
1443
0
    }
1444
0
    ERR_BAIL(aug);
1445
456
 done:
1446
456
    free_pathx(p);
1447
456
    api_exit(aug);
1448
456
    return cnt;
1449
1450
1.06k
 error:
1451
1.06k
    if (matches != NULL) {
1452
0
        if (*matches != NULL) {
1453
0
            for (i=0; i < cnt; i++)
1454
0
                free((*matches)[i]);
1455
0
            free(*matches);
1456
0
        }
1457
0
    }
1458
1.06k
    free_pathx(p);
1459
1.06k
    api_exit(aug);
1460
1.06k
    return -1;
1461
0
}
1462
1463
/* XFM1 and XFM2 can both be used to save the same file. That is an error
1464
   only if the two lenses in the two transforms are actually different. */
1465
static int check_save_dup(struct augeas *aug, const char *path,
1466
0
                          struct tree *xfm1, struct tree *xfm2) {
1467
0
    int result = 0;
1468
0
    struct lens *l1 = xfm_lens(aug, xfm1, NULL);
1469
0
    struct lens *l2 = xfm_lens(aug, xfm2, NULL);
1470
0
    if (l1 != l2) {
1471
0
        const char *filename = path + strlen(AUGEAS_FILES_TREE) + 1;
1472
0
        transform_file_error(aug, "mxfm_save", filename,
1473
0
                             "Lenses %s and %s could be used to save this file",
1474
0
                             xfm_lens_name(xfm1),
1475
0
                             xfm_lens_name(xfm2));
1476
0
        ERR_REPORT(aug, AUG_EMXFM,
1477
0
                   "Path %s transformable by lens %s and %s",
1478
0
                   path,
1479
0
                   xfm_lens_name(xfm1),
1480
0
                   xfm_lens_name(xfm2));
1481
0
        result = -1;
1482
0
    }
1483
0
    return result;
1484
0
}
1485
1486
static int tree_save(struct augeas *aug, struct tree *tree,
1487
0
                     const char *path) {
1488
0
    int result = 0;
1489
0
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1490
0
    struct tree *load = tree_child_cr(meta, s_load);
1491
1492
    // FIXME: We need to detect subtrees that aren't saved by anything
1493
1494
0
    if (load == NULL)
1495
0
        return -1;
1496
1497
0
    list_for_each(t, tree) {
1498
0
        if (t->file && ! t->dirty) {
1499
0
            continue;
1500
0
        } else {
1501
0
            char *tpath = NULL;
1502
0
            struct tree *transform = NULL;
1503
0
            if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1504
0
                result = -1;
1505
0
                continue;
1506
0
            }
1507
0
            if ( t->dirty ) {
1508
0
                list_for_each(xfm, load->children) {
1509
0
                    if (transform_applies(xfm, tpath)) {
1510
0
                        if (transform == NULL || transform == xfm) {
1511
0
                            transform = xfm;
1512
0
                        } else {
1513
0
                            result = check_save_dup(aug, tpath, transform, xfm);
1514
0
                        }
1515
0
                    }
1516
0
                }
1517
0
            }
1518
0
            if (transform != NULL) {
1519
                /* If this file did not previously exist and is being created by augeas,
1520
                 * then the 'file' flag in the node t will not be set yet. Set it now
1521
                 */
1522
0
                t->file = true;
1523
0
                int r = transform_save(aug, transform, tpath, t);
1524
0
                if (r == -1)
1525
0
                    result = -1;
1526
0
            } else {
1527
0
                if (tree_save(aug, t->children, tpath) == -1)
1528
0
                    result = -1;
1529
0
            }
1530
0
            free(tpath);
1531
0
        }
1532
0
    }
1533
0
    return result;
1534
0
}
1535
1536
/* Reset the flags based on what is set in the tree. */
1537
0
static int update_save_flags(struct augeas *aug) {
1538
0
    const char *savemode ;
1539
1540
0
    aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1541
0
    if (savemode == NULL)
1542
0
        return -1;
1543
1544
0
    aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1545
0
    if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1546
0
        aug->flags |= AUG_SAVE_NEWFILE;
1547
0
    } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1548
0
        aug->flags |= AUG_SAVE_BACKUP;
1549
0
    } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1550
0
        aug->flags |= AUG_SAVE_NOOP ;
1551
0
    } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1552
0
        return -1;
1553
0
    }
1554
1555
0
    return 0;
1556
0
}
1557
1558
static int unlink_removed_files(struct augeas *aug,
1559
0
                                struct tree *files, struct tree *meta) {
1560
    /* Find all nodes that correspond to a file and might have to be
1561
     * unlinked. A node corresponds to a file if it has a child labelled
1562
     * 'path', and we only consider it if there are no errors associated
1563
     * with it */
1564
0
    static const char *const file_nodes =
1565
0
        "descendant-or-self::*[path][count(error) = 0]";
1566
1567
0
    int result = 0;
1568
1569
0
    if (files->file)
1570
0
        return 0;
1571
1572
0
    for (struct tree *tm = meta->children; tm != NULL;) {
1573
0
        struct tree *tf = tree_child(files, tm->label);
1574
0
        struct tree *next = tm->next;
1575
0
        if (tf == NULL) {
1576
            /* Unlink all files in tm */
1577
0
            struct pathx *px = NULL;
1578
0
            if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1579
0
                            aug->symtab, NULL, &px) != PATHX_NOERROR) {
1580
0
                result = -1;
1581
0
                free_pathx(px);
1582
0
                continue;
1583
0
            }
1584
0
            for (struct tree *t = pathx_first(px);
1585
0
                 t != NULL;
1586
0
                 t = pathx_next(px)) {
1587
0
                if (remove_file(aug, t) < 0)
1588
0
                    result = -1;
1589
0
            }
1590
0
            free_pathx(px);
1591
0
        } else if (! tree_child(tm, "path")) {
1592
0
            if (unlink_removed_files(aug, tf, tm) < 0)
1593
0
                result = -1;
1594
0
        }
1595
0
        tm = next;
1596
0
    }
1597
0
    return result;
1598
0
}
1599
1600
0
int aug_save(struct augeas *aug) {
1601
0
    int ret = 0;
1602
0
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1603
0
    struct tree *meta_files = tree_child_cr(meta, s_files);
1604
0
    struct tree *files = tree_child_cr(aug->origin, s_files);
1605
0
    struct tree *load = tree_child_cr(meta, s_load);
1606
1607
0
    api_entry(aug);
1608
1609
0
    if (update_save_flags(aug) < 0)
1610
0
        goto error;
1611
1612
0
    if (files == NULL || meta == NULL || load == NULL)
1613
0
        goto error;
1614
1615
0
    aug_rm(aug, AUGEAS_EVENTS_SAVED);
1616
1617
0
    list_for_each(xfm, load->children)
1618
0
        transform_validate(aug, xfm);
1619
1620
0
    if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
1621
0
        ret = -1;
1622
1623
    /* Remove files whose entire subtree was removed. */
1624
0
    if (meta_files != NULL) {
1625
0
        if (unlink_removed_files(aug, files, meta_files) < 0)
1626
0
            ret = -1;
1627
0
    }
1628
0
    if (!(aug->flags & AUG_SAVE_NOOP)) {
1629
0
        tree_clean(aug->origin);
1630
0
    }
1631
1632
0
    api_exit(aug);
1633
0
    return ret;
1634
0
 error:
1635
0
    api_exit(aug);
1636
0
    return -1;
1637
0
}
1638
1639
20.1k
static int print_one(FILE *out, const char *path, const char *value) {
1640
20.1k
    int r;
1641
1642
20.1k
    r = fprintf(out, "%s", path);
1643
20.1k
    if (r < 0)
1644
0
        return -1;
1645
20.1k
    if (value != NULL) {
1646
7.09k
        char *val = escape(value, -1, STR_ESCAPES);
1647
7.09k
        r = fprintf(out, " = \"%s\"", val);
1648
7.09k
        free(val);
1649
7.09k
        if (r < 0)
1650
0
            return -1;
1651
7.09k
    }
1652
20.1k
    r = fputc('\n', out);
1653
20.1k
    if (r == EOF)
1654
0
        return -1;
1655
20.1k
    return 0;
1656
20.1k
}
1657
1658
/* PATH is the path up to TREE's parent */
1659
static int print_rec(FILE *out, struct tree *start, const char *ppath,
1660
20.1k
                     int pr_hidden) {
1661
20.1k
    int r;
1662
20.1k
    char *path = NULL;
1663
1664
20.1k
    list_for_each(tree, start) {
1665
13.9k
        if (TREE_HIDDEN(tree) && ! pr_hidden)
1666
0
            continue;
1667
1668
13.9k
        path = path_expand(tree, ppath);
1669
13.9k
        if (path == NULL)
1670
0
            goto error;
1671
1672
13.9k
        r = print_one(out, path, tree->value);
1673
13.9k
        if (r < 0)
1674
0
            goto error;
1675
13.9k
        r = print_rec(out, tree->children, path, pr_hidden);
1676
13.9k
        free(path);
1677
13.9k
        path = NULL;
1678
13.9k
        if (r < 0)
1679
0
            goto error;
1680
13.9k
    }
1681
20.1k
    return 0;
1682
0
 error:
1683
0
    free(path);
1684
0
    return -1;
1685
20.1k
}
1686
1687
77
static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1688
77
    char *path = NULL;
1689
77
    struct tree *tree;
1690
77
    int r;
1691
1692
6.25k
    for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1693
6.17k
        if (TREE_HIDDEN(tree) && ! pr_hidden)
1694
0
            continue;
1695
1696
6.17k
        path = path_of_tree(tree);
1697
6.17k
        if (path == NULL)
1698
0
            goto error;
1699
6.17k
        r = print_one(out, path, tree->value);
1700
6.17k
        if (r < 0)
1701
0
            goto error;
1702
6.17k
        r = print_rec(out, tree->children, path, pr_hidden);
1703
6.17k
        if (r < 0)
1704
0
            goto error;
1705
6.17k
        free(path);
1706
6.17k
        path = NULL;
1707
6.17k
    }
1708
77
    return 0;
1709
0
 error:
1710
0
    free(path);
1711
0
    return -1;
1712
77
}
1713
1714
0
int dump_tree(FILE *out, struct tree *tree) {
1715
0
    struct pathx *p;
1716
0
    int result;
1717
1718
0
    if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR) {
1719
0
        free_pathx(p);
1720
0
        return -1;
1721
0
    }
1722
1723
0
    result = print_tree(out, p, 1);
1724
0
    free_pathx(p);
1725
0
    return result;
1726
0
}
1727
1728
int aug_text_store(augeas *aug, const char *lens, const char *node,
1729
158
                   const char *path) {
1730
1731
158
    struct pathx *p;
1732
158
    const char *src;
1733
158
    int result = -1, r;
1734
1735
158
    api_entry(aug);
1736
1737
    /* Validate PATH is syntactically correct */
1738
158
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1739
158
    free_pathx(p);
1740
158
    ERR_BAIL(aug);
1741
1742
64
    r = aug_get(aug, node, &src);
1743
64
    ERR_BAIL(aug);
1744
17
    ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1745
17
              "Source node %s does not exist", node);
1746
11
    ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1747
11
              "Source node %s has a NULL value", node);
1748
1749
11
    result = text_store(aug, lens, path, src);
1750
158
 error:
1751
158
    api_exit(aug);
1752
158
    return result;
1753
11
}
1754
1755
int aug_text_retrieve(struct augeas *aug, const char *lens,
1756
                      const char *node_in, const char *path,
1757
0
                      const char *node_out) {
1758
0
    struct tree *tree = NULL;
1759
0
    const char *src;
1760
0
    char *out = NULL;
1761
0
    struct tree *tree_out;
1762
0
    int r;
1763
1764
0
    api_entry(aug);
1765
1766
0
    tree = tree_find(aug, path);
1767
0
    ERR_BAIL(aug);
1768
1769
0
    r = aug_get(aug, node_in, &src);
1770
0
    ERR_BAIL(aug);
1771
0
    ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1772
0
              "Source node %s does not exist", node_in);
1773
0
    ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1774
0
              "Source node %s has a NULL value", node_in);
1775
1776
0
    r = text_retrieve(aug, lens, path, tree, src, &out);
1777
0
    if (r < 0)
1778
0
        goto error;
1779
1780
0
    tree_out = tree_find_cr(aug, node_out);
1781
0
    ERR_BAIL(aug);
1782
1783
0
    tree_store_value(tree_out, &out);
1784
1785
0
    api_exit(aug);
1786
0
    return 0;
1787
0
 error:
1788
0
    free(out);
1789
0
    api_exit(aug);
1790
0
    return -1;
1791
0
}
1792
1793
int aug_transform(struct augeas *aug, const char *lens,
1794
0
                  const char *file, int excl) {
1795
0
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1796
0
    struct tree *load = tree_child_cr(meta, s_load);
1797
1798
0
    int r = 0, result = -1;
1799
0
    struct tree *xfm = NULL, *lns = NULL, *t = NULL;
1800
0
    const char *filter = NULL;
1801
0
    char *p;
1802
0
    int exists;
1803
0
    char *lensname = NULL, *xfmname = NULL;
1804
1805
0
    api_entry(aug);
1806
1807
0
    ERR_NOMEM(meta == NULL || load == NULL, aug);
1808
1809
0
    ARG_CHECK(STREQ("", lens), aug, "aug_transform: LENS must not be empty");
1810
0
    ARG_CHECK(STREQ("", file), aug, "aug_transform: FILE must not be empty");
1811
1812
0
    if ((p = strrchr(lens, '.'))) {
1813
0
        lensname = strdup(lens);
1814
0
        xfmname = strndup(lens, p - lens);
1815
0
        ERR_NOMEM(lensname == NULL || xfmname == NULL, aug);
1816
0
    } else {
1817
0
        r = xasprintf(&lensname, "%s.lns", lens);
1818
0
        xfmname = strdup(lens);
1819
0
        ERR_NOMEM(r < 0 || xfmname == NULL, aug);
1820
0
    }
1821
1822
0
    xfm = tree_child_cr(load, xfmname);
1823
0
    ERR_NOMEM(xfm == NULL, aug);
1824
1825
0
    lns = tree_child_cr(xfm, s_lens);
1826
0
    ERR_NOMEM(lns == NULL, aug);
1827
1828
0
    tree_store_value(lns, &lensname);
1829
1830
0
    exists = 0;
1831
1832
0
    filter = excl ? s_excl : s_incl;
1833
0
    list_for_each(c, xfm->children) {
1834
0
        if (c->value != NULL && STREQ(c->value, file)
1835
0
            && streqv(c->label, filter)) {
1836
0
            exists = 1;
1837
0
            break;
1838
0
        }
1839
0
    }
1840
0
    if (! exists) {
1841
0
        t = tree_append_s(xfm, filter, NULL);
1842
0
        ERR_NOMEM(t == NULL, aug);
1843
0
        r = tree_set_value(t, file);
1844
0
        ERR_NOMEM(r < 0, aug);
1845
0
    }
1846
1847
0
    result = 0;
1848
0
 error:
1849
0
    free(lensname);
1850
0
    free(xfmname);
1851
0
    api_exit(aug);
1852
0
    return result;
1853
0
}
1854
1855
1.52k
int aug_escape_name(augeas *aug, const char *in, char **out) {
1856
1.52k
    int result = -1;
1857
1858
1.52k
    api_entry(aug);
1859
1.52k
    ARG_CHECK(in == NULL, aug, "aug_escape_name: IN must not be NULL");
1860
1.52k
    ARG_CHECK(out == NULL, aug, "aug_escape_name: OUT must not be NULL");
1861
1862
1.52k
    result = pathx_escape_name(in, out);
1863
1.52k
    ERR_NOMEM(result < 0, aug);
1864
1.52k
 error:
1865
1.52k
    api_exit(aug);
1866
1.52k
    return result;
1867
1.52k
}
1868
1869
0
int aug_load_file(struct augeas *aug, const char *file) {
1870
0
    int result = -1, r;
1871
0
    struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1872
0
    struct tree *load = tree_child_cr(meta, s_load);
1873
0
    char *tree_path = NULL;
1874
0
    bool found = false;
1875
1876
0
    api_entry(aug);
1877
1878
0
    ERR_NOMEM(load == NULL, aug);
1879
1880
0
    list_for_each(xfm, load->children)  {
1881
0
        if (filter_matches(xfm, file)) {
1882
0
            transform_load(aug, xfm, file);
1883
0
            found = true;
1884
0
            break;
1885
0
        }
1886
0
    }
1887
1888
0
    ERR_THROW(!found, aug, AUG_ENOLENS,
1889
0
              "can not determine lens to load file %s", file);
1890
1891
    /* Mark the nodes we just loaded as clean so they won't get saved
1892
       without additional modifications */
1893
0
    r = xasprintf(&tree_path, "/files/%s", file);
1894
0
    ERR_NOMEM(r < 0, aug);
1895
1896
0
    struct tree *t = tree_fpath(aug, tree_path);
1897
0
    if (t != NULL) {
1898
0
        tree_clean(t);
1899
0
    }
1900
1901
0
    result = 0;
1902
0
error:
1903
0
    api_exit(aug);
1904
0
    free(tree_path);
1905
0
    return result;
1906
0
}
1907
1908
158
int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
1909
158
    struct pathx *p;
1910
158
    int result = -1;
1911
1912
158
    api_entry(aug);
1913
1914
158
    if (pathin == NULL || strlen(pathin) == 0) {
1915
1
        pathin = "/*";
1916
1
    }
1917
1918
158
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1919
158
    ERR_BAIL(aug);
1920
1921
77
    result = print_tree(out, p, 0);
1922
158
 error:
1923
158
    free_pathx(p);
1924
158
    api_exit(aug);
1925
158
    return result;
1926
77
}
1927
1928
static char *
1929
0
tree_source(const augeas *aug, struct tree *tree) {
1930
0
    char *result = NULL;
1931
1932
0
    while (!(ROOT_P(tree) || tree->file))
1933
0
        tree = tree->parent;
1934
1935
0
    if (tree->file) {
1936
0
        if (tree->span == NULL) {
1937
0
            int r;
1938
0
            r = ALLOC(tree->span);
1939
0
            ERR_NOMEM(r < 0, aug);
1940
0
            tree->span->filename = make_string(path_of_tree(tree));
1941
0
            ERR_NOMEM(tree->span->filename == NULL, aug);
1942
0
        }
1943
0
        result = strdup(tree->span->filename->str);
1944
0
        ERR_NOMEM(result == NULL, aug);
1945
0
    }
1946
0
 error:
1947
0
    return result;
1948
0
}
1949
1950
0
int aug_source(const augeas *aug, const char *path, char **file_path) {
1951
0
    int result = -1, r;
1952
0
    struct pathx *p = NULL;
1953
0
    struct tree *match;
1954
1955
0
    api_entry(aug);
1956
1957
0
    ARG_CHECK(file_path == NULL, aug,
1958
0
              "aug_source_file: FILE_PATH must not be NULL");
1959
0
    *file_path = NULL;
1960
1961
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1962
0
    ERR_BAIL(aug);
1963
1964
0
    r = pathx_find_one(p, &match);
1965
0
    ERR_BAIL(aug);
1966
0
    ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
1967
0
              r, path);
1968
0
    ERR_THROW(r == 0, aug, AUG_ENOMATCH, "There is no node matching %s",
1969
0
              path);
1970
1971
0
    *file_path = tree_source(aug, match);
1972
0
    ERR_BAIL(aug);
1973
1974
0
    result = 0;
1975
0
 error:
1976
0
    free_pathx(p);
1977
0
    api_exit(aug);
1978
0
    return result;
1979
0
}
1980
1981
0
int aug_preview(struct augeas *aug, const char *path, char **out) {
1982
0
    struct tree *tree = NULL;
1983
0
    struct pathx *p;
1984
0
    int r;
1985
0
    int result=-1;
1986
0
    char *lens_path = NULL;
1987
0
    char *lens_name = NULL;
1988
0
    char *file_path = NULL;
1989
0
    char *source_filename = NULL;
1990
0
    char *source_text = NULL;
1991
1992
0
    *out = NULL;
1993
1994
0
    api_entry(aug);
1995
1996
0
    p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1997
0
    ERR_BAIL(aug);
1998
1999
0
    tree = pathx_first(p);
2000
0
    ERR_BAIL(aug);
2001
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
2002
2003
0
    file_path = tree_source(aug, tree);
2004
2005
0
    ERR_THROW(file_path == NULL, aug, AUG_EBADARG, "Path %s is not associated with a file", path);
2006
2007
0
    tree = tree_find(aug, file_path);
2008
2009
0
    xasprintf(&lens_path, "%s%s/%s", AUGEAS_META_TREE, file_path, s_lens);
2010
0
    ERR_NOMEM(lens_path == NULL, aug);
2011
2012
0
    aug_get(aug,lens_path,(const char **) &lens_name);
2013
0
    ERR_BAIL(aug);
2014
2015
0
    ERR_THROW(lens_name == NULL, aug, AUG_ENOLENS, "No lens found for path %s", path);
2016
2017
0
    xasprintf(&source_filename, "%s%s",aug->root, file_path + strlen(AUGEAS_FILES_TREE) + 1);
2018
0
    ERR_NOMEM(source_filename == NULL, aug);
2019
2020
0
    source_text = xread_file(source_filename);
2021
2022
0
    ERR_THROW(source_text == NULL, aug, AUG_EFILEACCESS, "Cannot read file %s", source_filename);
2023
2024
0
    r = text_retrieve(aug, lens_name, file_path, tree, source_text, out);
2025
0
    if (r < 0)
2026
0
        goto error;
2027
2028
0
    result = 0;
2029
2030
0
 error:
2031
0
    free(p);
2032
0
    free(file_path);
2033
0
    free(lens_path);
2034
0
    free(source_filename);
2035
0
    free(source_text);
2036
0
    api_exit(aug);
2037
0
    return result;
2038
0
}
2039
2040
1.68k
void aug_close(struct augeas *aug) {
2041
1.68k
    if (aug == NULL)
2042
0
        return;
2043
2044
    /* There's no point in bothering with api_entry/api_exit here */
2045
1.68k
    free_tree(aug->origin);
2046
1.68k
    unref(aug->modules, module);
2047
1.68k
    if (aug->error->exn != NULL) {
2048
1.68k
        aug->error->exn->ref = 0;
2049
1.68k
        free_value(aug->error->exn);
2050
1.68k
        aug->error->exn = NULL;
2051
1.68k
    }
2052
1.68k
    free((void *) aug->root);
2053
1.68k
    free(aug->modpathz);
2054
1.68k
    free_symtab(aug->symtab);
2055
1.68k
    unref(aug->error->info, info);
2056
1.68k
    free(aug->error->details);
2057
1.68k
    free(aug->error);
2058
1.68k
    free(aug);
2059
1.68k
}
2060
2061
0
int __aug_load_module_file(struct augeas *aug, const char *filename) {
2062
0
    api_entry(aug);
2063
0
    int r = load_module_file(aug, filename, NULL);
2064
0
    api_exit(aug);
2065
0
    return r;
2066
0
}
2067
2068
0
int tree_equal(const struct tree *t1, const struct tree *t2) {
2069
0
    while (t1 != NULL && t2 != NULL) {
2070
0
        if (!streqv(t1->label, t2->label))
2071
0
            return 0;
2072
0
        if (!streqv(t1->value, t2->value))
2073
0
            return 0;
2074
0
        if (! tree_equal(t1->children, t2->children))
2075
0
            return 0;
2076
0
        t1 = t1->next;
2077
0
        t2 = t2->next;
2078
0
    }
2079
0
    return t1 == t2;
2080
0
}
2081
2082
int aug_ns_attr(const augeas* aug, const char *var, int i,
2083
0
                const char **value, const char **label, char **file_path) {
2084
0
    int result = -1;
2085
2086
0
    if (value != NULL)
2087
0
        *value = NULL;
2088
2089
0
    if (label != NULL)
2090
0
        *label = NULL;
2091
2092
0
    if (file_path != NULL)
2093
0
        *file_path = NULL;
2094
2095
0
    api_entry(aug);
2096
2097
0
    struct tree *tree = pathx_symtab_get_tree(aug->symtab, var, i);
2098
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH,
2099
0
              "Node %s[%d] does not exist", var, i);
2100
2101
0
    if (file_path != NULL) {
2102
0
        *file_path = tree_source(aug, tree);
2103
0
        ERR_BAIL(aug);
2104
0
    }
2105
2106
0
    if (value != NULL)
2107
0
        *value = tree->value;
2108
2109
0
    if (label != NULL)
2110
0
        *label = tree->label;
2111
2112
0
    result = 1;
2113
2114
0
 error:
2115
0
    api_exit(aug);
2116
0
    return result;
2117
0
}
2118
2119
int aug_ns_label(const augeas* aug, const char *var, int i,
2120
0
                 const char **label, int *index) {
2121
0
    int result = -1;
2122
2123
0
    if (label != NULL)
2124
0
        *label = NULL;
2125
2126
0
    if (index != NULL)
2127
0
        *index = -1;
2128
2129
0
    api_entry(aug);
2130
2131
0
    struct tree *tree = pathx_symtab_get_tree(aug->symtab, var, i);
2132
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH,
2133
0
              "Node %s[%d] does not exist", var, i);
2134
2135
0
    if (label != NULL)
2136
0
        *label = tree->label;
2137
2138
0
    if (index != NULL) {
2139
0
        *index = tree_sibling_index(tree);
2140
0
    }
2141
2142
0
    result = 1;
2143
2144
0
 error:
2145
0
    api_exit(aug);
2146
0
    return result;
2147
0
}
2148
2149
int aug_ns_value(const augeas* aug, const char *var, int i,
2150
0
                 const char **value) {
2151
0
    int result = -1;
2152
2153
0
    if (value != NULL)
2154
0
        *value = NULL;
2155
2156
0
    api_entry(aug);
2157
2158
0
    struct tree *tree = pathx_symtab_get_tree(aug->symtab, var, i);
2159
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH,
2160
0
              "Node %s[%d] does not exist", var, i);
2161
2162
0
    if (value != NULL)
2163
0
        *value = tree->value;
2164
2165
0
    result = 1;
2166
2167
0
 error:
2168
0
    api_exit(aug);
2169
0
    return result;
2170
0
}
2171
2172
0
int aug_ns_count(const augeas *aug, const char *var) {
2173
0
    int result = -1;
2174
2175
0
    api_entry(aug);
2176
2177
0
    result = pathx_symtab_count(aug->symtab, var);
2178
2179
0
    api_exit(aug);
2180
2181
0
    return result;
2182
0
}
2183
2184
0
int aug_ns_path(const augeas *aug, const char *var, int i, char **path) {
2185
0
    int result = -1;
2186
2187
0
    *path = NULL;
2188
2189
0
    api_entry(aug);
2190
2191
0
    struct tree *tree = pathx_symtab_get_tree(aug->symtab, var, i);
2192
0
    ERR_THROW(tree == NULL, aug, AUG_ENOMATCH,
2193
0
              "Node %s[%d] does not exist", var, i);
2194
2195
0
    *path = path_of_tree(tree);
2196
2197
0
    result = 0;
2198
2199
0
 error:
2200
0
    api_exit(aug);
2201
0
    return result;
2202
0
}
2203
2204
/*
2205
 * Error reporting API
2206
 */
2207
0
int aug_error(struct augeas *aug) {
2208
0
    return aug->error->code;
2209
0
}
2210
2211
0
const char *aug_error_message(struct augeas *aug) {
2212
0
    aug_errcode_t errcode = aug->error->code;
2213
2214
0
    if (errcode >= ARRAY_CARDINALITY(errcodes))
2215
0
        errcode = AUG_EINTERNAL;
2216
0
    return errcodes[errcode];
2217
0
}
2218
2219
0
const char *aug_error_minor_message(struct augeas *aug) {
2220
0
    return aug->error->minor_details;
2221
0
}
2222
2223
0
const char *aug_error_details(struct augeas *aug) {
2224
0
    return aug->error->details;
2225
0
}
2226
2227
/*
2228
 * Local variables:
2229
 *  indent-tabs-mode: nil
2230
 *  c-indent-level: 4
2231
 *  c-basic-offset: 4
2232
 *  tab-width: 4
2233
 * End:
2234
 */