00001 /* 00002 Error-checking support functions 00003 AUP2, Sec. 1.04.2 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 #include <pthread.h> 00023 00024 static void ec_mutex(bool lock) 00025 { 00026 static pthread_mutex_t ec_mtx = PTHREAD_MUTEX_INITIALIZER; 00027 int errnum; 00028 char *msg; 00029 00030 if (lock) { 00031 if ((errnum = pthread_mutex_lock(&ec_mtx)) == 0) 00032 return; 00033 } 00034 else { 00035 if ((errnum = pthread_mutex_unlock(&ec_mtx)) == 0) 00036 return; 00037 } 00038 if ((msg = strerror(errnum)) == NULL) 00039 fprintf(stderr, "Mutex error in ec_* function: %d\n", errnum); 00040 else 00041 fprintf(stderr, "Mutex error in ec_* function: %s\n", msg); 00042 exit(EXIT_FAILURE); 00043 } 00044 00045 /*[ec_atexit_fcn]*/ 00046 static void ec_atexit_fcn(void) 00047 { 00048 ec_print(); 00049 } 00050 /*[ec_node]*/ 00051 static struct ec_node { 00052 struct ec_node *ec_next; 00053 int ec_errno; 00054 EC_ERRTYPE ec_type; 00055 char *ec_context; 00056 } *ec_head, ec_node_emergency; 00057 static char ec_s_emergency[100]; 00058 00059 const bool ec_in_cleanup = false; 00060 /*[ec_push]*/ 00061 #define SEP1 " [" 00062 #define SEP2 ":" 00063 #define SEP3 "] " 00064 00065 void ec_push(const char *fcn, const char *file, int line, 00066 const char *str, int errno_arg, EC_ERRTYPE type) 00067 { 00068 struct ec_node node, *p; 00069 size_t len; 00070 static bool attexit_called = false; 00071 00072 ec_mutex(true); 00073 node.ec_errno = errno_arg; 00074 node.ec_type = type; 00075 if (str == NULL) 00076 str = ""; 00077 len = strlen(fcn) + strlen(SEP1) + strlen(file) + strlen(SEP2) + 00078 6 + strlen(SEP3) + strlen(str) + 1; 00079 node.ec_context = (char *)calloc(1, len); 00080 if (node.ec_context == NULL) { 00081 if (ec_s_emergency[0] == '\0') 00082 node.ec_context = ec_s_emergency; 00083 else 00084 node.ec_context = "?"; 00085 len = sizeof(ec_s_emergency); 00086 } 00087 if (node.ec_context != NULL) 00088 snprintf(node.ec_context, len, "%s%s%s%s%d%s%s", fcn, SEP1, 00089 file, SEP2, line, SEP3, str); 00090 p = (struct ec_node *)calloc(1, sizeof(struct ec_node)); 00091 if (p == NULL && ec_node_emergency.ec_context == NULL) 00092 p = &ec_node_emergency; /* use just once */ 00093 if (p != NULL) { 00094 node.ec_next = ec_head; 00095 ec_head = p; 00096 *ec_head = node; 00097 } 00098 if (!attexit_called) { 00099 attexit_called = true; 00100 ec_mutex(false); 00101 if (atexit(ec_atexit_fcn) != 0) { 00102 ec_push(fcn, file, line, "atexit failed", errno, EC_ERRNO); 00103 ec_print(); /* so at least the error gets shown */ 00104 } 00105 } 00106 else 00107 ec_mutex(false); 00108 } 00109 /*[ec_print]*/ 00110 void ec_print(void) 00111 { 00112 struct ec_node *e; 00113 int level = 0; 00114 00115 ec_mutex(true); 00116 for (e = ec_head; e != NULL; e = e->ec_next, level++) { 00117 char buf[200], buf2[25 + sizeof(buf)]; 00118 00119 if (e == &ec_node_emergency) 00120 fprintf(stderr, "\t*** Trace may be incomplete ***\n"); 00121 syserrmsgtype(buf, sizeof(buf), e->ec_context, 00122 e->ec_next == NULL ? e->ec_errno : 0, e->ec_type); 00123 snprintf(buf2, sizeof(buf2), "%s\t%d: %s", 00124 (level == 0? "ERROR:" : ""), level, buf); 00125 fprintf(stderr, "%s\n", buf2); 00126 logfmt(buf2); 00127 } 00128 ec_mutex(false); 00129 } 00130 /*[ec_reinit]*/ 00131 void ec_reinit(void) 00132 { 00133 struct ec_node *e, *e_next; 00134 00135 ec_mutex(true); 00136 for (e = ec_head; e != NULL; e = e_next) { 00137 e_next = e->ec_next; 00138 if (e->ec_context != ec_s_emergency) 00139 free(e->ec_context); 00140 if (e != &ec_node_emergency) 00141 free(e); 00142 } 00143 ec_head = NULL; 00144 memset(&ec_node_emergency, 0, sizeof(ec_node_emergency)); 00145 memset(&ec_s_emergency, 0, sizeof(ec_s_emergency)); 00146 ec_mutex(false); 00147 } 00148 /*[ec_warn]*/ 00149 void ec_warn(void) 00150 { 00151 fprintf(stderr, "***WARNING: Control flowed into EC_CLEANUP_BGN\n"); 00152 } 00153 /*[]*/