[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