[augeas-devel] [PATCH] Validate trees representing a transform before using them

David Lutterkort lutter at redhat.com
Wed Mar 18 23:04:59 UTC 2009


---
 src/augeas.c      |   41 +++++++++++----------------
 src/internal.h    |    2 +
 src/transform.c   |   79 +++++++++++++++++++++++++++++++++++++++++++----------
 src/transform.h   |    7 +++++
 tests/test-load.c |   35 +++++++++++++++++++++++
 5 files changed, 125 insertions(+), 39 deletions(-)

diff --git a/src/augeas.c b/src/augeas.c
index 42eaac3..a6ac078 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -94,19 +94,6 @@ static struct pathx *parse_user_pathx(const struct augeas *aug,
     return NULL;
 }
 
-static struct tree *tree_find(struct tree *origin, const char *path) {
-    struct pathx *px = NULL;
-    struct tree *result = NULL;
-
-    if (pathx_parse(origin, path, &px) != 0)
-        return NULL;
-
-    pathx_find_one(px, &result);
-    free_pathx(px);
-
-    return result;
-}
-
 static struct tree *tree_child(struct tree *tree, const char *label) {
     if (tree == NULL)
         return NULL;
@@ -138,8 +125,8 @@ static const char *init_root(const char *root0) {
     return root;
 }
 
-static struct tree *tree_append(struct tree *parent,
-                                char *label, char *value) {
+struct tree *tree_append(struct tree *parent,
+                         char *label, char *value) {
     struct tree *result = make_tree(label, value, parent, NULL);
     if (result != NULL)
         list_append(parent->children, result);
@@ -310,7 +297,8 @@ int aug_load(struct augeas *aug) {
     tree_unlink_children(files);
 
     list_for_each(xfm, load->children) {
-        transform_load(aug, xfm);
+        if (transform_validate(aug, xfm) == 0)
+            transform_load(aug, xfm);
     }
     tree_clean(aug->origin);
     return 0;
@@ -764,28 +752,33 @@ static int unlink_removed_files(struct augeas *aug,
 
 int aug_save(struct augeas *aug) {
     int ret = 0;
-    struct tree *files;
+    struct tree *meta = tree_child(aug->origin, "augeas");
+    struct tree *meta_files = tree_child(meta, "files");
+    struct tree *files = tree_child(aug->origin, "files");
+    struct tree *load = tree_child(meta, "load");
 
     if (update_save_flags(aug) < 0)
         return -1;
 
-    files = tree_find(aug->origin, AUGEAS_FILES_TREE);
     if (files == NULL)
         return -1;
 
+    if (meta == NULL || load == NULL)
+        return 0;
+
     aug_rm(aug, AUGEAS_EVENTS_SAVED);
 
+    list_for_each(xfm, load->children)
+        transform_validate(aug, xfm);
+
     if (files->dirty) {
         list_for_each(t, files->children) {
             if (tree_save(aug, t, AUGEAS_FILES_TREE) == -1)
                 ret = -1;
         }
-        /* Remove files whose entire subtree was removed. META
-         * will be NULL if all files are new
-         */
-        struct tree *meta = tree_find(aug->origin, AUGEAS_META_FILES);
-        if (meta != NULL) {
-            if (unlink_removed_files(aug, files, meta) < 0)
+        /* Remove files whose entire subtree was removed. */
+        if (meta_files != NULL) {
+            if (unlink_removed_files(aug, files, meta_files) < 0)
                 ret = -1;
         }
     }
diff --git a/src/internal.h b/src/internal.h
index b689677..407f184 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -321,6 +321,8 @@ struct tree *make_tree(char *label, char *value,
 struct tree  *make_tree_origin(struct tree *root);
 
 int tree_replace(struct tree *origin, const char *path, struct tree *sub);
+/* Make a new tree node and append it to parent's children */
+struct tree *tree_append(struct tree *parent, char *label, char *value);
 
 int tree_rm(struct pathx *p);
 int tree_unlink(struct tree *tree);
diff --git a/src/transform.c b/src/transform.c
index fbb6dc2..155a7af 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -402,6 +402,25 @@ static int load_file(struct augeas *aug, struct lens *lens, char *filename) {
     return result;
 }
 
+/* The lens for a transform can be referred to in one of two ways:
+ * either by a fully qualified name "Module.lens" or by the special
+ * syntax "@Module"; the latter means we should take the lens from the
+ * autoload transform for Module
+ */
+static struct lens *lens_from_name(struct augeas *aug, const char *name) {
+    if (name[0] == '@') {
+        struct module *modl = NULL;
+        for (modl = aug->modules;
+             modl != NULL && !streqv(modl->name, name + 1);
+             modl = modl->next);
+        if (modl == NULL || modl->autoload == NULL)
+            return NULL;
+        return modl->autoload->lens;
+    } else {
+        return lens_lookup(aug, name);
+    }
+}
+
 static struct lens *xfm_lens(struct augeas *aug, struct tree *xfm) {
     struct tree *l = NULL;
 
@@ -411,23 +430,53 @@ static struct lens *xfm_lens(struct augeas *aug, struct tree *xfm) {
 
     if (l == NULL || l->value == NULL)
         return NULL;
+    return lens_from_name(aug, l->value);
+}
 
-    /* The lens for a transform can be referred to in one of two ways:
-     * either by a fully qualified name "Module.lens" or by the special
-     * syntax "@Module"; the latter means we should take the lens from the
-     * autoload transform for Module
-     */
-    if (l->value[0] == '@') {
-        struct module *modl = NULL;
-        for (modl = aug->modules;
-             modl != NULL && !streqv(modl->name, l->value + 1);
-             modl = modl->next);
-        if (modl == NULL || modl->autoload == NULL)
-            return NULL;
-        return modl->autoload->lens;
-    } else {
-        return lens_lookup(aug, l->value);
+static void xfm_error(struct tree *xfm, const char *msg) {
+    char *v = strdup(msg);
+    char *l = strdup("error");
+    struct tree *e = NULL;
+
+    if (l == NULL || v == NULL)
+        return;
+    e = tree_append(xfm, l, v);
+}
+
+int transform_validate(struct augeas *aug, struct tree *xfm) {
+    struct tree *l = NULL;
+
+    for (struct tree *t = xfm->children; t != NULL; ) {
+        if (streqv(t->label, "lens"))
+            l = t;
+        if (streqv(t->label, "error")) {
+            struct tree *del = t;
+            t = del->next;
+            tree_unlink(del);
+        } else {
+            t = t->next;
+        }
+    }
+
+    if (l == NULL) {
+        xfm_error(xfm, "missing a child with label 'lens'");
+        return -1;
     }
+    if (l->value == NULL) {
+        xfm_error(xfm, "the 'lens' node does not contain a lens name");
+        return -1;
+    }
+    if (lens_from_name(aug, l->value) == NULL) {
+        char *msg;
+        if (asprintf(&msg, "the lens '%s' does not exist", l->value) < 0) {
+            xfm_error(xfm, "the lens does not exist");
+        } else {
+            xfm_error(xfm, msg);
+            free(msg);
+        }
+        return -1;
+    }
+    return 0;
 }
 
 int transform_load(struct augeas *aug, struct tree *xfm) {
diff --git a/src/transform.h b/src/transform.h
index 78483dc..1178f64 100644
--- a/src/transform.h
+++ b/src/transform.h
@@ -54,6 +54,13 @@ void free_transform(struct transform *xform);
  * are glob patterns used to filter which files to transform.
  */
 
+/* Verify that the tree XFM represents a valid transform. If it does not,
+ * add an 'error' child to it.
+ *
+ * Return 0 if XFM is a valid transform, -1 otherwise.
+ */
+int transform_validate(struct augeas *aug, struct tree *xfm);
+
 /* Load all files matching the TRANSFORM's filter into the tree in AUG by
  * applying the TRANSFORM's lens to their contents and putting the
  * resulting tree under "/files" + filename. Also stores some information
diff --git a/tests/test-load.c b/tests/test-load.c
index 3d6fab1..4ca1fce 100644
--- a/tests/test-load.c
+++ b/tests/test-load.c
@@ -99,6 +99,40 @@ static void testNoLoad(CuTest *tc) {
     aug_close(aug);
 }
 
+static void invalidLens(CuTest *tc, augeas *aug, const char *lens) {
+    int r, nmatches;
+
+    r = aug_set(aug, "/augeas/load/Junk/lens", lens);
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_set(aug, "/augeas/load/Junk/incl", "/dev/null");
+    CuAssertRetSuccess(tc, r);
+
+    r = aug_load(aug);
+    CuAssertRetSuccess(tc, r);
+
+    nmatches = aug_match(aug, "/augeas/load/Junk/error", NULL);
+    CuAssertIntEquals(tc, 1, nmatches);
+}
+
+static void testInvalidLens(CuTest *tc) {
+    augeas *aug = NULL;
+    int r;
+
+    aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD);
+    CuAssertPtrNotNull(tc, aug);
+
+    r = aug_rm(aug, "/augeas/load/*");
+    CuAssertTrue(tc, r >= 0);
+
+    invalidLens(tc, aug, NULL);
+    invalidLens(tc, aug, "@Nomodule");
+    invalidLens(tc, aug, "@Util");
+    invalidLens(tc, aug, "Nomodule.noelns");
+
+    aug_close(aug);
+}
+
 int main(void) {
     char *output = NULL;
     CuSuite* suite = CuSuiteNew();
@@ -106,6 +140,7 @@ int main(void) {
 
     SUITE_ADD_TEST(suite, testDefault);
     SUITE_ADD_TEST(suite, testNoLoad);
+    SUITE_ADD_TEST(suite, testInvalidLens);
 
     abs_top_srcdir = getenv("abs_top_srcdir");
     if (abs_top_srcdir == NULL)
-- 
1.6.0.6




More information about the augeas-devel mailing list