[augeas-devel] [PATCH 1/8] Error reporting API and infrastructure

David Lutterkort lutter at redhat.com
Tue Sep 22 00:48:58 UTC 2009


Only reporting errors in the tree makes the API much harder to use; the
aug_error* functions make it easier to inquire about errors
programmatically.
---
 src/augeas.c           |   30 ++++++++++++++++++++++++++++++
 src/augeas.h           |   27 +++++++++++++++++++++++++++
 src/augeas_sym.version |    8 ++++++++
 src/internal.c         |   23 +++++++++++++++++++++++
 src/internal.h         |   35 +++++++++++++++++++++++++++++++++++
 5 files changed, 123 insertions(+), 0 deletions(-)

diff --git a/src/augeas.c b/src/augeas.c
index 646ec6c..8e87a53 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -51,6 +51,13 @@ static const char *const static_nodes[][2] = {
     { AUGEAS_META_TREE "/version/defvar", NULL }
 };
 
+static const char *const errcodes[] = {
+    "No error",                                         /* AUG_NOERROR */
+    "Cannot allocate memory",                           /* AUG_ENOMEM */
+    "Internal error (please file a bug)",               /* AUG_EINTERNAL */
+    "Invalid path expression"                           /* AUG_EPATHX */
+};
+
 static void tree_mark_dirty(struct tree *tree) {
     do {
         tree->dirty = 1;
@@ -991,6 +998,7 @@ void aug_close(struct augeas *aug) {
     free((void *) aug->root);
     free(aug->modpathz);
     free_symtab(aug->symtab);
+    free(aug->error.details);
     free(aug);
 }
 
@@ -1008,6 +1016,28 @@ int tree_equal(const struct tree *t1, const struct tree *t2) {
     return t1 == t2;
 }
 
+/*
+ * Error reporting API
+ */
+int aug_error(struct augeas *aug) {
+    return aug->error.code;
+}
+
+const char *aug_error_message(struct augeas *aug) {
+    aug_errcode_t errcode = aug->error.code;
+
+    if (errcode > ARRAY_CARDINALITY(errcodes))
+        errcode = AUG_EINTERNAL;
+    return errcodes[errcode];
+}
+
+const char *aug_error_minor_message(struct augeas *aug) {
+    return aug->error.minor_details;
+}
+
+const char *aug_error_details(struct augeas *aug) {
+    return aug->error.details;
+}
 
 /*
  * Local variables:
diff --git a/src/augeas.h b/src/augeas.h
index 972ea35..7ffe678 100644
--- a/src/augeas.h
+++ b/src/augeas.h
@@ -272,6 +272,33 @@ int aug_print(const augeas *aug, FILE *out, const char *path);
  */
 void aug_close(augeas *aug);
 
+/*
+ * Error reporting
+ */
+
+typedef enum {
+    AUG_NOERROR,        /* No error */
+    AUG_ENOMEM,         /* Out of memory */
+    AUG_EINTERNAL,      /* Internal error (bug) */
+    AUG_EPATHX          /* Invalid path expression */
+} aug_errcode_t;
+
+/* Return the error code from the last API call */
+int aug_error(augeas *aug);
+
+/* Return a human-readable message for the error code */
+const char *aug_error_message(augeas *aug);
+
+/* Return a human-readable message elaborating the error code; might be
+ * NULL. For example, when the error code is AUG_EPATHX, this will explain
+ * how the path expression is invalid */
+const char *aug_error_minor_message(augeas *aug);
+
+/* Return details about the error, which might be NULL. For example, for
+ * AUG_EPATHX, indicates where in the path expression the error
+ * occurred. The returned value can only be used until the next API call
+ */
+const char *aug_error_details(augeas *aug);
 #endif
 
 
diff --git a/src/augeas_sym.version b/src/augeas_sym.version
index 0643904..0014f68 100644
--- a/src/augeas_sym.version
+++ b/src/augeas_sym.version
@@ -21,3 +21,11 @@ AUGEAS_0.8.0 {
       aug_defnode;
       aug_load;
 } AUGEAS_0.1.0;
+
+AUGEAS_0.10.0 {
+    global:
+      aug_error;
+      aug_error_message;
+      aug_error_minor_message;
+      aug_error_details;
+} AUGEAS_0.8.0;
diff --git a/src/internal.c b/src/internal.c
index 4f0b779..9d508d3 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -23,6 +23,7 @@
 #include <config.h>
 
 #include <ctype.h>
+#include <stdio.h>
 #include <stdarg.h>
 
 #include "internal.h"
@@ -389,6 +390,28 @@ int xasprintf(char **strp, const char *format, ...) {
   return result;
 }
 
+static void vreport_error(struct error *err, aug_errcode_t errcode,
+                   const char *format, va_list ap) {
+    /* We only remember the first error */
+    if (err->code != AUG_NOERROR)
+        return;
+    assert(err->details == NULL);
+
+    err->code = errcode;
+    if (format != NULL) {
+        if (vasprintf(&err->details, format, ap) < 0)
+            err->details = NULL;
+    }
+}
+
+void report_error(struct error *err, aug_errcode_t errcode,
+                  const char *format, ...) {
+    va_list ap;
+
+    va_start(ap, format);
+    vreport_error(err, errcode, format, ap);
+    va_end(ap);
+}
 /*
  * Local variables:
  *  indent-tabs-mode: nil
diff --git a/src/internal.h b/src/internal.h
index e8d5014..1e0111b 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -25,6 +25,7 @@
 
 #include "list.h"
 #include "datadir.h"
+#include "augeas.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -266,6 +267,16 @@ const char *xstrerror(int errnum, char *buf, size_t len);
 /* Like asprintf, but set *STRP to NULL on error */
 int xasprintf(char **strp, const char *format, ...);
 
+/*
+ * Error details in a separate struct that we can pass around
+ */
+struct error {
+    aug_errcode_t  code;
+    int            minor;
+    char          *details;       /* Human readable explanation */
+    const char    *minor_details; /* Human readable version of MINOR */
+};
+
 /* Struct: augeas
  * The data structure representing a connection to Augeas. */
 struct augeas {
@@ -278,8 +289,32 @@ struct augeas {
     char             *modpathz;   /* The search path for modules as a
                                      glibc argz vector */
     struct pathx_symtab *symtab;
+    struct error        error;
 };
 
+void report_error(struct error *err, aug_errcode_t errcode,
+                  const char *format, ...)
+    ATTRIBUTE_FORMAT(printf, 3, 4);
+
+#define ERR_BAIL(aug) if ((aug)->error.code != AUG_NOERROR) goto error;
+
+#define ERR_NOMEM(cond, aug)                             \
+    if (cond) {                                          \
+        report_error(&((aug)->error), AUG_ENOMEM, NULL); \
+        goto error;                                      \
+    }
+
+#define ERR_REPORT(aug, code, fmt ...)          \
+    report_error(&((aug)->error), code, ## fmt)
+
+#define ERR_THROW(cond, aug, code, fmt ...)             \
+    do {                                                \
+        if (cond) {                                     \
+            report_error(&(aug)->error, code, ## fmt);  \
+            goto error;                                 \
+        }                                               \
+    } while(0)
+
 /* Struct: tree
  * An entry in the global config tree. The data structure allows associating
  * values with interior nodes, but the API currently marks that as an error.
-- 
1.6.2.5




More information about the augeas-devel mailing list