cdd5d04afcdd98320d172691ac1d8cdbd451c756
1 /*
2 * SysDB - src/core/error.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include "core/error.h"
29 #include "utils/strbuf.h"
31 #include <pthread.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include <stdlib.h>
39 /*
40 * private data types
41 */
43 typedef struct {
44 int prio;
45 sdb_strbuf_t *msg;
46 _Bool logged;
47 } sdb_error_ctx_t;
48 #define SDB_ERROR_INIT { -1, NULL, 1 }
50 /*
51 * private variables
52 */
54 static sdb_error_ctx_t default_error_ctx = SDB_ERROR_INIT;
56 static pthread_key_t error_ctx_key;
57 static _Bool error_ctx_key_initialized = 0;
59 /*
60 * private helper functions
61 */
63 static void
64 sdb_error_ctx_destructor(void *p)
65 {
66 sdb_error_ctx_t *ctx = p;
68 if (! ctx)
69 return;
71 sdb_strbuf_destroy(ctx->msg);
72 free(ctx);
73 } /* sdb_error_ctx_destructor */
75 static void
76 sdb_error_ctx_init(void)
77 {
78 if (error_ctx_key_initialized)
79 return;
81 pthread_key_create(&error_ctx_key, sdb_error_ctx_destructor);
82 error_ctx_key_initialized = 1;
83 } /* sdb_error_init */
85 static sdb_error_ctx_t *
86 sdb_error_ctx_create(void)
87 {
88 sdb_error_ctx_t *ctx;
90 ctx = malloc(sizeof(*ctx));
91 if (! ctx)
92 return NULL;
94 *ctx = default_error_ctx;
95 ctx->msg = sdb_strbuf_create(64);
96 if (! ctx->msg) {
97 free(ctx);
98 return NULL;
99 }
101 if (! error_ctx_key_initialized)
102 sdb_error_ctx_init();
103 pthread_setspecific(error_ctx_key, ctx);
104 return ctx;
105 } /* sdb_error_ctx_create */
107 static sdb_error_ctx_t *
108 sdb_error_get_ctx(void)
109 {
110 sdb_error_ctx_t *ctx;
112 if (! error_ctx_key_initialized)
113 sdb_error_ctx_init();
114 ctx = pthread_getspecific(error_ctx_key);
116 if (! ctx)
117 ctx = sdb_error_ctx_create();
118 if (! ctx)
119 return NULL;
120 return ctx;
121 } /* sdb_error_get_ctx */
123 static int
124 sdb_error_vprintf(const char *fmt, va_list ap)
125 {
126 sdb_error_ctx_t *ctx;
128 ctx = sdb_error_get_ctx();
129 if (! ctx)
130 return -1;
132 ctx->logged = 0;
133 return (int)sdb_strbuf_vsprintf(ctx->msg, fmt, ap);
134 } /* sdb_error_vprintf */
136 static int
137 sdb_error_vappend(const char *fmt, va_list ap)
138 {
139 sdb_error_ctx_t *ctx;
141 ctx = sdb_error_get_ctx();
142 if (! ctx)
143 return -1;
145 ctx->logged = 0;
146 return (int)sdb_strbuf_vappend(ctx->msg, fmt, ap);
147 } /* sdb_error_vappend */
149 static int
150 sdb_do_log(int prio)
151 {
152 sdb_error_ctx_t *ctx;
153 int ret;
155 ctx = sdb_error_get_ctx();
156 if (! ctx)
157 return -1;
159 if (prio >= 0)
160 ctx->prio = prio;
162 if (ctx->logged)
163 return 0;
165 ret = fprintf(stderr, "[%s] %s\n",
166 SDB_LOG_PRIO_TO_STRING(prio),
167 sdb_strbuf_string(ctx->msg));
168 ctx->logged = 1;
169 return ret;
170 } /* sdb_do_log */
172 /*
173 * public API
174 */
176 int
177 sdb_log(int prio, const char *fmt, ...)
178 {
179 va_list ap;
180 int ret;
182 va_start(ap, fmt);
183 ret = sdb_error_vprintf(fmt, ap);
184 va_end(ap);
186 if (ret > 0)
187 sdb_do_log(prio);
188 return ret;
189 } /* sdb_log */
191 int
192 sdb_error_set(const char *fmt, ...)
193 {
194 va_list ap;
195 int ret;
197 va_start(ap, fmt);
198 ret = sdb_error_vprintf(fmt, ap);
199 va_end(ap);
201 return ret;
202 } /* sdb_error_set */
204 int
205 sdb_error_append(const char *fmt, ...)
206 {
207 va_list ap;
208 int ret;
210 va_start(ap, fmt);
211 ret = sdb_error_vappend(fmt, ap);
212 va_end(ap);
214 return ret;
215 } /* sdb_error_append */
217 int
218 sdb_error_chomp(void)
219 {
220 sdb_error_ctx_t *ctx;
222 ctx = sdb_error_get_ctx();
223 if (! ctx)
224 return -1;
226 sdb_strbuf_chomp(ctx->msg);
227 return 0;
228 } /* sdb_error_chomp */
230 int
231 sdb_error_log(int prio)
232 {
233 return sdb_do_log(prio);
234 } /* sdb_error_log */
236 const char *
237 sdb_error_get(void)
238 {
239 sdb_error_ctx_t *ctx;
241 ctx = sdb_error_get_ctx();
242 if (! ctx)
243 return "success";
244 return sdb_strbuf_string(ctx->msg);
245 } /* sdb_error_get */
247 int
248 sdb_error_get_prio(void)
249 {
250 sdb_error_ctx_t *ctx;
252 ctx = sdb_error_get_ctx();
253 if (! ctx)
254 return -1;
255 return ctx->prio;
256 } /* sdb_error_get_prio */
258 char *
259 sdb_strerror(int errnum, char *strerrbuf, size_t buflen)
260 {
261 #if STRERROR_R_CHAR_P
262 {
263 char *tmp = strerror_r(errnum, strerrbuf, buflen);
264 if (*strerrbuf = '\0') {
265 if (tmp && (tmp != strerrbuf) && (*tmp != '\0'))
266 strncpy(strerrbuf, tmp, buflen);
267 else
268 snprintf(strerrbuf, buflen, "unknown error #%i "
269 "(strerror_r(3) did not return an error message)",
270 errnum);
271 }
272 }
273 #else
274 if (strerror_r(errnum, strerrbuf, buflen))
275 snprintf(strerrbuf, buflen, "unknown error #%i "
276 "(strerror_r(3) failed)", errnum);
277 #endif
279 strerrbuf[buflen - 1] = '\0';
280 return strerrbuf;
281 } /* sdb_strerror */
283 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */