From ee1b4750545fefcd260259bcc146b2ee898f6410 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 07 2019 10:47:51 +0000 Subject: import augeas-1.10.1-8.el8 --- diff --git a/.augeas.metadata b/.augeas.metadata new file mode 100644 index 0000000..a966240 --- /dev/null +++ b/.augeas.metadata @@ -0,0 +1 @@ +3cfa4870fac3b6697e8039cb611cb0c5a75498a4 SOURCES/augeas-1.10.1.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83a3dbf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/augeas-1.10.1.tar.gz diff --git a/SOURCES/0001-Fix-several-memory-leak-in-augmatch.patch b/SOURCES/0001-Fix-several-memory-leak-in-augmatch.patch new file mode 100644 index 0000000..60022fe --- /dev/null +++ b/SOURCES/0001-Fix-several-memory-leak-in-augmatch.patch @@ -0,0 +1,53 @@ +From 0cfb9fc93b4cd967c9f8bb2f50df5ccff84a497e Mon Sep 17 00:00:00 2001 +From: Han Han +Date: Mon, 9 Apr 2018 15:59:45 +0800 +Subject: [PATCH] Fix several memory leak in augmatch + +(cherry picked from commit 46a62a71553c6bac8f61ecc2a33f65b13e7ad2c0) +--- + src/augmatch.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/augmatch.c b/src/augmatch.c +index 20045c5f..1ac9b680 100644 +--- a/src/augmatch.c ++++ b/src/augmatch.c +@@ -131,6 +131,7 @@ static void check_load_error(struct augeas *aug, const char *file) { + const char *msg, *line, *col; + + aug_defvar(aug, "info", info); ++ free(info); + die(aug_ns_count(aug, "info") == 0, "file %s does not exist\n", file); + + aug_defvar(aug, "error", "$info/error"); +@@ -240,7 +241,7 @@ static void print_tree(struct augeas *aug, int level, + static void print(struct augeas *aug, const char *path, const char *match) { + static const char *const match_var = "match"; + +- cleanup(freep) struct node *nodes = NULL; ++ struct node *nodes = NULL; + + nodes = calloc(max_nodes, sizeof(struct node)); + oom_when(nodes == NULL); +@@ -265,6 +266,10 @@ static void print(struct augeas *aug, const char *path, const char *match) { + aug_defvar(aug, nodes[0].var, prefix); + print_tree(aug, 0, prefix + strlen(path) + 1, nodes); + } ++ for (int i=0; i < max_nodes; i++) { ++ free(nodes[i].var); ++ } ++ free(nodes); + } + + /* Look at the filename and try to guess based on the extension. The +@@ -421,6 +426,7 @@ int main(int argc, char **argv) { + } + + print(aug, path, match); ++ free(path); + } + + /* +-- +2.17.2 + diff --git a/SOURCES/0002-Use-a-safer-calling-convention-for-native-functions.patch b/SOURCES/0002-Use-a-safer-calling-convention-for-native-functions.patch new file mode 100644 index 0000000..b55b882 --- /dev/null +++ b/SOURCES/0002-Use-a-safer-calling-convention-for-native-functions.patch @@ -0,0 +1,464 @@ +From c514988fa3ff57e7622678963c1141b59b4d88d7 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Mon, 4 Jun 2018 23:19:28 -0700 +Subject: [PATCH] Use a safer calling convention for native functions + +The native functions in the lens interpreter used a calling convention that +required unsafe casting of function pointers. We now use a calling +convention that does not cause any function pointer casts. + +(cherry picked from commit 31c3532e5e8d4707dfb7de12278221001dafdd5a) +--- + src/builtin.c | 161 +++++++++++++++++++++++++++++++++----------------- + src/syntax.c | 34 ++--------- + src/syntax.h | 11 +++- + 3 files changed, 119 insertions(+), 87 deletions(-) + +diff --git a/src/builtin.c b/src/builtin.c +index 732ee10c..7cf4fa0a 100644 +--- a/src/builtin.c ++++ b/src/builtin.c +@@ -42,8 +42,10 @@ + */ + + /* V_REGEXP -> V_STRING -> V_LENS */ +-static struct value *lns_del(struct info *info, +- struct value *rxp, struct value *dflt) { ++static struct value *lns_del(struct info *info, struct value **argv) { ++ struct value *rxp = argv[0]; ++ struct value *dflt = argv[1]; ++ + assert(rxp->tag == V_REGEXP); + assert(dflt->tag == V_STRING); + return lns_make_prim(L_DEL, ref(info), +@@ -51,44 +53,59 @@ static struct value *lns_del(struct info *info, + } + + /* V_REGEXP -> V_LENS */ +-static struct value *lns_store(struct info *info, struct value *rxp) { ++static struct value *lns_store(struct info *info, struct value **argv) { ++ struct value *rxp = argv[0]; ++ + assert(rxp->tag == V_REGEXP); + return lns_make_prim(L_STORE, ref(info), ref(rxp->regexp), NULL); + } + + /* V_STRING -> V_LENS */ +-static struct value *lns_value(struct info *info, struct value *str) { ++static struct value *lns_value(struct info *info, struct value **argv) { ++ struct value *str = argv[0]; ++ + assert(str->tag == V_STRING); + return lns_make_prim(L_VALUE, ref(info), NULL, ref(str->string)); + } + + /* V_REGEXP -> V_LENS */ +-static struct value *lns_key(struct info *info, struct value *rxp) { ++static struct value *lns_key(struct info *info, struct value **argv) { ++ struct value *rxp = argv[0]; ++ + assert(rxp->tag == V_REGEXP); + return lns_make_prim(L_KEY, ref(info), ref(rxp->regexp), NULL); + } + + /* V_STRING -> V_LENS */ +-static struct value *lns_label(struct info *info, struct value *str) { ++static struct value *lns_label(struct info *info, struct value **argv) { ++ struct value *str = argv[0]; ++ + assert(str->tag == V_STRING); + return lns_make_prim(L_LABEL, ref(info), NULL, ref(str->string)); + } + + /* V_STRING -> V_LENS */ +-static struct value *lns_seq(struct info *info, struct value *str) { ++static struct value *lns_seq(struct info *info, struct value **argv) { ++ struct value *str = argv[0]; ++ + assert(str->tag == V_STRING); + return lns_make_prim(L_SEQ, ref(info), NULL, ref(str->string)); + } + + /* V_STRING -> V_LENS */ +-static struct value *lns_counter(struct info *info, struct value *str) { ++static struct value *lns_counter(struct info *info, struct value **argv) { ++ struct value *str = argv[0]; ++ + assert(str->tag == V_STRING); + return lns_make_prim(L_COUNTER, ref(info), NULL, ref(str->string)); + } + + /* V_LENS -> V_LENS -> V_LENS -> V_LENS */ +-static struct value *lns_square(struct info *info, struct value *l1, +- struct value *l2, struct value *l3) { ++static struct value *lns_square(struct info *info, struct value **argv) { ++ struct value *l1 = argv[0]; ++ struct value *l2 = argv[1]; ++ struct value *l3 = argv[2]; ++ + assert(l1->tag == V_LENS); + assert(l2->tag == V_LENS); + assert(l3->tag == V_LENS); +@@ -179,8 +196,10 @@ static struct value *pathx_parse_glue(struct info *info, struct value *tree, + } + + /* V_LENS -> V_STRING -> V_TREE */ +-static struct value *lens_get(struct info *info, struct value *l, +- struct value *str) { ++static struct value *lens_get(struct info *info, struct value **argv) { ++ struct value *l = argv[0]; ++ struct value *str = argv[1]; ++ + assert(l->tag == V_LENS); + assert(str->tag == V_STRING); + struct lns_error *err; +@@ -210,8 +229,11 @@ static struct value *lens_get(struct info *info, struct value *l, + + + /* V_LENS -> V_TREE -> V_STRING -> V_STRING */ +-static struct value *lens_put(struct info *info, struct value *l, +- struct value *tree, struct value *str) { ++static struct value *lens_put(struct info *info, struct value **argv) { ++ struct value *l = argv[0]; ++ struct value *tree = argv[1]; ++ struct value *str = argv[2]; ++ + assert(l->tag == V_LENS); + assert(tree->tag == V_TREE); + assert(str->tag == V_STRING); +@@ -237,11 +259,14 @@ static struct value *lens_put(struct info *info, struct value *l, + } + + /* V_STRING -> V_STRING -> V_TREE -> V_TREE */ +-static struct value *tree_set_glue(struct info *info, struct value *path, +- struct value *val, struct value *tree) { ++static struct value *tree_set_glue(struct info *info, struct value **argv) { + // FIXME: This only works if TREE is not referenced more than once; + // otherwise we'll have some pretty weird semantics, and would really + // need to copy TREE first ++ struct value *path = argv[0]; ++ struct value *val = argv[1]; ++ struct value *tree = argv[2]; ++ + assert(path->tag == V_STRING); + assert(val->tag == V_STRING); + assert(tree->tag == V_TREE); +@@ -277,11 +302,13 @@ static struct value *tree_set_glue(struct info *info, struct value *path, + } + + /* V_STRING -> V_TREE -> V_TREE */ +-static struct value *tree_clear_glue(struct info *info, struct value *path, +- struct value *tree) { ++static struct value *tree_clear_glue(struct info *info, struct value **argv) { + // FIXME: This only works if TREE is not referenced more than once; + // otherwise we'll have some pretty weird semantics, and would really + // need to copy TREE first ++ struct value *path = argv[0]; ++ struct value *tree = argv[1]; ++ + assert(path->tag == V_STRING); + assert(tree->tag == V_TREE); + +@@ -349,25 +376,32 @@ static struct value *tree_insert_glue(struct info *info, struct value *label, + + /* Insert after */ + /* V_STRING -> V_STRING -> V_TREE -> V_TREE */ +-static struct value *tree_insa_glue(struct info *info, struct value *label, +- struct value *path, struct value *tree) { ++static struct value *tree_insa_glue(struct info *info, struct value **argv) { ++ struct value *label = argv[0]; ++ struct value *path = argv[1]; ++ struct value *tree = argv[2]; ++ + return tree_insert_glue(info, label, path, tree, 0); + } + + /* Insert before */ + /* V_STRING -> V_STRING -> V_TREE -> V_TREE */ +-static struct value *tree_insb_glue(struct info *info, struct value *label, +- struct value *path, struct value *tree) { ++static struct value *tree_insb_glue(struct info *info, struct value **argv) { ++ struct value *label = argv[0]; ++ struct value *path = argv[1]; ++ struct value *tree = argv[2]; ++ + return tree_insert_glue(info, label, path, tree, 1); + } + + /* V_STRING -> V_TREE -> V_TREE */ +-static struct value *tree_rm_glue(struct info *info, +- struct value *path, +- struct value *tree) { ++static struct value *tree_rm_glue(struct info *info, struct value **argv) { + // FIXME: This only works if TREE is not referenced more than once; + // otherwise we'll have some pretty weird semantics, and would really + // need to copy TREE first ++ struct value *path = argv[0]; ++ struct value *tree = argv[1]; ++ + assert(path->tag == V_STRING); + assert(tree->tag == V_TREE); + +@@ -390,7 +424,9 @@ static struct value *tree_rm_glue(struct info *info, + } + + /* V_STRING -> V_STRING */ +-static struct value *gensym(struct info *info, struct value *prefix) { ++static struct value *gensym(struct info *info, struct value **argv) { ++ struct value *prefix = argv[0]; ++ + assert(prefix->tag == V_STRING); + static unsigned int count = 0; + struct value *v; +@@ -406,7 +442,9 @@ static struct value *gensym(struct info *info, struct value *prefix) { + } + + /* V_STRING -> V_FILTER */ +-static struct value *xform_incl(struct info *info, struct value *s) { ++static struct value *xform_incl(struct info *info, struct value **argv) { ++ struct value *s = argv[0]; ++ + assert(s->tag == V_STRING); + struct value *v = make_value(V_FILTER, ref(info)); + v->filter = make_filter(ref(s->string), 1); +@@ -414,7 +452,9 @@ static struct value *xform_incl(struct info *info, struct value *s) { + } + + /* V_STRING -> V_FILTER */ +-static struct value *xform_excl(struct info *info, struct value *s) { ++static struct value *xform_excl(struct info *info, struct value **argv) { ++ struct value *s = argv[0]; ++ + assert(s->tag == V_STRING); + struct value *v = make_value(V_FILTER, ref(info)); + v->filter = make_filter(ref(s->string), 0); +@@ -422,8 +462,10 @@ static struct value *xform_excl(struct info *info, struct value *s) { + } + + /* V_LENS -> V_FILTER -> V_TRANSFORM */ +-static struct value *xform_transform(struct info *info, struct value *l, +- struct value *f) { ++static struct value *xform_transform(struct info *info, struct value **argv) { ++ struct value *l = argv[0]; ++ struct value *f = argv[1]; ++ + assert(l->tag == V_LENS); + assert(f->tag == V_FILTER); + if (l->lens->value || l->lens->key) { +@@ -436,14 +478,16 @@ static struct value *xform_transform(struct info *info, struct value *l, + return v; + } + +-static struct value *sys_getenv(struct info *info, struct value *n) { +- assert(n->tag == V_STRING); ++static struct value *sys_getenv(struct info *info, struct value **argv) { ++ assert(argv[0]->tag == V_STRING); + struct value *v = make_value(V_STRING, ref(info)); +- v->string = dup_string(getenv(n->string->str)); ++ v->string = dup_string(getenv(argv[0]->string->str)); + return v; + } + +-static struct value *sys_read_file(struct info *info, struct value *n) { ++static struct value *sys_read_file(struct info *info, struct value **argv) { ++ struct value *n = argv[0]; ++ + assert(n->tag == V_STRING); + char *str = NULL; + +@@ -464,7 +508,10 @@ static struct value *sys_read_file(struct info *info, struct value *n) { + + /* V_LENS -> V_LENS */ + static struct value *lns_check_rec_glue(struct info *info, +- struct value *l, struct value *r) { ++ struct value **argv) { ++ struct value *l = argv[0]; ++ struct value *r = argv[1]; ++ + assert(l->tag == V_LENS); + assert(r->tag == V_LENS); + int check = typecheck_p(info); +@@ -477,28 +524,28 @@ static struct value *lns_check_rec_glue(struct info *info, + */ + + /* V_STRING -> V_UNIT */ +-static struct value *pr_string(struct info *info, struct value *s) { +- printf("%s", s->string->str); ++static struct value *pr_string(struct info *info, struct value **argv) { ++ printf("%s", argv[0]->string->str); + return make_unit(ref(info)); + } + + /* V_REGEXP -> V_UNIT */ +-static struct value *pr_regexp(struct info *info, struct value *r) { +- print_regexp(stdout, r->regexp); ++static struct value *pr_regexp(struct info *info, struct value **argv) { ++ print_regexp(stdout, argv[0]->regexp); + return make_unit(ref(info)); + } + + /* V_STRING -> V_UNIT */ +-static struct value *pr_endline(struct info *info, struct value *s) { +- printf("%s\n", s->string->str); ++static struct value *pr_endline(struct info *info, struct value **argv) { ++ printf("%s\n", argv[0]->string->str); + return make_unit(ref(info)); + } + + /* V_TREE -> V_TREE */ + static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info, +- struct value *t) { +- print_tree_braces(stdout, 0, t->origin); +- return ref(t); ++ struct value **argv) { ++ print_tree_braces(stdout, 0, argv[0]->origin); ++ return ref(argv[0]); + } + + /* +@@ -515,27 +562,29 @@ static struct value *lns_value_of_type(struct info *info, struct regexp *rx) { + } + + /* V_LENS -> V_REGEXP */ +-static struct value *lns_ctype(struct info *info, struct value *l) { +- return lns_value_of_type(info, l->lens->ctype); ++static struct value *lns_ctype(struct info *info, struct value **argv) { ++ return lns_value_of_type(info, argv[0]->lens->ctype); + } + + /* V_LENS -> V_REGEXP */ +-static struct value *lns_atype(struct info *info, struct value *l) { +- return lns_value_of_type(info, l->lens->atype); ++static struct value *lns_atype(struct info *info, struct value **argv) { ++ return lns_value_of_type(info, argv[0]->lens->atype); + } + + /* V_LENS -> V_REGEXP */ +-static struct value *lns_vtype(struct info *info, struct value *l) { +- return lns_value_of_type(info, l->lens->vtype); ++static struct value *lns_vtype(struct info *info, struct value **argv) { ++ return lns_value_of_type(info, argv[0]->lens->vtype); + } + + /* V_LENS -> V_REGEXP */ +-static struct value *lns_ktype(struct info *info, struct value *l) { +- return lns_value_of_type(info, l->lens->ktype); ++static struct value *lns_ktype(struct info *info, struct value **argv) { ++ return lns_value_of_type(info, argv[0]->lens->ktype); + } + + /* V_LENS -> V_STRING */ +-static struct value *lns_fmt_atype(struct info *info, struct value *l) { ++static struct value *lns_fmt_atype(struct info *info, struct value **argv) { ++ struct value *l = argv[0]; ++ + struct value *result = NULL; + char *s = NULL; + int r; +@@ -549,8 +598,10 @@ static struct value *lns_fmt_atype(struct info *info, struct value *l) { + } + + /* V_REGEXP -> V_STRING -> V_STRING */ +-static struct value *rx_match(struct info *info, +- struct value *rx, struct value *s) { ++static struct value *rx_match(struct info *info, struct value **argv) { ++ struct value *rx = argv[0]; ++ struct value *s = argv[1]; ++ + struct value *result = NULL; + const char *str = s->string->str; + struct re_registers regs; +diff --git a/src/syntax.c b/src/syntax.c +index 612544c7..d26babcc 100644 +--- a/src/syntax.c ++++ b/src/syntax.c +@@ -1023,42 +1023,16 @@ typedef struct value *(*impl5)(struct info *, struct value *, struct value *, + + static struct value *native_call(struct info *info, + struct native *func, struct ctx *ctx) { +- struct value *argv[func->argc]; ++ struct value *argv[func->argc + 1]; + struct binding *b = ctx->local; +- struct value *result; + + for (int i = func->argc - 1; i >= 0; i--) { + argv[i] = b->value; + b = b->next; + } ++ argv[func->argc] = NULL; + +- switch(func->argc) { +- case 0: +- result = ((impl0) *func->impl)(info); +- break; +- case 1: +- result = ((impl1) *func->impl)(info, argv[0]); +- break; +- case 2: +- result = ((impl2) *func->impl)(info, argv[0], argv[1]); +- break; +- case 3: +- result = ((impl3) *func->impl)(info, argv[0], argv[1], argv[2]); +- break; +- case 4: +- result = ((impl4) *func->impl)(info, argv[0], argv[1], argv[2], argv[3]); +- break; +- case 5: +- result = ((impl5) *func->impl)(info, argv[0], argv[1], argv[2], argv[3], +- argv[4]); +- break; +- default: +- assert(0); +- abort(); +- break; +- } +- +- return result; ++ return func->impl(info, argv); + } + + static void type_error1(struct info *info, const char *msg, struct type *type) { +@@ -1857,7 +1831,7 @@ make_native_info(struct error *error, const char *fname, int line) { + int define_native_intl(const char *file, int line, + struct error *error, + struct module *module, const char *name, +- int argc, void *impl, ...) { ++ int argc, func_impl impl, ...) { + assert(argc > 0); /* We have no unit type */ + assert(argc <= 5); + va_list ap; +diff --git a/src/syntax.h b/src/syntax.h +index 12c3bae4..30aefe58 100644 +--- a/src/syntax.h ++++ b/src/syntax.h +@@ -112,10 +112,17 @@ struct param { + struct type *type; + }; + ++/* The protoype for the implementation of a native/builtin function in the ++ * interpreter. ++ * ++ * The arguments are passed as a NULL-terminated array of values. ++ */ ++typedef struct value *(*func_impl)(struct info *, struct value *argv[]); ++ + struct native { + unsigned int argc; + struct type *type; +- struct value *(*impl)(void); ++ func_impl impl; + }; + + /* An exception in the interpreter. Some exceptions are reported directly +@@ -270,7 +277,7 @@ ATTRIBUTE_RETURN_CHECK + int define_native_intl(const char *fname, int line, + struct error *error, + struct module *module, const char *name, +- int argc, void *impl, ...); ++ int argc, func_impl impl, ...); + + struct module *builtin_init(struct error *); + +-- +2.17.2 + diff --git a/SOURCES/0003-src-augeas.c-aug_source-actually-return-the-source-f.patch b/SOURCES/0003-src-augeas.c-aug_source-actually-return-the-source-f.patch new file mode 100644 index 0000000..c4bed1d --- /dev/null +++ b/SOURCES/0003-src-augeas.c-aug_source-actually-return-the-source-f.patch @@ -0,0 +1,27 @@ +From 47ec34301b9a797e9a6cb8b24adf9fc7fb3bbbd3 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Mon, 29 Jan 2018 14:03:36 +0100 +Subject: [PATCH] * src/augeas.c (aug_source): actually return the source for + the node + +(cherry picked from commit 70481d8e09af372f168a38755ae3173df1fe43d9) +--- + src/augeas.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/augeas.c b/src/augeas.c +index 8ec264cf..df760f50 100644 +--- a/src/augeas.c ++++ b/src/augeas.c +@@ -1958,7 +1958,7 @@ int aug_source(const augeas *aug, const char *path, char **file_path) { + ERR_THROW(r == 0, aug, AUG_ENOMATCH, "There is no node matching %s", + path); + +- tree_source(aug, match); ++ *file_path = tree_source(aug, match); + ERR_BAIL(aug); + + result = 0; +-- +2.17.2 + diff --git a/SOURCES/0004-tests-test-api.c-add-a-check-for-aug_source.patch b/SOURCES/0004-tests-test-api.c-add-a-check-for-aug_source.patch new file mode 100644 index 0000000..5f5f746 --- /dev/null +++ b/SOURCES/0004-tests-test-api.c-add-a-check-for-aug_source.patch @@ -0,0 +1,81 @@ +From 8686eeeea05de0c5a3aeccfa7560b7668635b99e Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Mon, 11 Jun 2018 12:20:31 -0700 +Subject: [PATCH] * tests/test-api.c: add a check for aug_source + +(cherry picked from commit 74e2f6c74e2e910034339dcda2d46c9aa3f83776) +--- + src/augeas.h | 2 ++ + tests/test-api.c | 36 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/src/augeas.h b/src/augeas.h +index d6a1a707..a8770790 100644 +--- a/src/augeas.h ++++ b/src/augeas.h +@@ -403,6 +403,8 @@ int aug_print(const augeas *aug, FILE *out, const char *path); + * contain the path to the toplevel node of that file underneath /files. If + * it does not, *FILE_PATH will be NULL. + * ++ * The caller is responsible for freeing *FILE_PATH ++ * + * Returns: + * 0 on success, or a negative value on failure. It is an error if PATH + * matches more than one node. +diff --git a/tests/test-api.c b/tests/test-api.c +index fda8ab6a..6460d7ba 100644 +--- a/tests/test-api.c ++++ b/tests/test-api.c +@@ -816,6 +816,41 @@ static void testAugNs(CuTest *tc) { + aug_close(aug); + } + ++/* Test aug_source */ ++static void testAugSource(CuTest *tc) { ++ struct augeas *aug; ++ int r; ++ char *s; ++ ++ aug = aug_init(root, loadpath, AUG_NO_STDINC|AUG_NO_LOAD); ++ CuAssertPtrNotNull(tc, aug); ++ CuAssertIntEquals(tc, AUG_NOERROR, aug_error(aug)); ++ ++ r = aug_load_file(aug, "/etc/hosts"); ++ CuAssertIntEquals(tc, 0, r); ++ ++ r = aug_source(aug, "/files/etc/hosts/1", &s); ++ CuAssertIntEquals(tc, 0, r); ++ CuAssertStrEquals(tc, "/files/etc/hosts", s); ++ free(s); ++ ++ r = aug_source(aug, "/files/etc/fstab", &s); ++ CuAssertIntEquals(tc, -1, r); ++ CuAssertIntEquals(tc, AUG_ENOMATCH, aug_error(aug)); ++ CuAssertPtrEquals(tc, NULL, s); ++ ++ r = aug_source(aug, "/files[", &s); ++ CuAssertIntEquals(tc, -1, r); ++ CuAssertIntEquals(tc, AUG_EPATHX, aug_error(aug)); ++ CuAssertPtrEquals(tc, NULL, s); ++ ++ r = aug_source(aug, "/files/etc/hosts/*", &s); ++ CuAssertIntEquals(tc, -1, r); ++ CuAssertIntEquals(tc, AUG_EMMATCH, aug_error(aug)); ++ CuAssertPtrEquals(tc, NULL, s); ++ ++} ++ + int main(void) { + char *output = NULL; + CuSuite* suite = CuSuiteNew(); +@@ -840,6 +875,7 @@ int main(void) { + SUITE_ADD_TEST(suite, testLoadBadPath); + SUITE_ADD_TEST(suite, testLoadBadLens); + SUITE_ADD_TEST(suite, testAugNs); ++ SUITE_ADD_TEST(suite, testAugSource); + + abs_top_srcdir = getenv("abs_top_srcdir"); + if (abs_top_srcdir == NULL) +-- +2.17.2 + diff --git a/SOURCES/0005-src-augtool.c-fix-access-to-invalid-memory.patch b/SOURCES/0005-src-augtool.c-fix-access-to-invalid-memory.patch new file mode 100644 index 0000000..47423d5 --- /dev/null +++ b/SOURCES/0005-src-augtool.c-fix-access-to-invalid-memory.patch @@ -0,0 +1,47 @@ +From 78c87b3f3b359fac5401f81a86dd9e2f5968220e Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 19 Jul 2018 15:43:21 +0200 +Subject: [PATCH] * src/augtool.c: fix access to invalid memory + +When stripping the context from the result, readline_path_generator used +to realloc the string to a shorter size, copying only the content after +the prefix. This resulted in reading with strcpy from the previous +memory, which is freed already. Avoid the issue, and simplify the code +by using strdup, freeing the old string. + +This issue could be reproduced in augtool, trying to autocomplete files +without the /files prefix, e.g.: + augtool> ls + +(cherry picked from commit 05b5784b2029f198ea486738d33fb7b49ef23eb8) +--- + src/augtool.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/augtool.c b/src/augtool.c +index ff097bd9..2745812c 100644 +--- a/src/augtool.c ++++ b/src/augtool.c +@@ -153,15 +153,13 @@ static char *readline_path_generator(const char *text, int state) { + + /* strip off context if the user didn't give it */ + if (ctx != NULL) { +- char *c = realloc(child, strlen(child)-strlen(ctx)+1); +- if (c == NULL) { +- free(child); +- return NULL; +- } + int ctxidx = strlen(ctx); + if (child[ctxidx] == SEP) + ctxidx++; +- strcpy(c, &child[ctxidx]); ++ char *c = strdup(&child[ctxidx]); ++ free(child); ++ if (c == NULL) ++ return NULL; + child = c; + } + +-- +2.17.2 + diff --git a/SOURCES/0006-src-fa.c-fa_dot_debug-check-result-of-fopen.patch b/SOURCES/0006-src-fa.c-fa_dot_debug-check-result-of-fopen.patch new file mode 100644 index 0000000..583616f --- /dev/null +++ b/SOURCES/0006-src-fa.c-fa_dot_debug-check-result-of-fopen.patch @@ -0,0 +1,32 @@ +From dfbd54466e83b8c545da931db73f6c0ac73ae136 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 19 Jul 2018 16:55:58 +0200 +Subject: [PATCH] * src/fa.c (fa_dot_debug): check result of fopen + +Return earlier if fopen fails, otherwise fa_dot will dereference a null +pointer. + +(cherry picked from commit 2fd3692404cd4290f106bc6886e6cba949452fa0) +--- + src/fa.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/fa.c b/src/fa.c +index 412d1394..8e1d7d47 100644 +--- a/src/fa.c ++++ b/src/fa.c +@@ -286,6 +286,11 @@ static void fa_dot_debug(struct fa *fa, const char *tag) { + return; + + fp = fopen(fname, "w"); ++ if (fp == NULL) { ++ free(fname); ++ return; ++ } ++ + fa_dot(fp, fa); + fclose(fp); + free(fname); +-- +2.17.2 + diff --git a/SOURCES/0007-src-jmt.c-add_lens-fix-memory-leak-w-debugging.patch b/SOURCES/0007-src-jmt.c-add_lens-fix-memory-leak-w-debugging.patch new file mode 100644 index 0000000..ec5d997 --- /dev/null +++ b/SOURCES/0007-src-jmt.c-add_lens-fix-memory-leak-w-debugging.patch @@ -0,0 +1,44 @@ +From d2822e9faffdffc44ab6d8418c13b63a65e20338 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 20 Jul 2018 14:08:50 +0200 +Subject: [PATCH] * src/jmt.c (add_lens): fix memory leak w/ debugging + +format_lens returns a new string every time, so save its result, and +free it properly after use. + +(cherry picked from commit 4310fcc41c6f870da71d07423d6ac64ea6a60998) +--- + src/jmt.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/jmt.c b/src/jmt.c +index 79953da1..86179eed 100644 +--- a/src/jmt.c ++++ b/src/jmt.c +@@ -1109,16 +1109,20 @@ static ind_t add_lens(struct jmt *jmt, struct lens *lens) { + + if (debugging("cf.jmt")) { + if (sA == NULL) { ++ char *s = format_lens(lens); + printf("add_lens: "); + print_regexp(stdout, lens->ctype); +- printf(" %s\n", format_lens(lens)); ++ printf(" %s\n", s); ++ free(s); + } else { ++ char *s = format_lens(lens); + printf("add_lens: "); + flens(stdout, l); +- printf(" %u %s\n", sA->num, format_lens(lens)); ++ printf(" %u %s\n", sA->num, s); + if (nullable) { +- printf("add_lens: // %s\n", format_lens(lens)); ++ printf("add_lens: // %s\n", s); + } ++ free(s); + } + } + +-- +2.17.2 + diff --git a/SOURCES/0008-src-pathx.c-parse_location_path-fix-memleak-on-error.patch b/SOURCES/0008-src-pathx.c-parse_location_path-fix-memleak-on-error.patch new file mode 100644 index 0000000..3cea428 --- /dev/null +++ b/SOURCES/0008-src-pathx.c-parse_location_path-fix-memleak-on-error.patch @@ -0,0 +1,29 @@ +From 095005bc98e28df6abcbb75dccfbbfa59d7b440d Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 20 Jul 2018 16:25:33 +0200 +Subject: [PATCH] * src/pathx.c (parse_location_path): fix memleak on error + +If parse_relative_location_path fails, then the early return will leak +locpath. Use the common error handling to cleanup all the resources. + +(cherry picked from commit b8dc554919827d70a6d24b054da463254164dca2) +--- + src/pathx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/pathx.c b/src/pathx.c +index 48c8b0b1..bd0fe2e3 100644 +--- a/src/pathx.c ++++ b/src/pathx.c +@@ -1971,7 +1971,7 @@ static void parse_location_path(struct state *state) { + state->pos += 1; + locpath = parse_relative_location_path(state); + if (HAS_ERROR(state)) +- return; ++ goto error; + struct step *step = make_step(DESCENDANT_OR_SELF, state); + if (HAS_ERROR(state)) + goto error; +-- +2.17.2 + diff --git a/SOURCES/0009-src-syntax.c-interpreter_init-fix-memleak-on-load_mo.patch b/SOURCES/0009-src-syntax.c-interpreter_init-fix-memleak-on-load_mo.patch new file mode 100644 index 0000000..35d65c2 --- /dev/null +++ b/SOURCES/0009-src-syntax.c-interpreter_init-fix-memleak-on-load_mo.patch @@ -0,0 +1,43 @@ +From 7d296f655e21e0e6866e783c534fee4629bc7a38 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 20 Jul 2018 16:30:26 +0200 +Subject: [PATCH] * src/syntax.c (interpreter_init): fix memleak on load_module + fail + +If load_module fails, then name is not freed. Instead, store the +return value of load_module separately, cleanup name, and then check +that value. + +(cherry picked from commit d5a6da8a8e302b8bf1fe35ae0bdd0433e522ddf2) +--- + src/syntax.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/syntax.c b/src/syntax.c +index d26babcc..f9f2849e 100644 +--- a/src/syntax.c ++++ b/src/syntax.c +@@ -2060,6 +2060,7 @@ int interpreter_init(struct augeas *aug) { + + for (int i=0; i < globbuf.gl_pathc; i++) { + char *name, *p, *q; ++ int res; + p = strrchr(globbuf.gl_pathv[i], SEP); + if (p == NULL) + p = globbuf.gl_pathv[i]; +@@ -2068,9 +2069,10 @@ int interpreter_init(struct augeas *aug) { + q = strchr(p, '.'); + name = strndup(p, q - p); + name[0] = toupper(name[0]); +- if (load_module(aug, name) == -1) +- goto error; ++ res = load_module(aug, name); + free(name); ++ if (res == -1) ++ goto error; + } + globfree(&globbuf); + return 0; +-- +2.17.2 + diff --git a/SOURCES/0010-src-transform.c-transform_save-fix-leaks-on-fchmod-f.patch b/SOURCES/0010-src-transform.c-transform_save-fix-leaks-on-fchmod-f.patch new file mode 100644 index 0000000..eccbf2f --- /dev/null +++ b/SOURCES/0010-src-transform.c-transform_save-fix-leaks-on-fchmod-f.patch @@ -0,0 +1,29 @@ +From 93c4dc92dfbc5fbca8fbda96dc68172430b7095e Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 20 Jul 2018 16:32:44 +0200 +Subject: [PATCH] * src/transform.c (transform_save): fix leaks on fchmod fail + +If fchmod fails, the early return prevents any cleanup of the function +resources, e.g. the open FILEs. Use the common error handling instead. + +(cherry picked from commit 4d1a3f3cd8d97f852c6e7c50942255d535ad1405) +--- + src/transform.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/transform.c b/src/transform.c +index 6a0ce858..176482b9 100644 +--- a/src/transform.c ++++ b/src/transform.c +@@ -1258,7 +1258,7 @@ int transform_save(struct augeas *aug, struct tree *xfm, + + if (fchmod(fileno(fp), 0666 & ~curumsk) < 0) { + err_status = "create_chmod"; +- return -1; ++ goto done; + } + } + +-- +2.17.2 + diff --git a/SOURCES/0011-src-augparse.c-main-call-aug_close-even-on-failure.patch b/SOURCES/0011-src-augparse.c-main-call-aug_close-even-on-failure.patch new file mode 100644 index 0000000..e15144b --- /dev/null +++ b/SOURCES/0011-src-augparse.c-main-call-aug_close-even-on-failure.patch @@ -0,0 +1,28 @@ +From 7ae515ec6182fe2e4e834444eadefac0d4ac5fbd Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 20 Jul 2018 16:34:40 +0200 +Subject: [PATCH] * src/augparse.c (main): call aug_close even on failure + +Even if the resources will be freed at the exit, manually call aug_close +to make sure that analyzers/checkers see only the real issues. + +(cherry picked from commit c1f99b22810526f674f38c4faee647bcf061e4e3) +--- + src/augparse.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/augparse.c b/src/augparse.c +index 96a686c8..ad2342ac 100644 +--- a/src/augparse.c ++++ b/src/augparse.c +@@ -140,6 +140,7 @@ int main(int argc, char **argv) { + if (s != NULL) { + fprintf(stderr, "%s\n", s); + } ++ aug_close(aug); + exit(EXIT_FAILURE); + } + +-- +2.17.2 + diff --git a/SOURCES/0012-Grub-tolerate-some-invalid-entries.patch b/SOURCES/0012-Grub-tolerate-some-invalid-entries.patch new file mode 100644 index 0000000..2e4b880 --- /dev/null +++ b/SOURCES/0012-Grub-tolerate-some-invalid-entries.patch @@ -0,0 +1,159 @@ +From ae4e64c5bba611f6c1e2714aa834f365996f42f6 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Mon, 4 Jun 2018 10:45:19 -0700 +Subject: [PATCH] Grub: tolerate some invalid entries + +Refusing to parse an entire file because of invalid entries is too +harsh. Try to make the behavior a little friendlier by simply mapping invalid +entries to '#error' nodes but still parsing the rest of the file. + +Also remove del_to_eol, that would delete anything up to eol; it was only +used in kw_pres, but should have never been used there. kw_pres should only +match the keyword and eol. A line like 'quiet foo bar baz' should not be +accepted by (kw_pres "quiet"). +--- + lenses/grub.aug | 58 ++++++++++++++++++++++++++++++++------ + lenses/tests/test_grub.aug | 25 ++++++++++++++++ + 2 files changed, 75 insertions(+), 8 deletions(-) + +diff --git a/lenses/grub.aug b/lenses/grub.aug +index 06f9e79f..24ad39bc 100644 +--- a/lenses/grub.aug ++++ b/lenses/grub.aug +@@ -29,9 +29,6 @@ module Grub = + (* View: eol *) + let eol = Util.eol + +- (* View: del_to_eol *) +- let del_to_eol = del /[^ \t\n]*/ "" +- + (* View: spc *) + let spc = Util.del_ws_spc + +@@ -92,7 +89,22 @@ module Grub = + eol ] + + (* View: kw_pres *) +- let kw_pres (kw:string) = [ opt_ws . key kw . del_to_eol . eol ] ++ let kw_pres (kw:string) = [ opt_ws . key kw . eol ] ++ ++ (* View: error ++ * Parse a line that looks almost like a valid setting, but isn't, ++ * into an '#error' node. Any line that starts with letters, but not ++ * anything matching kw, is considered an error line. ++ * ++ * Parameters: ++ * kw:regexp - the valid keywords that are _not_ considered an ++ * error ++ *) ++ let error (kw:regexp) = ++ let not_kw = /[a-zA-Z]+/ - kw in ++ [ label "#error" . Util.del_opt_ws "\t" ++ . store (not_kw . /([^a-zA-Z\n].*[^ \t\n])?/) . eol ] ++ + + (************************************************************************ + * Group: BOOT ENTRIES +@@ -138,8 +150,8 @@ module Grub = + spc . [ label "from" . store Rx.no_spaces ] )? . + eol ] + +- (* View: menu_setting *) +- let menu_setting = kw_menu_arg "default" ++ (* View: menu_entry *) ++ let menu_entry = kw_menu_arg "default" + | kw_menu_arg "fallback" + | kw_pres "hiddenmenu" + | kw_menu_arg "timeout" +@@ -156,6 +168,21 @@ module Grub = + | device + | setkey + ++ (* View: menu_error ++ * Accept lines not matching menu_entry and stuff them into ++ * '#error' nodes ++ *) ++ let menu_error = ++ let kw = /default|fallback|hiddenmenu|timeout|splashimage|gfxmenu/ ++ |/foreground|background|verbose|boot|password|title/ ++ |/serial|setkey|terminal|color|device/ in ++ error kw ++ ++ (* View: menu_setting ++ * a valid menu setting or a line that looks like one but is an #error ++ *) ++ let menu_setting = menu_entry | menu_error ++ + (* View: title *) + let title = del /title[ \t=]+/ "title " . value_to_eol . eol + +@@ -206,9 +233,9 @@ module Grub = + let configfile = + [ command "configfile" "\t" . spc . store Rx.no_spaces . eol ] + +- (* View: boot_setting ++ (* View: boot_entry + entries *) +- let boot_setting = ++ let boot_entry = + let boot_arg_re = "root" | "initrd" | "rootnoverify" | "uuid" + | "findroot" | "bootfs" (* Solaris extensions *) + in kw_boot_arg boot_arg_re +@@ -223,6 +250,21 @@ module Grub = + | kw_pres "makeactive" + | password_arg + ++ (* View: boot_error ++ * Accept lines not matching boot_entry and stuff them into ++ * '#error' nodes ++ *) ++ let boot_error = ++ let kw = /lock|uuid|password|root|initrd|rootnoverify|findroot|bootfs/ ++ |/configfile|chainloader|title|boot|quiet|kernel|module/ ++ |/makeactive|savedefault|map/ in ++ error kw ++ ++ (* View: boot_setting ++ * a valid boot setting or a line that looks like one but is an #error ++ *) ++ let boot_setting = boot_entry | boot_error ++ + (* View: boot *) + let boot = + let line = ((boot_setting|comment)* . boot_setting)? in +diff --git a/lenses/tests/test_grub.aug b/lenses/tests/test_grub.aug +index 8a0d9f4a..75657203 100644 +--- a/lenses/tests/test_grub.aug ++++ b/lenses/tests/test_grub.aug +@@ -257,3 +257,28 @@ password --encrypted ^9^32kwzzX./3WISQ0C /boot/grub/custom.lst + { "password" = "secret" + { "md5" } + } } ++ ++ (* Test parsing of invalid entries via menu_error *) ++ test Grub.lns get "default=0\ncrud=no\n" = ++ { "default" = "0" } ++ { "#error" = "crud=no" } ++ ++ (* We handle some pretty bizarre bad syntax *) ++ test Grub.lns get "default=0 ++crud no ++valid:nope ++nonsense = yes ++bad arg1 arg2 arg3=v\n" = ++ { "default" = "0" } ++ { "#error" = "crud no" } ++ { "#error" = "valid:nope" } ++ { "#error" = "nonsense = yes" } ++ { "#error" = "bad arg1 arg2 arg3=v" } ++ ++ (* Test parsing of invalid entries via boot_error *) ++ test Grub.lns get "title test ++ root (hd0,0) ++ crud foo\n" = ++ { "title" = "test" ++ { "root" = "(hd0,0)" } ++ { "#error" = "crud foo" } } +-- +2.17.2 + diff --git a/SOURCES/0013-Fix-sudoers-lens-always_query_group_plugin-588.patch b/SOURCES/0013-Fix-sudoers-lens-always_query_group_plugin-588.patch new file mode 100644 index 0000000..b7a9c5d --- /dev/null +++ b/SOURCES/0013-Fix-sudoers-lens-always_query_group_plugin-588.patch @@ -0,0 +1,26 @@ +From 27b453cf1413be596175e676bc88a493959f5c4e Mon Sep 17 00:00:00 2001 +From: Steve Traylen +Date: Thu, 1 Nov 2018 13:54:32 +0100 +Subject: [PATCH] Fix sudoers lens: "always_query_group_plugin" (#588) + +The option is now enabled by default in the default sudoers of +RHEL 7.6 (and probably soon CentOS 7). +--- + lenses/sudoers.aug | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lenses/sudoers.aug b/lenses/sudoers.aug +index 11920d77..043c5636 100644 +--- a/lenses/sudoers.aug ++++ b/lenses/sudoers.aug +@@ -316,6 +316,7 @@ let parameter_flag_kw = "always_set_home" | "authenticate" | "env_editor" + | "closefrom_override" | "compress_io" | "fast_glob" + | "log_input" | "log_output" | "pwfeedback" + | "umask_override" | "use_pty" | "match_group_by_gid" ++ | "always_query_group_plugin" + + let parameter_flag = [ del_negate . negate_node? + . key parameter_flag_kw ] +-- +2.17.2 + diff --git a/SOURCES/0014-Rsyslog-support-include-directive.patch b/SOURCES/0014-Rsyslog-support-include-directive.patch new file mode 100644 index 0000000..3b11f2e --- /dev/null +++ b/SOURCES/0014-Rsyslog-support-include-directive.patch @@ -0,0 +1,40 @@ +From a76a98b08de120f90a2c51fa43a86288ba6aebf8 Mon Sep 17 00:00:00 2001 +From: David Lutterkort +Date: Wed, 13 Jun 2018 19:24:38 -0700 +Subject: [PATCH] Rsyslog: support include() directive + +--- + lenses/rsyslog.aug | 2 +- + lenses/tests/test_rsyslog.aug | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/lenses/rsyslog.aug b/lenses/rsyslog.aug +index 6648f3de..35f19a5b 100644 +--- a/lenses/rsyslog.aug ++++ b/lenses/rsyslog.aug +@@ -33,7 +33,7 @@ let config_object_param = [ key /[A-Za-z.]+/ . Sep.equal . Quote.dquote + let config_sep = del /[ \t]+|[ \t]*#.*\n[ \t]*/ " " + + let config_object = +- [ key /action|global|input|module|parser|timezone/ . ++ [ key /action|global|input|module|parser|timezone|include/ . + Sep.lbracket . + config_object_param . ( config_sep . config_object_param )* . + Sep.rbracket . Util.comment_or_eol ] +diff --git a/lenses/tests/test_rsyslog.aug b/lenses/tests/test_rsyslog.aug +index b71d32c5..5386f836 100644 +--- a/lenses/tests/test_rsyslog.aug ++++ b/lenses/tests/test_rsyslog.aug +@@ -199,3 +199,9 @@ test Rsyslog.lns get "module(load=\"imuxsock\" # provides support for local s + { "SysSock.Use" = "off" } + { "#comment" = "Turn off message reception via local log socket;" } } + { "#comment" = "local messages are retrieved through imjournal now." } ++ ++(* Added in rsyslog 8.33 *) ++test Rsyslog.lns get "include(file=\"/etc/rsyslog.d/*.conf\" mode=\"optional\")\n" = ++ { "include" ++ { "file" = "/etc/rsyslog.d/*.conf" } ++ { "mode" = "optional" } } +-- +2.17.2 + diff --git a/SOURCES/0015-New-lens-Semanage-594.patch b/SOURCES/0015-New-lens-Semanage-594.patch new file mode 100644 index 0000000..f238e8c --- /dev/null +++ b/SOURCES/0015-New-lens-Semanage-594.patch @@ -0,0 +1,173 @@ +From eafe62886f8941e249d8eceaee732d3b35e19616 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 29 Nov 2018 11:22:28 +0100 +Subject: [PATCH] New lens: Semanage (#594) + +Introduce a new lens to parse /etc/selinux/semanage.conf instead of +using Simplevars: the latter cannot handle the more complex syntax of +groups introduced in newer versions of libsemanage. +--- + lenses/semanage.aug | 37 ++++++++++++++++ + lenses/simplevars.aug | 1 - + lenses/tests/test_semanage.aug | 81 ++++++++++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + 4 files changed, 119 insertions(+), 1 deletion(-) + create mode 100644 lenses/semanage.aug + create mode 100644 lenses/tests/test_semanage.aug + +diff --git a/lenses/semanage.aug b/lenses/semanage.aug +new file mode 100644 +index 00000000..46f93b32 +--- /dev/null ++++ b/lenses/semanage.aug +@@ -0,0 +1,37 @@ ++(* ++Module: Semanage ++ Parses /etc/selinux/semanage.conf ++ ++Author: ++ Pino Toscano ++ ++About: License ++ This file is licenced under the LGPL v2+, like the rest of Augeas. ++ ++About: Configuration files ++ This lens applies to /etc/selinux/semanage.conf. See . ++ ++About: Examples ++ The file contains various examples and tests. ++*) ++ ++module Semanage = ++ autoload xfm ++ ++let comment = IniFile.comment "#" "#" ++let sep = IniFile.sep "=" "=" ++let empty = IniFile.empty ++let eol = IniFile.eol ++ ++let entry = IniFile.entry IniFile.entry_re sep comment ++ | empty ++ ++let title = IniFile.title_label "@group" (IniFile.record_re - /^end$/) ++let record = [ title . entry+ . Util.del_str "[end]" . eol ] ++ ++let lns = (entry | record)* ++ ++(* Variable: filter *) ++let filter = incl "/etc/selinux/semanage.conf" ++ ++let xfm = transform lns filter +diff --git a/lenses/simplevars.aug b/lenses/simplevars.aug +index ad9795f0..6e6547cc 100644 +--- a/lenses/simplevars.aug ++++ b/lenses/simplevars.aug +@@ -46,6 +46,5 @@ let filter = incl "/etc/kernel-img.conf" + . incl "/etc/audit/auditd.conf" + . incl "/etc/mixerctl.conf" + . incl "/etc/wsconsctlctl.conf" +- . incl "/etc/selinux/semanage.conf" + + let xfm = transform lns filter +diff --git a/lenses/tests/test_semanage.aug b/lenses/tests/test_semanage.aug +new file mode 100644 +index 00000000..a6ceaca0 +--- /dev/null ++++ b/lenses/tests/test_semanage.aug +@@ -0,0 +1,81 @@ ++(* ++Module: Test_Semanage ++ Provides unit tests and examples for the lens. ++*) ++ ++module Test_Semanage = ++ ++(* Variable: phony_conf *) ++let phony_conf = "# this is a comment ++ ++mykey = myvalue # eol comment ++anotherkey = another value ++" ++ ++(* Test: Semanage.lns *) ++test Semanage.lns get phony_conf = ++ { "#comment" = "this is a comment" } ++ { } ++ { "mykey" = "myvalue" ++ { "#comment" = "eol comment" } } ++ { "anotherkey" = "another value" } ++ ++(* Test: Semanage.lns ++ Quotes are OK in variables that do not begin with a quote *) ++test Semanage.lns get "UserParameter=custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'\n" = ++ { "UserParameter" = "custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'" } ++ ++(* Test: Semanage.lns ++ Support empty values *) ++test Semanage.lns get "foo =\n" = ++ { "foo" } ++ ++(* Variable: conf *) ++let conf = "module-store = direct ++module-store = \"source\" ++ ++#policy-version = 19 ++ ++expand-check=0 ++ ++usepasswd=False ++bzip-small=true ++bzip-blocksize=5 ++ignoredirs=/root ++ ++[sefcontext_compile] ++path = /usr/sbin/sefcontext_compile ++args = -r $@ ++ ++[end] ++ ++config=test ++ ++[verify module] ++test=value ++[end] ++" ++ ++(* Test: Semanage.lns *) ++test Semanage.lns get conf = ++ { "module-store" = "direct" } ++ { "module-store" = "source" } ++ { } ++ { "#comment" = "policy-version = 19" } ++ { } ++ { "expand-check" = "0" } ++ { } ++ { "usepasswd" = "False" } ++ { "bzip-small" = "true" } ++ { "bzip-blocksize" = "5" } ++ { "ignoredirs" = "/root" } ++ { } ++ { "@group" = "sefcontext_compile" ++ { "path" = "/usr/sbin/sefcontext_compile" } ++ { "args" = "-r $@" } ++ { } } ++ { } ++ { "config" = "test" } ++ { } ++ { "@group" = "verify module" ++ { "test" = "value" } } +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 8e035e91..2b87c1c7 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -186,6 +186,7 @@ lens_tests = \ + lens-rx.sh \ + lens-samba.sh \ + lens-securetty.sh \ ++ lens-semanage.sh \ + lens-services.sh \ + lens-shadow.sh \ + lens-shells.sh \ +-- +2.17.2 + diff --git a/SOURCES/0016-New-lens-Anaconda-597.patch b/SOURCES/0016-New-lens-Anaconda-597.patch new file mode 100644 index 0000000..24bd8d4 --- /dev/null +++ b/SOURCES/0016-New-lens-Anaconda-597.patch @@ -0,0 +1,186 @@ +From affbc1187de0ca5f9c0cc23ba75da7b8d09402e4 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 12 Dec 2018 13:54:06 +0100 +Subject: [PATCH] New lens: Anaconda (#597) + +Introduce a new lens to parse the INI-like `/etc/sysconfig/anaconda` instead of using `Shellvars`. +--- + lenses/anaconda.aug | 30 +++++++++++ + lenses/shellvars.aug | 1 + + lenses/tests/test_anaconda.aug | 89 +++++++++++++++++++++++++++++++ + tests/Makefile.am | 1 + + tests/root/etc/sysconfig/anaconda | 5 ++ + 5 files changed, 126 insertions(+) + create mode 100644 lenses/anaconda.aug + create mode 100644 lenses/tests/test_anaconda.aug + create mode 100644 tests/root/etc/sysconfig/anaconda + +diff --git a/lenses/anaconda.aug b/lenses/anaconda.aug +new file mode 100644 +index 00000000..8f618db2 +--- /dev/null ++++ b/lenses/anaconda.aug +@@ -0,0 +1,30 @@ ++(* ++Module: Anaconda ++ Parses Anaconda's user interaction configuration files. ++ ++Author: Pino Toscano ++ ++About: Reference ++ https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html ++ ++About: Configuration file ++ This lens applies to /etc/sysconfig/anaconda. ++ ++About: License ++ This file is licensed under the LGPL v2+, like the rest of Augeas. ++*) ++module Anaconda = ++autoload xfm ++ ++let comment = IniFile.comment "#" "#" ++let sep = IniFile.sep "=" "=" ++ ++let entry = IniFile.entry IniFile.entry_re sep comment ++let title = IniFile.title IniFile.record_re ++let record = IniFile.record title entry ++ ++let lns = IniFile.lns record comment ++ ++let filter = incl "/etc/sysconfig/anaconda" ++ ++let xfm = transform lns filter +diff --git a/lenses/shellvars.aug b/lenses/shellvars.aug +index c92d56ea..467e9643 100644 +--- a/lenses/shellvars.aug ++++ b/lenses/shellvars.aug +@@ -252,6 +252,7 @@ module Shellvars = + + let filter_sysconfig = + sc_incl "*" . ++ sc_excl "anaconda" . + sc_excl "bootloader" . + sc_excl "hw-uuid" . + sc_excl "hwconf" . +diff --git a/lenses/tests/test_anaconda.aug b/lenses/tests/test_anaconda.aug +new file mode 100644 +index 00000000..50b0ac22 +--- /dev/null ++++ b/lenses/tests/test_anaconda.aug +@@ -0,0 +1,89 @@ ++(* ++Module: Test_Anaconda ++ Provides unit tests and examples for the lens. ++ ++ - 'exampleN' snippets are taken from the documentation: ++ https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html ++ - 'installedN' snippets are taken from the resulting files after ++ a successful installation ++*) ++ ++module Test_Anaconda = ++ ++let example1 = "# comment example - before the section headers ++ ++[section_1] ++# comment example - inside section 1 ++key_a_in_section1=some_value ++key_b_in_section1=some_value ++ ++[section_2] ++# comment example - inside section 2 ++key_a_in_section2=some_value ++" ++ ++test Anaconda.lns get example1 = ++ { "#comment" = "comment example - before the section headers" } ++ { } ++ { "section_1" ++ { "#comment" = "comment example - inside section 1" } ++ { "key_a_in_section1" = "some_value" } ++ { "key_b_in_section1" = "some_value" } ++ { } ++ } ++ { "section_2" ++ { "#comment" = "comment example - inside section 2" } ++ { "key_a_in_section2" = "some_value" } ++ } ++ ++let example2 = "# this is the user interaction config file ++ ++[General] ++post_install_tools_disabled=0 ++ ++[DatetimeSpoke] ++# the date and time spoke has been visited ++visited=1 ++changed_timezone=1 ++changed_ntp=0 ++changed_timedate=1 ++ ++[KeyboardSpoke] ++# the keyboard spoke has not been visited ++visited=0 ++" ++ ++test Anaconda.lns get example2 = ++ { "#comment" = "this is the user interaction config file" } ++ { } ++ { "General" ++ { "post_install_tools_disabled" = "0" } ++ { } ++ } ++ { "DatetimeSpoke" ++ { "#comment" = "the date and time spoke has been visited" } ++ { "visited" = "1" } ++ { "changed_timezone" = "1" } ++ { "changed_ntp" = "0" } ++ { "changed_timedate" = "1" } ++ { } ++ } ++ { "KeyboardSpoke" ++ { "#comment" = "the keyboard spoke has not been visited" } ++ { "visited" = "0" } ++ } ++ ++let installed1 = "# This file has been generated by the Anaconda Installer 21.48.22.134-1 ++ ++[ProgressSpoke] ++visited = 1 ++ ++" ++ ++test Anaconda.lns get installed1 = ++ { "#comment" = "This file has been generated by the Anaconda Installer 21.48.22.134-1" } ++ { } ++ { "ProgressSpoke" ++ { "visited" = "1" } ++ { } ++ } +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 2b87c1c7..7aa1f14c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -22,6 +22,7 @@ lens_tests = \ + lens-activemq_xml.sh \ + lens-afs_cellalias.sh \ + lens-aliases.sh \ ++ lens-anaconda.sh \ + lens-anacron.sh \ + lens-approx.sh \ + lens-apt_update_manager.sh \ +diff --git a/tests/root/etc/sysconfig/anaconda b/tests/root/etc/sysconfig/anaconda +new file mode 100644 +index 00000000..73318cf6 +--- /dev/null ++++ b/tests/root/etc/sysconfig/anaconda +@@ -0,0 +1,5 @@ ++# This file has been generated by the Anaconda Installer 21.48.22.134-1 ++ ++[ProgressSpoke] ++visited = 1 ++ +-- +2.17.2 + diff --git a/SPECS/augeas.spec b/SPECS/augeas.spec new file mode 100644 index 0000000..de65c90 --- /dev/null +++ b/SPECS/augeas.spec @@ -0,0 +1,371 @@ +Name: augeas +Version: 1.10.1 +Release: 8%{?dist} +Summary: A library for changing configuration files + +Group: System Environment/Libraries +License: LGPLv2+ +URL: http://augeas.net/ +Source0: http://download.augeas.net/%{name}-%{version}.tar.gz +Patch1: 0001-Fix-several-memory-leak-in-augmatch.patch +Patch2: 0002-Use-a-safer-calling-convention-for-native-functions.patch +Patch3: 0003-src-augeas.c-aug_source-actually-return-the-source-f.patch +Patch4: 0004-tests-test-api.c-add-a-check-for-aug_source.patch +Patch5: 0005-src-augtool.c-fix-access-to-invalid-memory.patch +Patch6: 0006-src-fa.c-fa_dot_debug-check-result-of-fopen.patch +Patch7: 0007-src-jmt.c-add_lens-fix-memory-leak-w-debugging.patch +Patch8: 0008-src-pathx.c-parse_location_path-fix-memleak-on-error.patch +Patch9: 0009-src-syntax.c-interpreter_init-fix-memleak-on-load_mo.patch +Patch10: 0010-src-transform.c-transform_save-fix-leaks-on-fchmod-f.patch +Patch11: 0011-src-augparse.c-main-call-aug_close-even-on-failure.patch +Patch12: 0012-Grub-tolerate-some-invalid-entries.patch +Patch13: 0013-Fix-sudoers-lens-always_query_group_plugin-588.patch +Patch14: 0014-Rsyslog-support-include-directive.patch +Patch15: 0015-New-lens-Semanage-594.patch +Patch16: 0016-New-lens-Anaconda-597.patch + +BuildRequires: readline-devel libselinux-devel libxml2-devel +BuildRequires: autoconf, automake +Requires: %{name}-libs = %{version}-%{release} + +%description +A library for programmatically editing configuration files. Augeas parses +configuration files into a tree structure, which it exposes through its +public API. Changes made through the API are written back to the initially +read files. + +The transformation works very hard to preserve comments and formatting +details. It is controlled by ``lens'' definitions that describe the file +format and the transformation into a tree. + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name}-libs = %{version}-%{release} +Requires: pkgconfig + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%package libs +Summary: Libraries for %{name} +Group: System Environment/Libraries + +Provides: bundled(gnulib) + +%description libs +The libraries for %{name}. + +Augeas is a library for programmatically editing configuration files. It parses +configuration files into a tree structure, which it exposes through its +public API. Changes made through the API are written back to the initially +read files. + +%package static +Summary: Static libraries for %{name} +Group: Development/Libraries +Requires: %{name}-devel = %{version}-%{release} + +%description static +The %{name}-static package contains static libraries needed to produce +static builds using %{name}. + + + +%prep +%setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 + +# Patches affect Makefile.am and configure.ac, so rerun autotools. +autoreconf +autoconf + +%build +%configure \ +%ifarch riscv64 + --disable-gnulib-tests \ +%endif + --enable-static +make V=1 %{?_smp_mflags} + +%check +# Disable test-preserve.sh SELinux testing. This fails when run under mock due +# to differing SELinux labelling. +export SKIP_TEST_PRESERVE_SELINUX=1 + +make %{?_smp_mflags} check || { + echo '===== tests/test-suite.log =====' + cat tests/test-suite.log + exit 1 +} + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT INSTALL="%{__install} -p" +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' + +# The tests/ subdirectory contains lenses used only for testing, and +# so it shouldn't be packaged. +rm -r $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/dist/tests + +# In 1.9.0, the example /usr/bin/dump gets installed inadvertently +rm -f $RPM_BUILD_ROOT/usr/bin/dump + +%clean +rm -rf $RPM_BUILD_ROOT + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_bindir}/augmatch +%{_bindir}/augparse +%{_bindir}/augtool +%{_bindir}/fadot +%doc %{_mandir}/man1/* +%{_datadir}/vim/vimfiles/syntax/augeas.vim +%{_datadir}/vim/vimfiles/ftdetect/augeas.vim + +%files libs +%defattr(-,root,root,-) +# _datadir/augeas and _datadir/augeas/lenses are owned +# by filesystem. +%{_datadir}/augeas/lenses/dist +%{_libdir}/*.so.* +%doc AUTHORS COPYING NEWS + +%files devel +%defattr(-,root,root,-) +%doc +%{_includedir}/* +%{_libdir}/*.so +%{_libdir}/pkgconfig/augeas.pc + +%files static +%defattr(-,root,root,-) +%{_libdir}/libaugeas.a +%{_libdir}/libfa.a + +%changelog +* Thu Dec 13 2018 Pino Toscano - 1.10.1-8 +- Add simple tests (RHBZ#1653994) + +* Wed Dec 12 2018 Pino Toscano - 1.10.1-7 +- Anaconda: new lens (RHBZ#1657192) + +* Thu Nov 29 2018 Pino Toscano - 1.10.1-6 +- Semanage: new lens (RHBZ#1652840) +- Add "Provides: bundled(gnulib)" to augeas-libs, as it embeds gnulib + (RHBZ#1653768) + +* Fri Nov 23 2018 Pino Toscano - 1.10.1-5 +- Rsyslog: support include() directive (RHBZ#1652832) + +* Tue Nov 13 2018 Pino Toscano - 1.10.1-4 +- Grub: better handle invalid grub.conf files (RHBZ#1649262) +- Sudoers: handle "always_query_group_plugin" option (RHBZ#1649299) + +* Mon Oct 08 2018 Pino Toscano - 1.10.1-3 +- Backport some upstream commits to fix few memory leaks, and potential + memory issues (RHBZ#1602446) + +* Wed Feb 07 2018 Fedora Release Engineering - 1.10.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Jan 29 2018 David Lutterkort - 1.10.1-1 +- New upstream version 1.10.1 + +* Fri Jan 26 2018 Richard W.M. Jones - 1.10.0-1 +- New upstream version 1.10.0 (RHBZ#1538846). +- Remove upstream patch. +- New tool ‘augmatch’. + +* Tue Nov 21 2017 David Lutterkort - 1.9.0 +- New upstream version 1.9.0 (RHBZ#1482713) +- Add -static subpackage (RHBZ#1405600) + +* Thu Aug 24 2017 Richard W.M. Jones - 1.8.1-1 +- New upstream version 1.8.1. +- Fixes CVE-2017-7555 (RHBZ#1482340). + +* Wed Aug 02 2017 Fedora Release Engineering - 1.8.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.8.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Tue Mar 21 2017 Dominic Cleal - 1.8.0-1 +- Update to 1.8.0 + +* Fri Feb 10 2017 Fedora Release Engineering - 1.7.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Igor Gnatenko - 1.7.0-3 +- Rebuild for readline 7.x + +* Sat Nov 12 2016 Richard W.M. Jones - 1.7.0-2 +- riscv64: Disable gnulib tests on riscv64 architecture. + +* Wed Nov 09 2016 Dominic Cleal - 1.7.0-1 +- Update to 1.7.0 + +* Mon Aug 08 2016 Dominic Cleal - 1.6.0-1 +- Update to 1.6.0 + +* Thu May 12 2016 Dominic Cleal - 1.5.0-1 +- Update to 1.5.0 + +* Wed Feb 03 2016 Fedora Release Engineering - 1.4.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jun 17 2015 Fedora Release Engineering - 1.4.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue Jun 02 2015 Dominic Cleal - 1.4.0-1 +- Update to 1.4.0 + +* Sat Nov 08 2014 Dominic Cleal - 1.3.0-1 +- Update to 1.3.0; remove all patches + +* Fri Aug 15 2014 Fedora Release Engineering - 1.2.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 1.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Mon Mar 31 2014 Dominic Cleal - 1.2.0-2 +- Add patch for Krb5, parse braces in values (RHBZ#1079444) + +* Wed Feb 12 2014 Dominic Cleal - 1.2.0-1 +- Update to 1.2.0, add check section +- Update source URL to download.augeas.net (RHBZ#996032) + +* Sat Aug 03 2013 Fedora Release Engineering - 1.1.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Wed Jun 19 2013 David Lutterkort - 1.1.0-1 +- Update to 1.1.0; remove all patches + +* Tue Jun 18 2013 Richard W.M. Jones - 1.0.0-4 +- Fix /etc/sysconfig/network (RHBZ#904222). + +* Wed Jun 5 2013 Richard W.M. Jones - 1.0.0-3 +- Don't package lenses in tests/ subdirectory. + +* Wed Feb 13 2013 Fedora Release Engineering - 1.0.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Fri Jan 4 2013 David Lutterkort - 1.0.0-1 +- New version; remove all patches + +* Wed Jul 18 2012 Fedora Release Engineering - 0.10.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jan 10 2012 David Lutterkort - 0.10.0-3 +- Add patches for bugs 247 and 248 (JSON lens) + +* Sat Dec 3 2011 Richard W.M. Jones - 0.10.0-2 +- Add patch to resolve missing libxml2 requirement in augeas.pc. + +* Fri Dec 2 2011 David Lutterkort - 0.10.0-1 +- New version + +* Mon Jul 25 2011 David Lutterkort - 0.9.0-1 +- New version; removed patch pathx-whitespace-ea010d8 + +* Tue May 3 2011 David Lutterkort - 0.8.1-2 +- Add patch pathx-whitespace-ea010d8.patch to fix BZ 700608 + +* Fri Apr 15 2011 David Lutterkort - 0.8.1-1 +- New version + +* Wed Feb 23 2011 David Lutterkort - 0.8.0-1 +- New version + +* Mon Feb 07 2011 Fedora Release Engineering - 0.7.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Nov 22 2010 Matthew Booth - 0.7.4-1 +- Update to version 0.7.4 + +* Thu Nov 18 2010 Richard W.M. Jones - 0.7.3-2 +- Upstream patch proposed to fix GCC optimization bug (RHBZ#651992). + +* Fri Aug 6 2010 David Lutterkort - 0.7.3-1 +- Remove upstream patches + +* Tue Jun 29 2010 David Lutterkort - 0.7.2-2 +- Patches based on upstream fix for BZ 600141 + +* Tue Jun 22 2010 David Lutterkort - 0.7.2-1 +- Fix ownership of /usr/share/augeas. BZ 569393 + +* Wed Apr 21 2010 David Lutterkort - 0.7.1-1 +- New version + +* Thu Jan 14 2010 David Lutterkort - 0.7.0-1 +- Remove patch vim-ftdetect-syntax.patch. It's upstream + +* Tue Dec 15 2009 David Lutterkort - 0.6.0-2 +- Fix ftdetect file for vim + +* Mon Nov 30 2009 David Lutterkort - 0.6.0-1 +- Install vim syntax files + +* Mon Sep 14 2009 David Lutterkort - 0.5.3-1 +- Remove separate xorg.aug, included in upstream source + +* Tue Aug 25 2009 Matthew Booth - 0.5.2-3 +- Include new xorg lens from upstream + +* Fri Jul 24 2009 Fedora Release Engineering - 0.5.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 13 2009 David Lutterkort - 0.5.2-1 +- New version + +* Fri Jun 5 2009 David Lutterkort - 0.5.1-1 +- Install fadot + +* Fri Mar 27 2009 David Lutterkort - 0.5.0-2 +- fadot isn't being installed just yet + +* Tue Mar 24 2009 David Lutterkort - 0.5.0-1 +- New program /usr/bin/fadot + +* Mon Mar 9 2009 David Lutterkort - 0.4.2-1 +- New version + +* Fri Feb 27 2009 David Lutterkort - 0.4.1-1 +- New version + +* Fri Feb 6 2009 David Lutterkort - 0.4.0-1 +- New version + +* Mon Jan 26 2009 David Lutterkort - 0.3.6-1 +- New version + +* Tue Dec 23 2008 David Lutterkort - 0.3.5-1 +- New version + +* Mon Feb 25 2008 David Lutterkort - 0.0.4-1 +- Initial specfile