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 */
42 * Explicitly cleanup the memory allocated to the error buffer,
43 * just in case valgrind complains about it.
45 static void _fr_logging_free(void *arg)
50 /** Log to thread local error buffer
52 * @param fmt printf style format string. If NULL sets the 'new' byte to false,
53 * effectively clearing the last message.
55 void fr_strerror_printf(char const *fmt, ...)
61 buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free);
66 * malloc is thread safe, talloc is not
68 buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */
70 fr_perror("Failed allocating memory for libradius error buffer");
74 ret = fr_thread_local_set(fr_strerror_buffer, buffer);
76 fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret));
83 * NULL has a special meaning, setting the new byte to false.
86 buffer[FR_STRERROR_BUFSIZE * 2] = '\0';
92 * Alternate where we write the message, so we can do:
93 * fr_strerror_printf("Additional error: %s", fr_strerror());
95 switch (buffer[FR_STRERROR_BUFSIZE * 2]) {
97 vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap);
98 buffer[FR_STRERROR_BUFSIZE * 2] = '\2'; /* Flip the 'new' byte to true */
102 vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap);
103 buffer[FR_STRERROR_BUFSIZE * 2] = '\1'; /* Flip the 'new' byte to true */
109 /** Get the last library error
111 * Will only return the last library error once, after which it will return a zero length string.
113 * @return library error or zero length string
115 char const *fr_strerror(void)
119 buffer = fr_thread_local_get(fr_strerror_buffer);
120 if (!buffer) return "";
122 switch (buffer[FR_STRERROR_BUFSIZE * 2]) {
127 buffer[FR_STRERROR_BUFSIZE * 2] = '\0'; /* Flip the 'new' byte to false */
131 buffer[FR_STRERROR_BUFSIZE * 2] = '\0'; /* Flip the 'new' byte to false */
132 return buffer + FR_STRERROR_BUFSIZE;
136 /** Guaranteed to be thread-safe version of strerror
138 * @param num errno as returned by function or from global errno.
139 * @return local specific error string relating to errno.
141 char const *fr_syserror(int num)
146 buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
149 * malloc is thread safe, talloc is not
151 buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE);
153 fr_perror("Failed allocating memory for system error buffer");
157 ret = fr_thread_local_set(fr_syserror_buffer, buffer);
159 fr_perror("Failed setting up TLS for system error buffer: %s", fr_syserror(ret));
170 * XSI-Compliant version
172 #if !defined(HAVE_FEATURES_H) || !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE)
173 if ((ret = strerror_r(num, buffer, (size_t)FR_STRERROR_BUFSIZE) != 0)) {
175 fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), "
176 "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret));
182 * GNU Specific version
184 * The GNU Specific version returns a char pointer. That pointer may point
185 * the buffer you just passed in, or to an immutable static string.
190 p = strerror_r(num, buffer, (size_t)FR_STRERROR_BUFSIZE);
193 fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p "
194 "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno));
205 void fr_perror(char const *fmt, ...)
211 vfprintf(stderr, fmt, ap);
213 error = fr_strerror();
214 if (error && (error[0] != '\0')) {
215 fprintf(stderr, ": %s\n", error);