2ec1e693 |
1 | /* -*-c-*- |
2 | * |
e9060e7e |
3 | * $Id: err.c,v 1.2 2002/02/02 19:16:46 mdw Exp $ |
2ec1e693 |
4 | * |
5 | * Error reporting |
6 | * |
7 | * (c) 2001 Mark Wooding |
8 | */ |
9 | |
10 | /*----- Licensing notice --------------------------------------------------* |
11 | * |
12 | * This file is part of Jog: Programming for a jogging machine. |
13 | * |
14 | * Jog is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * Jog is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with Jog; if not, write to the Free Software Foundation, |
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | */ |
28 | |
2ec1e693 |
29 | /*----- Header files ------------------------------------------------------*/ |
30 | |
31 | #ifdef HAVE_CONFIG_H |
32 | # include "config.h" |
33 | #endif |
34 | |
35 | #include <errno.h> |
36 | #include <stdarg.h> |
37 | #include <stdio.h> |
38 | #include <stdlib.h> |
39 | #include <string.h> |
40 | #include <time.h> |
41 | |
42 | #include <mLib/exc.h> |
43 | #include <mLib/quis.h> |
44 | |
e9060e7e |
45 | #include "auerr.h" |
2ec1e693 |
46 | #include "err.h" |
47 | |
48 | /*----- Static variables --------------------------------------------------*/ |
49 | |
50 | static FILE *logfp = 0; |
51 | static unsigned flags = 0; |
52 | |
53 | #define f_thread 1u |
54 | |
55 | /*----- Main code ---------------------------------------------------------*/ |
56 | |
57 | /* --- @err_abort@ --- * |
58 | * |
59 | * Arguments: @int reason@ = abort reason code |
60 | * @unsigned long err@ = abort error code |
61 | * @const char *msg@ = error message |
62 | * |
63 | * Returns: Doesn't. |
64 | * |
65 | * Use: Reports a fatal error. |
66 | */ |
67 | |
68 | void err_abortv(int reason, unsigned long err, const char *msg, va_list *ap) |
69 | { |
70 | fprintf(stderr, "%s: fatal error (code %d-%lu): ", QUIS, reason, err); |
71 | vfprintf(stderr, msg, *ap); |
72 | putc('\n', stderr); |
e9060e7e |
73 | auerr_abort(reason, err); |
2ec1e693 |
74 | abort(); |
75 | } |
76 | |
77 | void err_abort(int reason, unsigned long err, const char *msg, ...) |
78 | { |
79 | va_list ap; |
80 | |
81 | va_start(ap, msg); |
82 | err_abortv(reason, err, msg, &ap); |
83 | va_end(ap); |
84 | } |
85 | |
86 | /* --- @err_init@ --- * |
87 | * |
88 | * Arguments: --- |
89 | * |
90 | * Returns: --- |
91 | * |
92 | * Use: Attempts to initialize the logging system. It is a |
93 | * catastrophic failure if logging can't start up. |
94 | */ |
95 | |
96 | static void err_exc(exc_extype ex, exc_exval v) |
97 | { |
98 | switch (ex) { |
99 | case EXC_NOMEM: |
100 | err_report(ERR_EXC, 0, ex, "out of memory"); |
101 | break; |
102 | default: |
103 | err_report(ERR_EXC, 0, ex, "uncaught mLib exception"); |
104 | break; |
105 | } |
106 | exit(EXIT_FAILURE); |
107 | } |
108 | |
109 | void err_init(void) |
110 | { |
111 | const char *lf; |
112 | |
113 | lf = getenv("JOG_LOGFILE"); |
114 | if (!lf) |
115 | logfp = stderr; |
116 | else if ((logfp = fopen(lf, "w")) == 0) { |
117 | err_abort(ERRABORT_LOGOPEN, errno, |
118 | "couldn't open logfile `%s': %s", lf, strerror(errno)); |
119 | } |
120 | exc_uncaught(err_exc); |
121 | } |
122 | |
123 | /* --- @err_report@ --- * |
124 | * |
125 | * Arguments: @int ctx@ = context code |
126 | * @int reason@ = reason code |
127 | * @unsigned long err@ = system error code |
128 | * @const char *msg@ = textual message to log |
129 | * |
130 | * Returns: --- |
131 | * |
132 | * Use: Reports an error. Doesn't abort anything unless something |
133 | * really serious happens. |
134 | */ |
135 | |
136 | void err_reportv(int ctx, int reason, unsigned long err, |
137 | const char *msg, va_list *ap) |
138 | { |
139 | char buf[256]; |
140 | time_t t; |
141 | struct tm *tm; |
142 | |
143 | if (ctx && !(flags & f_thread)) { |
144 | unsigned f = flags; |
145 | flags |= f_thread; |
e9060e7e |
146 | auerr(ctx, reason, err); |
2ec1e693 |
147 | flags = f; |
148 | } |
149 | t = time(0); |
150 | tm = localtime(&t); |
151 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); |
152 | if (fputs(buf, logfp) == EOF || |
153 | fprintf(stderr, " %s: ", QUIS) == EOF || |
154 | vfprintf(logfp, msg, *ap) == EOF || |
155 | (ctx && (fprintf(logfp, " (error %d", ctx) == EOF || |
156 | (reason && fprintf(logfp, "-%d", reason) == EOF) || |
157 | (err && fprintf(logfp, ":%lu", err) == EOF) || |
158 | putc(')', logfp) == EOF)) || |
159 | putc('\n', logfp) == EOF || |
160 | fflush(logfp) == EOF) { |
161 | err_abort(ERRABORT_LOGWRITE, errno, |
162 | "error writing logfile: %s", strerror(errno)); |
163 | } |
164 | } |
165 | |
166 | void err_report(int ctx, int reason, unsigned long err, const char *msg, ...) |
167 | { |
168 | va_list ap; |
169 | |
170 | va_start(ap, msg); |
171 | err_reportv(ctx, reason, err, msg, &ap); |
172 | va_end(ap); |
173 | } |
174 | |
175 | /* --- @err_log@ --- * |
176 | * |
177 | * Arguments: @const char *msg@ = textual message to log |
178 | * |
179 | * Returns: --- |
180 | * |
181 | * Use: Logs a message. |
182 | */ |
183 | |
184 | void err_logv(const char *msg, va_list *ap) |
185 | { |
186 | err_reportv(0, 0, 0, msg, ap); |
187 | } |
188 | |
189 | void err_log(const char *msg, ...) |
190 | { |
191 | va_list ap; |
192 | |
193 | va_start(ap, msg); |
194 | err_reportv(0, 0, 0, msg, &ap); |
195 | va_end(ap); |
196 | } |
197 | |
198 | /*----- That's all, folks -------------------------------------------------*/ |