From 80224de6c2ff870ea36ff98b491223c674e4d57a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 3 Mar 2013 15:47:12 -0600 Subject: [PATCH 1/1] Refactor error functions; make re-entrant Use strerror_r() (the "XSI-compliant" version) instead of strerror(). --- src/extract_image.c | 4 +- src/util.c | 89 ++++++++++++++++++++++++++------------------- src/util.h | 19 ++++++---- src/wimlib.h | 3 +- src/write.c | 17 ++++----- 5 files changed, 75 insertions(+), 57 deletions(-) diff --git a/src/extract_image.c b/src/extract_image.c index 0d1db2c0..c2021563 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -321,8 +321,8 @@ static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) } #endif if (errno != ENOSYS || args->num_lutimes_warnings < 10) { - /*WARNING("Failed to set timestamp on file `%s': %s",*/ - /*output_path, strerror(errno));*/ + /*WARNING_WITH_ERRNO("Failed to set timestamp on file `%s',*/ + /*output_path");*/ args->num_lutimes_warnings++; } } diff --git a/src/util.c b/src/util.c index e8e3a37b..9aad4b2c 100644 --- a/src/util.c +++ b/src/util.c @@ -21,6 +21,13 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ +#undef _GNU_SOURCE +/* Make sure the POSIX-compatible strerror_r() is declared, rather than the GNU + * version, which has a different return type. */ +#define _POSIX_C_SOURCE 200112 +#include +#define _GNU_SOURCE + #include "wimlib_internal.h" #include "endianness.h" #include "timestamp.h" @@ -28,65 +35,71 @@ #include #include #include -#include + #include /* for getpid() */ /* True if wimlib is to print an informational message when an error occurs. * This can be turned off by calling wimlib_set_print_errors(false). */ #ifdef ENABLE_ERROR_MESSAGES #include -bool __wimlib_print_errors = false; +static bool wimlib_print_errors = false; -void wimlib_error(const char *format, ...) +static void wimlib_vmsg(const char *tag, const char *format, + va_list va, bool perror) { - if (__wimlib_print_errors) { - va_list va; - int errno_save; - - va_start(va, format); - errno_save = errno; - fputs("[ERROR] ", stderr); + if (wimlib_print_errors) { + int errno_save = errno; + fflush(stdout); + fputs(tag, stderr); vfprintf(stderr, format, va); + if (perror && errno_save != 0) { + char buf[50]; + int res = strerror_r(errno_save, buf, sizeof(buf)); + if (res) { + snprintf(buf, sizeof(buf), + "unknown error (errno=%d)", errno_save); + } + fputs(buf, stderr); + } putc('\n', stderr); errno = errno_save; - va_end(va); } } +void wimlib_error(const char *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg("[ERROR] ", format, va, false); + va_end(va); +} + void wimlib_error_with_errno(const char *format, ...) { - if (__wimlib_print_errors) { - va_list va; - int errno_save; + va_list va; - va_start(va, format); - errno_save = errno; - fflush(stdout); - fputs("[ERROR] ", stderr); - vfprintf(stderr, format, va); - if (errno_save != 0) - fprintf(stderr, ": %s", strerror(errno_save)); - putc('\n', stderr); - errno = errno_save; - va_end(va); - } + va_start(va, format); + wimlib_vmsg("[ERROR] ", format, va, true); + va_end(va); } void wimlib_warning(const char *format, ...) { - if (__wimlib_print_errors) { - va_list va; - int errno_save; + va_list va; - va_start(va, format); - errno_save = errno; - fflush(stdout); - fputs("[WARNING] ", stderr); - vfprintf(stderr, format, va); - putc('\n', stderr); - errno = errno_save; - va_end(va); - } + va_start(va, format); + wimlib_vmsg("[WARNING] ", format, va, false); + va_end(va); +} + +void wimlib_warning_with_errno(const char *format, ...) +{ + va_list va; + + va_start(va, format); + wimlib_vmsg("[WARNING] ", format, va, true); + va_end(va); } #endif @@ -94,7 +107,7 @@ void wimlib_warning(const char *format, ...) WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages) { #ifdef ENABLE_ERROR_MESSAGES - __wimlib_print_errors = show_error_messages; + wimlib_print_errors = show_error_messages; return 0; #else if (show_error_messages) diff --git a/src/util.h b/src/util.h index 0979d98f..4f405666 100644 --- a/src/util.h +++ b/src/util.h @@ -86,20 +86,25 @@ typedef uint64_t u64; #define BUFFER_SIZE 4096 #ifdef ENABLE_ERROR_MESSAGES -extern bool __wimlib_print_errors; extern void wimlib_error(const char *format, ...) FORMAT(printf, 1, 2) COLD; extern void wimlib_error_with_errno(const char *format, ...) FORMAT(printf, 1, 2) COLD; extern void wimlib_warning(const char *format, ...) FORMAT(printf, 1, 2) COLD; -# define ERROR wimlib_error -# define ERROR_WITH_ERRNO wimlib_error_with_errno -# define WARNING wimlib_warning +extern void wimlib_warning_with_errno(const char *format, ...) + FORMAT(printf, 1, 2) COLD; +# define ERROR wimlib_error +# define ERROR_WITH_ERRNO wimlib_error_with_errno +# define WARNING wimlib_warning +# define WARNING_WITH_ERRNO wimlib_warning #else -# define ERROR(format, ...) -# define ERROR_WITH_ERRNO(format, ...) -# define WARNING(format, ...) +static inline FORMAT(printf, 1, 2) void +dummy_printf(const char *format, ...) { } +# define ERROR(format, ...) dummy_printf +# define ERROR_WITH_ERRNO(format, ...) dummy_printf +# define WARNING(format, ...) dummy_printf +# define WARNING_WITH_ERRNO(format, ...) dummy_printf #endif /* ENABLE_ERROR_MESSAGES */ #if defined(ENABLE_DEBUG) || defined(ENABLE_MORE_DEBUG) diff --git a/src/wimlib.h b/src/wimlib.h index 1de5d045..55289fe9 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -118,7 +118,8 @@ * * wimlib is thread-safe as long as different ::WIMStruct's are used, except for * the fact that wimlib_set_print_errors() and wimlib_set_memory_allocator() - * both apply globally. + * both apply globally, and you also must call wimlib_global_init() in the main + * thread to avoid any race conditions with one-time allocations of memory. * * To open an existing WIM, use wimlib_open_wim(). * diff --git a/src/write.c b/src/write.c index 1f471d6f..4b06146f 100644 --- a/src/write.c +++ b/src/write.c @@ -1265,8 +1265,8 @@ out_join: for (unsigned i = 0; i < num_threads; i++) { if (pthread_join(compressor_threads[i], NULL)) { - WARNING("Failed to join compressor thread %u: %s", - i, strerror(errno)); + WARNING_WITH_ERRNO("Failed to join compressor " + "thread %u", i); } } FREE(compressor_threads); @@ -1603,8 +1603,8 @@ int lock_wim(WIMStruct *w, FILE *fp) " by another process!", w->filename); ret = WIMLIB_ERR_ALREADY_LOCKED; } else { - WARNING("Failed to lock `%s': %s", - w->filename, strerror(errno)); + WARNING_WITH_ERRNO("Failed to lock `%s'", + w->filename); ret = 0; } } else { @@ -1642,8 +1642,7 @@ void close_wim_writable(WIMStruct *w) { if (w->out_fp) { if (fclose(w->out_fp) != 0) { - WARNING("Failed to close output WIM: %s", - strerror(errno)); + WARNING_WITH_ERRNO("Failed to close output WIM"); } w->out_fp = NULL; } @@ -1929,8 +1928,8 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, w->fp = fopen(w->filename, "rb"); if (w->fp == NULL) { ret = WIMLIB_ERR_REOPEN; - WARNING("Failed to re-open `%s' read-only: %s", - w->filename, strerror(errno)); + WARNING_WITH_ERRNO("Failed to re-open `%s' read-only", + w->filename); FREE(w->filename); w->filename = NULL; } @@ -1938,7 +1937,7 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, err: /* Remove temporary file. */ if (unlink(tmpfile) != 0) - WARNING("Failed to remove `%s': %s", tmpfile, strerror(errno)); + WARNING_WITH_ERRNO("Failed to remove `%s'", tmpfile); return ret; } -- 2.43.0