aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2019-04-12 22:32:26 +0200
committerMattias Andrée <maandree@kth.se>2019-04-12 22:32:26 +0200
commit5012504d2f215002a429b14f238ebfc1d0029c05 (patch)
tree7d70dbbdef6c93da503683c30b6c6d2e90f36881
parentAdd readme (diff)
downloadliberror-5012504d2f215002a429b14f238ebfc1d0029c05.tar.gz
liberror-5012504d2f215002a429b14f238ebfc1d0029c05.tar.bz2
liberror-5012504d2f215002a429b14f238ebfc1d0029c05.tar.xz
Add support for extended details
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--README4
-rw-r--r--copy_error.c35
-rw-r--r--free_error.c37
-rw-r--r--liberror.h57
-rw-r--r--print_error.c61
5 files changed, 175 insertions, 19 deletions
diff --git a/README b/README
index 4d24223..e0efe29 100644
--- a/README
+++ b/README
@@ -6,8 +6,8 @@ specific, maybe multiple library, errors.
The errors are thread-local, support error description, error
source string (which function failed), and error code with
error code group (e.g. "errno", "addrinfo" or a library name),
-as well as cause chains, and if linked together with
-liberror-backtrace, backtraces.
+as well as cause chains, extended details, and if linked
+together with liberror-backtrace, backtraces.
The important functions are:
diff --git a/copy_error.c b/copy_error.c
index 8d93131..ebf71b4 100644
--- a/copy_error.c
+++ b/copy_error.c
@@ -2,6 +2,8 @@
#include "internal.h"
+#define STRDUP(S) ((S) ? strdup(S) : NULL)
+
struct liberror_error *
liberror_copy_error(struct liberror_error *src)
{
@@ -16,6 +18,7 @@ liberror_copy_error(struct liberror_error *src)
if (dest->backtrace)
dest->backtrace->refcount += 1;
dest->dynamically_allocated = 1;
+
if (src->cause) {
dest->cause = liberror_copy_error(src->cause);
if (!dest->cause) {
@@ -25,7 +28,39 @@ liberror_copy_error(struct liberror_error *src)
dest = NULL;
}
}
+
+ switch (dest->details_type) {
+ case LIBERROR_DETAILS_USER:
+ dest->details.user.data = dest->details.user.copy_data(dest->details.user.data);
+ if (!dest->details.user.data)
+ goto fail;
+ break;
+
+ case LIBERROR_DETAILS_ONE_FILE:
+ dest->details.one_file.name = STRDUP(src->details.one_file.name);
+ if (src->details.one_file.name && !dest->details.one_file.name)
+ goto fail;
+ break;
+
+ case LIBERROR_DETAILS_TWO_FILES:
+ dest->details.two_files.name1 = STRDUP(src->details.two_files.name1);
+ dest->details.two_files.name2 = STRDUP(src->details.two_files.name2);
+ if (src->details.two_files.name1 && !dest->details.two_files.name1)
+ goto fail;
+ if (src->details.two_files.name2 && !dest->details.two_files.name2)
+ goto fail;
+ break;
+
+ case LIBERROR_DETAILS_NONE:
+ default:
+ break;
+ }
}
errno = saved_errno;
return dest;
+
+fail:
+ liberror_free_error(dest);
+ errno = saved_errno;
+ return NULL;
}
diff --git a/free_error.c b/free_error.c
index a15d36c..1af0104 100644
--- a/free_error.c
+++ b/free_error.c
@@ -5,11 +5,34 @@
void
liberror_free_error(struct liberror_error *error)
{
- if (!error)
- return;
- if (error->backtrace && !--error->backtrace->refcount)
- free(error->backtrace);
- liberror_free_error(error->cause);
- if (error->dynamically_allocated)
- free(error);
+ struct liberror_error *tmp;
+ while (error) {
+ if (error->backtrace && !--error->backtrace->refcount)
+ free(error->backtrace);
+
+ switch (error->details_type) {
+ case LIBERROR_DETAILS_USER:
+ if (error->details.user.data && error->details.user.free_data)
+ error->details.user.free_data(error->details.user.data);
+ break;
+
+ case LIBERROR_DETAILS_ONE_FILE:
+ free(error->details.one_file.name);
+ break;
+
+ case LIBERROR_DETAILS_TWO_FILES:
+ free(error->details.two_files.name1);
+ free(error->details.two_files.name2);
+ break;
+
+ case LIBERROR_DETAILS_NONE:
+ default:
+ break;
+ }
+
+ tmp = error;
+ error = error->cause;
+ if (tmp->dynamically_allocated)
+ free(tmp);
+ }
}
diff --git a/liberror.h b/liberror.h
index 27c700d..508dbac 100644
--- a/liberror.h
+++ b/liberror.h
@@ -13,6 +13,53 @@
struct liberror_backtrace;
/**
+ * Value that specifies which feild in a
+ * `union liberror_details` that is used
+ */
+enum liberror_details_type {
+ LIBERROR_DETAILS_NONE,
+ LIBERROR_DETAILS_USER,
+ LIBERROR_DETAILS_ONE_FILE,
+ LIBERROR_DETAILS_TWO_FILES
+};
+
+/**
+ * Error details
+ */
+union liberror_details {
+ /**
+ * For `LIBERROR_DETAILS_USER`
+ */
+ struct {
+ const char *library;
+ void *data;
+ void (*free_data)(void *);
+ void *(*copy_data)(void *);
+ } user;
+
+ /**
+ * For `LIBERROR_DETAILS_ONE_FILE`
+ */
+ struct {
+ int fd;
+ char *name;
+ const char *role;
+ } one_file;
+
+ /**
+ * For `LIBERROR_DETAILS_TWO_FILES`
+ */
+ struct {
+ int fd1;
+ int fd2;
+ char *name1;
+ char *name2;
+ const char *role1;
+ const char *role2;
+ } two_files;
+};
+
+/**
* Error structure
*/
struct liberror_error {
@@ -63,6 +110,16 @@ struct liberror_error {
* Whether the error is physically allocated
*/
int dynamically_allocated;
+
+ /**
+ * Which value in `.details` that is used
+ */
+ enum liberror_details_type details_type;
+
+ /**
+ * Error detail
+ */
+ union liberror_details details;
};
diff --git a/print_error.c b/print_error.c
index 4675bab..245caa0 100644
--- a/print_error.c
+++ b/print_error.c
@@ -3,7 +3,7 @@
static void
-print_error_description(struct liberror_error *error, FILE *fp, const char *prefix)
+print_error(struct liberror_error *error, FILE *fp, char *prefix)
{
if (*error->description) {
if (*error->source)
@@ -15,6 +15,54 @@ print_error_description(struct liberror_error *error, FILE *fp, const char *pref
} else {
fprintf(fp, "%sError: %s error %lli\n", prefix, error->code_group, error->code);
}
+
+ *strchr(prefix, '\0') = ' ';
+
+ switch (error->details_type) {
+ case LIBERROR_DETAILS_ONE_FILE:
+ if (error->details.one_file.fd >= 0 || error->details.one_file.name) {
+ fprintf(fp, "%sDetails:\n", prefix);
+ if (error->details.one_file.name) {
+ fprintf(fp, "%s %s name: %s\n", prefix,
+ error->details.one_file.role, error->details.one_file.name);
+ }
+ if (error->details.one_file.fd >= 0) {
+ fprintf(fp, "%s %s descriptor: %i\n", prefix,
+ error->details.one_file.role, error->details.one_file.fd);
+ }
+ }
+ break;
+
+ case LIBERROR_DETAILS_TWO_FILES:
+ if (error->details.two_files.fd1 >= 0 || error->details.two_files.name1 ||
+ error->details.two_files.fd2 >= 0 || error->details.two_files.name2) {
+ fprintf(fp, "%sDetails:\n", prefix);
+ if (error->details.two_files.fd1 >= 0) {
+ fprintf(fp, "%s %s descriptor: %i\n", prefix,
+ error->details.two_files.role1, error->details.two_files.fd1);
+ }
+ if (error->details.two_files.name1) {
+ fprintf(fp, "%s %s name: %s\n", prefix,
+ error->details.two_files.role1, error->details.two_files.name1);
+ }
+ if (error->details.two_files.fd2 >= 0) {
+ fprintf(fp, "%s %s descriptor: %i\n", prefix,
+ error->details.two_files.role2, error->details.two_files.fd2);
+ }
+ if (error->details.two_files.name2) {
+ fprintf(fp, "%s %s name: %s\n", prefix,
+ error->details.two_files.role2, error->details.two_files.name2);
+ }
+ }
+ break;
+
+ case LIBERROR_DETAILS_NONE:
+ case LIBERROR_DETAILS_USER:
+ default:
+ break;
+ }
+
+ liberror_print_backtrace(error, fp, prefix);
}
@@ -43,20 +91,13 @@ liberror_print_error(struct liberror_error *error, FILE *fp, int reset, const ch
fp = stderr;
*p = *q = '\0';
- print_error_description(err, fp, prefix);
-
- *p = ' ';
- liberror_print_backtrace(err, fp, prefix);
+ print_error(err, fp, prefix);
while ((err = err->cause)) {
*p = *q = '\0';
fprintf(fp, "%sCaused by:\n", prefix);
-
*p = ' ';
- print_error_description(err, fp, prefix);
-
- *q = ' ';
- liberror_print_backtrace(err, fp, prefix);
+ print_error(err, fp, prefix);
}
if (reset) {