00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00046 static void ec_atexit_fcn(void)
00047 {
00048 ec_print();
00049 }
00050
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
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;
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();
00104 }
00105 }
00106 else
00107 ec_mutex(false);
00108 }
00109
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
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
00149 void ec_warn(void)
00150 {
00151 fprintf(stderr, "***WARNING: Control flowed into EC_CLEANUP_BGN\n");
00152 }
00153