diff options
author | Mattias Andrée <maandree@kth.se> | 2019-04-12 22:32:26 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2019-04-12 22:32:26 +0200 |
commit | 5012504d2f215002a429b14f238ebfc1d0029c05 (patch) | |
tree | 7d70dbbdef6c93da503683c30b6c6d2e90f36881 | |
parent | Add readme (diff) | |
download | liberror-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-- | README | 4 | ||||
-rw-r--r-- | copy_error.c | 35 | ||||
-rw-r--r-- | free_error.c | 37 | ||||
-rw-r--r-- | liberror.h | 57 | ||||
-rw-r--r-- | print_error.c | 61 |
5 files changed, 175 insertions, 19 deletions
@@ -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); + } } @@ -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) { |