2 * log.c Functions in the library call radlib_log() which
3 * does internal logging.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * Copyright 2000,2006 The FreeRADIUS server project
26 #include <freeradius-devel/libradius.h>
29 * Are we using glibc or a close relative?
31 #ifdef HAVE_FEATURES_H
32 # include <features.h>
35 #define FR_STRERROR_BUFSIZE (2048)
37 fr_thread_local_setup(char *, fr_strerror_buffer) /* macro */
38 fr_thread_local_setup(char *, fr_syserror_buffer) /* macro */
41 /** POSIX-2008 errno macros
43 * Non-POSIX macros may be added, but you must check they're defined.
45 char const *fr_errno_macro_names[] = {
48 [EADDRINUSE] = "EADDRINUSE",
49 [EADDRNOTAVAIL] = "EADDRNOTAVAIL",
50 [EAFNOSUPPORT] = "EAFNOSUPPORT",
51 #if EWOULDBLOCK == EAGAIN
52 [EWOULDBLOCK] = "EWOULDBLOCK or EAGAIN",
55 [EWOULDBLOCK] = "EWOULDBLOCK",
57 [EALREADY] = "EALREADY",
59 [EBADMSG] = "EBADMSG",
61 [ECANCELED] = "ECANCELED",
63 [ECONNABORTED] = "ECONNABORTED",
64 [ECONNREFUSED] = "ECONNREFUSED",
65 [ECONNRESET] = "ECONNRESET",
66 [EDEADLK] = "EDEADLK",
67 [EDESTADDRREQ] = "EDESTADDRREQ",
73 [EHOSTUNREACH] = "EHOSTUNREACH",
76 [EINPROGRESS] = "EINPROGRESS",
80 [EISCONN] = "EISCONN",
85 [EMSGSIZE] = "EMSGSIZE",
86 [EMULTIHOP] = "EMULTIHOP",
87 [ENAMETOOLONG] = "ENAMETOOLONG",
88 [ENETDOWN] = "ENETDOWN",
89 [ENETRESET] = "ENETRESET",
90 [ENETUNREACH] = "ENETUNREACH",
92 [ENOBUFS] = "ENOBUFS",
94 [ENODATA] = "ENODATA",
98 [ENOEXEC] = "ENOEXEC",
100 [ENOLINK] = "ENOLINK",
103 [ENOPROTOOPT] = "ENOPROTOOPT",
112 [ENOTCONN] = "ENOTCONN",
113 [ENOTDIR] = "ENOTDIR",
114 [ENOTEMPTY] = "ENOTEMPTY",
115 #ifdef ENOTRECOVERABLE
116 [ENOTRECOVERABLE] = "ENOTRECOVERABLE",
118 [ENOTSOCK] = "ENOTSOCK",
119 [ENOTSUP] = "ENOTSUP",
120 #if ENOTSUP != EOPNOTSUPP
121 [EOPNOTSUPP] = "EOPNOTSUPP",
125 [EOVERFLOW] = "EOVERFLOW",
127 [EOWNERDEAD] = "EOWNERDEAD",
132 [EPROTONOSUPPORT] = "EPROTONOSUPPORT",
133 [EPROTOTYPE] = "EPROTOTYPE",
142 [ETIMEDOUT] = "ETIMEDOUT",
143 [ETXTBSY] = "ETXTBSY",
149 * Explicitly cleanup the memory allocated to the error buffer,
150 * just in case valgrind complains about it.
152 static void _fr_logging_free(void *arg)
157 /** Log to thread local error buffer
159 * @param fmt printf style format string. If NULL sets the 'new' byte to false,
160 * effectively clearing the last message.
162 void fr_strerror_printf(char const *fmt, ...)
168 buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free);
173 * malloc is thread safe, talloc is not
175 buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */
177 fr_perror("Failed allocating memory for libradius error buffer");
181 ret = fr_thread_local_set(fr_strerror_buffer, buffer);
183 fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret));
190 * NULL has a special meaning, setting the new bit to false.
193 buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06;
199 * Alternate where we write the message, so we can do:
200 * fr_strerror_printf("Additional error: %s", fr_strerror());
202 switch (buffer[FR_STRERROR_BUFSIZE * 2] & 0x06) {
204 vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap);
205 buffer[FR_STRERROR_BUFSIZE * 2] = 0x05; /* Flip the 'new' bit to true */
209 vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap);
210 buffer[FR_STRERROR_BUFSIZE * 2] = 0x03; /* Flip the 'new' bit to true */
216 /** Get the last library error
218 * Will only return the last library error once, after which it will return a zero length string.
220 * @return library error or zero length string
222 char const *fr_strerror(void)
226 buffer = fr_thread_local_get(fr_strerror_buffer);
227 if (!buffer) return "";
229 switch (buffer[FR_STRERROR_BUFSIZE * 2]) {
234 buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; /* Flip the 'new' bit to false */
238 buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; /* Flip the 'new' bit to false */
239 return buffer + FR_STRERROR_BUFSIZE;
243 /** Guaranteed to be thread-safe version of strerror
245 * @param num errno as returned by function or from global errno.
246 * @return local specific error string relating to errno.
248 char const *fr_syserror(int num)
250 char *buffer, *p, *end;
253 buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
256 * malloc is thread safe, talloc is not
258 buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE);
260 fr_perror("Failed allocating memory for system error buffer");
264 ret = fr_thread_local_set(fr_syserror_buffer, buffer);
266 fr_perror("Failed setting up TLS for system error buffer: %s", fr_syserror(ret));
272 if (!num) return "No error";
275 end = p + FR_STRERROR_BUFSIZE;
279 * Prefix system errors with the macro name and number
280 * if we're debugging.
282 if (num < (int)(sizeof(fr_errno_macro_names) / sizeof(*fr_errno_macro_names))) {
283 p += snprintf(p, end - p, "%s: ", fr_errno_macro_names[num]);
285 p += snprintf(p, end - p, "errno %i: ", num);
287 if (p >= end) return p;
291 * XSI-Compliant version
293 #if !defined(HAVE_FEATURES_H) || !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE)
294 ret = strerror_r(num, p, end - p);
297 fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), "
298 "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret));
304 * GNU Specific version
306 * The GNU Specific version returns a char pointer. That pointer may point
307 * the buffer you just passed in, or to an immutable static string.
311 p = strerror_r(num, p, end - p);
314 fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p "
315 "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno));
327 void fr_perror(char const *fmt, ...)
333 vfprintf(stderr, fmt, ap);
335 error = fr_strerror();
336 if (error && (error[0] != '\0')) {
337 fprintf(stderr, ": %s\n", error);