infra: Clean up project setup
[jog] / err.c
1 /* -*-c-*-
2 *
3 * $Id: err.c,v 1.2 2002/02/02 19:16:46 mdw Exp $
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
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
45 #include "auerr.h"
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);
73 auerr_abort(reason, err);
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;
146 auerr(ctx, reason, err);
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 -------------------------------------------------*/