The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
strerror.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Support functions to allow libraries to provide errors to their callers
18 *
19 * @file src/lib/util/strerror.c
20 *
21 * @copyright 2017-2020 The FreeRADIUS server project
22 * @copyright 2017-2020 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: bb3637fd07afbdbb9331ebcd192fc6cb2125efb5 $")
25
26#include <freeradius-devel/util/dlist.h>
27#include <freeradius-devel/util/strerror.h>
28#include <freeradius-devel/util/atexit.h>
29
30#include <stdbool.h>
31
32#define FR_STRERROR_BUFSIZE (2048)
33
37 char const *msg; //!< Log message.
38
39 char const *subject; //!< Subject for error markers.
40 size_t offset; //!< Where to place the msg marker relative to the subject.
41
42 char const *file; //!< File where the error was created.
43 int line; //!< Line where the error occurred.
44};
45
46/** Holds data used by the logging stack
47 *
48 * pool_a and pool_b allow #fr_strerror and #fr_strerror_pop during
49 * a call to #fr_strerror_printf or #fr_strerror_printf_push.
50 */
51typedef struct {
52 TALLOC_CTX *pool_a; //!< Pool to avoid memory allocations.
53 TALLOC_CTX *pool_b; //!< Pool to avoid memory allocations.
54 TALLOC_CTX *pool; //!< Current pool in use.
55
58
59static _Thread_local fr_log_buffer_t *fr_strerror_buffer;
60static _Thread_local bool logging_stop; //!< Due to ordering issues we may get errors being
61 ///< logged from within other thread local destructors
62 ///< which cause a crash on exit if the logging buffer
63 ///< has already been freed.
64
65/*
66 * Explicitly cleanup the memory allocated to the error buffer,
67 * just in case valgrind complains about it.
68 */
69static int _fr_logging_free(void *arg)
70{
71 /*
72 * Free arg instead of thread local storage
73 * as address sanitizer does a better job
74 * of tracking and doesn't report a leak.
75 */
76 if (talloc_free(arg) < 0) return -1;
77 fr_strerror_buffer = NULL;
78
79 logging_stop = true;
80
81 return 0;
82}
83
84/** Initialise thread local storage
85 *
86 * @return fr_buffer_t containing log messages.
87 */
89{
91
92 if (unlikely(logging_stop)) return NULL; /* No more logging */
93
95 if (!buffer) {
96 buffer = talloc(NULL, fr_log_buffer_t); /* One byte extra for status */
97 if (!buffer) {
98 oom:
99 fr_perror("Failed allocating memory for libradius error buffer");
100 return NULL;
101 }
102 buffer->pool_a = talloc_pool(buffer, FR_STRERROR_BUFSIZE);
103 if (!buffer->pool_a) goto oom;
104
105 buffer->pool_b = talloc_pool(buffer, FR_STRERROR_BUFSIZE);
106 if (!buffer->pool_b) goto oom;
107
108 buffer->pool = buffer->pool_a;
109
111
113 }
114
115 return buffer;
116}
117
118/*
119 * If last pool was pool_a, allocate from pool_b
120 * ...and vice versa. This prevents the pools
121 * from leaking due to non-contiguous allocations
122 * when we're using fr_strerror as an argument
123 * for another message.
124 */
125static inline CC_HINT(always_inline) TALLOC_CTX *pool_alt(fr_log_buffer_t *buffer)
126{
127 if (buffer->pool == buffer->pool_a) {
128 buffer->pool = buffer->pool_b;
129 return buffer->pool;
130 }
131 return buffer->pool = buffer->pool_a;
132}
133
134static inline CC_HINT(always_inline) void pool_alt_free_children(fr_log_buffer_t *buffer)
135{
136 if (buffer->pool == buffer->pool_a) {
137 talloc_free_children(buffer->pool_b);
138 return;
139 }
140 talloc_free_children(buffer->pool_a);
141}
142
143/** Create an entry in the thread local logging stack, clearing all other entries
144 *
145 * @note Can't be inlined.
146 *
147 * @hidecallergraph
148 */
149static fr_log_entry_t *strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
150{
151 va_list ap_p;
152 fr_log_entry_t *entry;
154
156 if (unlikely(buffer == NULL)) return NULL;
157
158 /*
159 * Clear any existing log messages
160 */
161 if (!fmt) {
163 return NULL;
164 }
165
166 entry = talloc(pool_alt(buffer), fr_log_entry_t);
167 if (unlikely(!entry)) {
168 oom:
169 fr_perror("Failed allocating memory for libradius error buffer");
170 return NULL;
171 }
172
173 va_copy(ap_p, ap);
174 entry->msg = fr_vasprintf(entry, fmt, ap_p);
175 va_end(ap_p);
176 if (unlikely(!entry->msg)) goto oom;
177 entry->subject = NULL;
178 entry->offset = 0;
179 entry->file = file;
180 entry->line = line;
181
183 fr_dlist_clear(&buffer->entries);
184 fr_dlist_insert_tail(&buffer->entries, entry);
185
186 return entry;
187}
188
189/** Add a message to an existing stack of messages
190 *
191 * @param[in] file the error occurred in.
192 * @param[in] line the error occurred on.
193 * @param[in] buffer The log buffer to allocate memory from.
194 * @param[in] fmt printf style format string.
195 * @param[in] ap Arguments for the error string.
196 *
197 * @note Can't be inline.
198 *
199 * @hidecallergraph
200 */
202 fr_log_buffer_t *buffer, char const *fmt, va_list ap)
203{
204 va_list ap_p;
205 fr_log_entry_t *entry;
206
207 if (!fmt) return NULL;
208
209 /*
210 * Address pathological case where we could leak memory
211 * if only a combination of fr_strerror and
212 * fr_strerror_printf_push are used.
213 */
214 if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
215
216 entry = talloc(pool_alt(buffer), fr_log_entry_t);
217 if (unlikely(!entry)) {
218 oom:
219 fr_perror("Failed allocating memory for libradius error buffer");
220 return NULL;
221 }
222
223 va_copy(ap_p, ap);
224 entry->msg = fr_vasprintf(entry, fmt, ap_p);
225 va_end(ap_p);
226 if (unlikely(!entry->msg)) goto oom;
227 entry->subject = NULL;
228 entry->offset = 0;
229 entry->file = file;
230 entry->line = line;
231
232 return entry;
233}
234
235/** Log to thread local error buffer
236 *
237 * @param[in] file the error occurred in.
238 * @param[in] line the error occurred on.
239 * @param[in] fmt printf style format string.
240 * If NULL clears any existing messages.
241 * @param[in] ap Arguments for the format string.
242 *
243 * @hidecallergraph
244 */
245void _fr_strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
246{
247 va_list our_ap;
248
249 va_copy(our_ap, ap);
250 strerror_vprintf(file, line, fmt, our_ap);
251 va_end(our_ap);
252}
253
254/** Add a message to an existing stack of messages at the tail
255 *
256 * @param[in] file the error occurred in.
257 * @param[in] line the error occurred on.
258 * @param[in] fmt printf style format string.
259 * @param[in] ap Arguments for the format string.
260 *
261 * @hidecallergraph
262 */
263void _fr_strerror_vprintf_push(char const *file, int line, char const *fmt, va_list ap)
264{
265 va_list our_ap;
267 fr_log_entry_t *entry;
268
270 if (unlikely(buffer == NULL)) return;
271
272 va_copy(our_ap, ap);
273 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
274 va_end(our_ap);
275
276 if (unlikely(!entry)) return;
277
278 fr_dlist_insert_tail(&buffer->entries, entry);
279}
280
281/** Add a message to an existing stack of messages at the head
282 *
283 * @param[in] file the error occurred in.
284 * @param[in] line the error occurred on.
285 * @param[in] fmt printf style format string.
286 * @param[in] ap Arguments for the format string.
287 *
288 * @hidecallergraph
289 */
290void _fr_strerror_vprintf_push_head(char const *file, int line, char const *fmt, va_list ap)
291{
292 va_list our_ap;
294 fr_log_entry_t *entry;
295
297 if (unlikely(buffer == NULL)) return;
298
299 va_copy(our_ap, ap);
300 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
301 va_end(our_ap);
302
303 if (unlikely(!entry)) return;
304
305 fr_dlist_insert_head(&buffer->entries, entry);
306}
307
308/** Add an error marker to an existing stack of messages
309 *
310 * @param[in] file the error occurred in.
311 * @param[in] line the error occurred on.
312 * @param[in] subject to mark up.
313 * @param[in] offset Positive offset to show where the error
314 * should be positioned.
315 * @param[in] fmt Error string.
316 * @param[in] ap Arguments for the error string.
317 *
318 * @hidecallergraph
319 */
321 char const *subject, size_t offset, char const *fmt, va_list ap)
322{
323 va_list our_ap;
324 fr_log_entry_t *entry;
325
326 va_copy(our_ap, ap);
327 entry = strerror_vprintf(file, line, fmt, our_ap);
328 va_end(our_ap);
329
330 if (unlikely(!entry)) return;
331
332 entry->subject = talloc_strdup(entry, subject);
333 entry->offset = offset;
334}
335
336/** Add an error marker to an existing stack of messages at the tail
337 *
338 * @param[in] file the error occurred in.
339 * @param[in] line the error occurred on.
340 * @param[in] subject to mark up.
341 * @param[in] offset Positive offset to show where the error
342 * should be positioned.
343 * @param[in] fmt Error string.
344 * @param[in] ap Arguments for the error string.
345 *
346 * @hidecallergraph
347 */
349 char const *subject, size_t offset, char const *fmt, va_list ap)
350{
351 va_list our_ap;
352 fr_log_entry_t *entry;
354
356 if (unlikely(buffer == NULL)) return;
357
358 va_copy(our_ap, ap);
359 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
360 va_end(our_ap);
361
362 if (unlikely(!entry)) return;
363
364 entry->subject = talloc_strdup(entry, subject);
365 entry->offset = offset;
366
367 fr_dlist_insert_tail(&buffer->entries, entry);
368}
369
370/** Add an error marker to an existing stack of messages at the head
371 *
372 * @param[in] file the error occurred in.
373 * @param[in] line the error occurred on.
374 * @param[in] subject to mark up.
375 * @param[in] offset Positive offset to show where the error
376 * should be positioned.
377 * @param[in] fmt Error string.
378 * @param[in] ap Arguments for the error string.
379 *
380 * @hidecallergraph
381 */
383 char const *subject, size_t offset, char const *fmt, va_list ap)
384{
385 va_list our_ap;
386 fr_log_entry_t *entry;
388
390 if (unlikely(buffer == NULL)) return;
391
392 va_copy(our_ap, ap);
393 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
394 va_end(our_ap);
395
396 if (unlikely(!entry)) return;
397
398 entry->subject = talloc_strdup(entry, subject);
399 entry->offset = offset;
400
401 fr_dlist_insert_head(&buffer->entries, entry);
402}
403
404/** Create an entry in the thread local logging stack using a const string, clearing all other entries
405 *
406 * @hidecallergraph
407 */
408static inline CC_HINT(always_inline) fr_log_entry_t *strerror_const(char const *file, int line, char const *msg)
409{
410 fr_log_entry_t *entry;
412
414 if (unlikely(buffer == NULL)) return NULL;
415
416 entry = talloc(pool_alt(buffer), fr_log_entry_t);
417 if (unlikely(!entry)) {
418 fr_perror("Failed allocating memory for libradius error buffer");
419 return NULL;
420 }
421 /*
422 * For some reason this is significantly
423 * more efficient than a compound literal
424 * even though in the majority of cases
425 * compound literals and individual field
426 * assignments result in the same byte
427 * code.
428 */
429 entry->file = file;
430 entry->line = line;
431 entry->msg = msg;
432 entry->subject = NULL;
433 entry->offset = 0;
434
436 fr_dlist_clear(&buffer->entries);
437 fr_dlist_insert_tail(&buffer->entries, entry);
438
439 return entry;
440}
441
442/** Log to thread local error buffer
443 *
444 * @param[in] file the error occurred in.
445 * @param[in] line the error occurred on.
446 * @param[in] msg To add to error stack. Must have a
447 * lifetime equal to that of the program.
448 * @hidecallergraph
449 */
450void _fr_strerror_const(char const *file, int line, char const *msg)
451{
452 (void)strerror_const(file, line, msg);
453}
454
455/** Add a message to an existing stack of messages
456 *
457 * @param[in] file the error occurred in.
458 * @param[in] line the error occurred on.
459 * @param[in] buffer to add the message to.
460 * @param[in] msg To add to error stack. Must have a
461 * lifetime equal to that of the program.
462 *
463 * @hidecallergraph
464 */
465static inline CC_HINT(always_inline) fr_log_entry_t *strerror_const_push(char const *file, int line,
466 fr_log_buffer_t *buffer, char const *msg)
467{
468 fr_log_entry_t *entry;
469
470 /*
471 * Address pathological case where we could leak memory
472 * if only a combination of fr_strerror and
473 * fr_strerror_printf_push are used.
474 */
475 if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
476
477 entry = talloc(pool_alt(buffer), fr_log_entry_t);
478 if (unlikely(!entry)) {
479 fr_perror("Failed allocating memory for libradius error buffer");
480 return NULL;
481 }
482 /*
483 * For some reason this is significantly
484 * more efficient than a compound literal
485 * even though in the majority of cases
486 * compound literals and individual field
487 * assignments result in the same byte
488 * code.
489 */
490 entry->msg = msg;
491 entry->subject = NULL;
492 entry->offset = 0;
493 entry->file = file;
494 entry->line = line;
495
496 return entry;
497}
498
499/** Add a message to an existing stack of messages at the tail
500 *
501 * @param[in] file the error occurred in.
502 * @param[in] line the error occurred on.
503 * @param[in] msg To add to error stack. Must have a
504 * lifetime equal to that of the program.
505 *
506 * @hidecallergraph
507 */
508void _fr_strerror_const_push(char const *file, int line, char const *msg)
509{
511 fr_log_entry_t *entry;
512
514 if (unlikely(buffer == NULL)) return;
515
517 if (unlikely(!entry)) return;
518
519 fr_dlist_insert_tail(&buffer->entries, entry);
520}
521
522/** Add a message to an existing stack of messages at the head
523 *
524 * @param[in] file the error occurred in.
525 * @param[in] line the error occurred on.
526 * @param[in] msg To add to error stack. Must have a
527 * lifetime equal to that of the program.
528 *
529 * @hidecallergraph
530 */
531void _fr_strerror_const_push_head(char const *file, int line, char const *msg)
532{
534 fr_log_entry_t *entry;
535
537 if (unlikely(buffer == NULL)) return;
538
540 if (unlikely(!entry)) return;
541
542 fr_dlist_insert_head(&buffer->entries, entry);
543}
544
545/** Get the last library error
546 *
547 * Will only return the last library error once, after which it will return a zero length string.
548 * If there are additional messages on the log stack they will be discarded.
549 *
550 * @return library error or zero length string.
551 *
552 * @hidecallergraph
553 */
554char const *fr_strerror(void)
555{
557 fr_log_entry_t *entry;
558
560 if (unlikely(buffer == NULL)) return "";
561
562 entry = fr_dlist_tail(&buffer->entries);
563 if (!entry) return "";
564
565 /*
566 * Memory gets freed on next call to
567 * fr_strerror_printf or fr_strerror_printf_push.
568 */
569 fr_dlist_clear(&buffer->entries);
570
571 return entry->msg;
572}
573
574/** Clears all pending messages from the talloc pools
575 *
576 */
578{
580
581 if (unlikely(buffer == NULL)) return;
582
583 fr_dlist_clear(&buffer->entries);
584 talloc_free_children(buffer->pool_a);
585 talloc_free_children(buffer->pool_b);
586}
587
588/** Get the last library error marker
589 *
590 * @param[out] subject The subject string the error relates to.
591 * @param[out] offset Where to place the marker.
592 * @return
593 * - NULL if there are no pending errors.
594 * - The error message if there was an error.
595 *
596 * @hidecallergraph
597 */
598char const *fr_strerror_marker(char const **subject, size_t *offset)
599{
601 fr_log_entry_t *entry;
602
604 if (unlikely(buffer == NULL)) return "";
605
606 entry = fr_dlist_head(&buffer->entries);
607 if (!entry) return "";
608
609 /*
610 * Memory gets freed on next call to
611 * fr_strerror_printf or fr_strerror_printf_push.
612 */
613 fr_dlist_clear(&buffer->entries);
614
615 *subject = entry->subject;
616 *offset = entry->offset;
617
618 return entry->msg;
619}
620
621/** Get the last library error
622 *
623 * @return library error or zero length string.
624 *
625 * @hidecallergraph
626 */
627char const *fr_strerror_peek(void)
628{
630 fr_log_entry_t *entry;
631
633 if (unlikely(buffer == NULL)) return "";
634
635 entry = fr_dlist_tail(&buffer->entries);
636 if (!entry) return "";
637
638 return entry->msg;
639}
640
641/** Get the last library error marker
642 *
643 * @param[out] subject The subject string the error relates to.
644 * @param[out] offset Where to place the marker.
645 * @return
646 * - NULL if there are no pending errors.
647 * - The error message if there was an error.
648 *
649 * @hidecallergraph
650 */
651char const *fr_strerror_marker_peek(char const **subject, size_t *offset)
652{
654 fr_log_entry_t *entry;
655
657 if (unlikely(buffer == NULL)) return "";
658
659 entry = fr_dlist_head(&buffer->entries);
660 if (!entry) return "";
661
662 *subject = entry->subject;
663 *offset = entry->offset;
664
665 return entry->msg;
666}
667
668/** Pop the last library error
669 *
670 * Return the first message added to the error stack using #fr_strerror_printf
671 * or #fr_strerror_printf_push.
672 *
673 * @note Unlink fr_strerror() will return NULL if no messages are pending.
674 *
675 * @return
676 * - A library error.
677 * - NULL if no errors are pending.
678 *
679 * @hidecallergraph
680 */
681char const *fr_strerror_pop(void)
682{
684 fr_log_entry_t *entry;
685
687 if (unlikely(buffer == NULL)) return NULL;
688
689 entry = fr_dlist_head(&buffer->entries);
690 if (!entry) return NULL;
691
692 fr_dlist_remove(&buffer->entries, entry);
693
694 return entry->msg;
695}
696
697/** Pop the last library error with marker information
698 *
699 * Return the first message added to the error stack using #fr_strerror_printf
700 * or #fr_strerror_printf_push.
701 *
702 * @return
703 * - A library error.
704 * - NULL if no errors are pending.
705 *
706 * @hidecallergraph
707 */
708char const *fr_strerror_marker_pop(char const **subject, size_t *offset)
709{
711 fr_log_entry_t *entry;
712
714 if (unlikely(buffer == NULL)) return NULL;
715
716 entry = fr_dlist_head(&buffer->entries);
717 if (!entry) return NULL;
718
719 fr_dlist_remove(&buffer->entries, entry);
720
721 *subject = entry->subject;
722 *offset = entry->offset;
723
724 return entry->msg;
725}
726
727/** Print the current error to stderr with a prefix
728 *
729 * Used by utility functions lacking their own logging infrastructure
730 *
731 * @hidecallergraph
732 */
733void fr_perror(char const *fmt, ...)
734{
735 char const *error;
736 char const *subject;
737 size_t offset;
738 char *prefix = NULL;
739 va_list ap;
740
741 error = fr_strerror_marker_pop(&subject, &offset);
742 if (fmt) {
743 va_start(ap, fmt);
744 prefix = talloc_vasprintf(NULL, fmt, ap);
745 va_end(ap);
746
747 if (error) {
748 fprintf(stderr, "%s: %s\n", prefix, error);
749 } else {
750 fprintf(stderr, "%s\n", prefix);
751 talloc_free(prefix);
752 return;
753 }
754 talloc_free(prefix);
755 } else {
756 if (!error) return;
757 fprintf(stderr, "%s\n", error);
758 }
759
760 while ((error = fr_strerror_marker_pop(&subject, &offset))) {
761 if (error && (error[0] != '\0')) {
762 fprintf(stderr, "%s\n", error);
763 }
764 }
765
766}
767
768/** Print the stack of string buffers to a thread local buffer
769 *
770 * Used by utility functions lacking their own logging infrastructure
771 *
772 * @hidecallergraph
773 *
774 * @param[in] line_sep to insert between the log lines.
775 * @param[in] fmt to prefix all log messages with.
776 * @return
777 * - A thread local string buffer containing the concatenated messages.
778 */
779char const *fr_perror_to_str(char const *line_sep, char const *fmt, ...)
780{
781 char const *error;
782 char const *subject;
783 size_t offset;
784 char *prefix;
785 va_list ap;
786 fr_sbuff_t *agg;
787
788 FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX);
789
790 va_start(ap, fmt);
791 prefix = talloc_vasprintf(NULL, fmt, ap);
792 if (unlikely(!prefix)) return NULL;
793 va_end(ap);
794
795 error = fr_strerror_marker_pop(&subject, &offset);
796 if (error) {
797 if (fr_sbuff_in_sprintf(agg, "%s: %s%s", prefix, error, line_sep) < 0) return NULL;
798 } else {
799 if (fr_sbuff_in_sprintf(agg, "%s%s", prefix, error, line_sep) < 0) return NULL;
800 talloc_free(prefix);
801 return NULL;
802 }
803
804 while ((error = fr_strerror_marker_pop(&subject, &offset))) {
805 if (error && (error[0] != '\0')) {
806 if (fr_sbuff_in_sprintf(agg, "%s: %s%s", prefix, error, line_sep) < 0) return NULL;
807 }
808 }
809 talloc_free(prefix);
810
811 return fr_sbuff_start(agg);
812}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_end(args)
log_entry msg
Definition acutest.h:794
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
va_start(args, fmt)
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:221
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
static void * fr_dlist_tail(fr_dlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
Definition dlist.h:531
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:275
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
Definition dlist.h:338
static void fr_dlist_clear(fr_dlist_head_t *list_head)
Efficiently remove all elements in a dlist.
Definition dlist.h:295
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
talloc_free(reap)
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
Definition print.c:851
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1595
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
void _fr_strerror_marker_vprintf_push(char const *file, int line, char const *subject, size_t offset, char const *fmt, va_list ap)
Add an error marker to an existing stack of messages at the tail.
Definition strerror.c:348
void _fr_strerror_const_push(char const *file, int line, char const *msg)
Add a message to an existing stack of messages at the tail.
Definition strerror.c:508
char const * msg
Log message.
Definition strerror.c:37
size_t offset
Where to place the msg marker relative to the subject.
Definition strerror.c:40
TALLOC_CTX * pool_b
Pool to avoid memory allocations.
Definition strerror.c:53
static _Thread_local bool logging_stop
Due to ordering issues we may get errors being logged from within other thread local destructors whic...
Definition strerror.c:60
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
char const * fr_strerror_peek(void)
Get the last library error.
Definition strerror.c:627
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
TALLOC_CTX * pool
Current pool in use.
Definition strerror.c:54
static fr_log_entry_t * strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
Create an entry in the thread local logging stack, clearing all other entries.
Definition strerror.c:149
char const * fr_strerror_marker_pop(char const **subject, size_t *offset)
Pop the last library error with marker information.
Definition strerror.c:708
static fr_log_entry_t * strerror_vprintf_push(char const *file, int line, fr_log_buffer_t *buffer, char const *fmt, va_list ap)
Add a message to an existing stack of messages.
Definition strerror.c:201
void _fr_strerror_const_push_head(char const *file, int line, char const *msg)
Add a message to an existing stack of messages at the head.
Definition strerror.c:531
char const * subject
Subject for error markers.
Definition strerror.c:39
TALLOC_CTX * pool_a
Pool to avoid memory allocations.
Definition strerror.c:52
static void pool_alt_free_children(fr_log_buffer_t *buffer)
Definition strerror.c:134
static int _fr_logging_free(void *arg)
Definition strerror.c:69
void _fr_strerror_vprintf_push(char const *file, int line, char const *fmt, va_list ap)
Add a message to an existing stack of messages at the tail.
Definition strerror.c:263
void _fr_strerror_marker_vprintf(char const *file, int line, char const *subject, size_t offset, char const *fmt, va_list ap)
Add an error marker to an existing stack of messages.
Definition strerror.c:320
static fr_log_entry_t * strerror_const_push(char const *file, int line, fr_log_buffer_t *buffer, char const *msg)
Add a message to an existing stack of messages.
Definition strerror.c:465
int line
Line where the error occurred.
Definition strerror.c:43
void _fr_strerror_vprintf_push_head(char const *file, int line, char const *fmt, va_list ap)
Add a message to an existing stack of messages at the head.
Definition strerror.c:290
static _Thread_local fr_log_buffer_t * fr_strerror_buffer
Definition strerror.c:59
fr_dlist_head_t entries
Definition strerror.c:56
static fr_log_entry_t * strerror_const(char const *file, int line, char const *msg)
Create an entry in the thread local logging stack using a const string, clearing all other entries.
Definition strerror.c:408
static fr_log_buffer_t * fr_strerror_init(void)
Initialise thread local storage.
Definition strerror.c:88
void _fr_strerror_const(char const *file, int line, char const *msg)
Log to thread local error buffer.
Definition strerror.c:450
#define FR_STRERROR_BUFSIZE
Definition strerror.c:32
char const * fr_strerror_pop(void)
Pop the last library error.
Definition strerror.c:681
static TALLOC_CTX * pool_alt(fr_log_buffer_t *buffer)
Definition strerror.c:125
void _fr_strerror_marker_vprintf_push_head(char const *file, int line, char const *subject, size_t offset, char const *fmt, va_list ap)
Add an error marker to an existing stack of messages at the head.
Definition strerror.c:382
char const * file
File where the error was created.
Definition strerror.c:42
fr_dlist_t list
Definition strerror.c:36
char const * fr_perror_to_str(char const *line_sep, char const *fmt,...)
Print the stack of string buffers to a thread local buffer.
Definition strerror.c:779
char const * fr_strerror_marker_peek(char const **subject, size_t *offset)
Get the last library error marker.
Definition strerror.c:651
char const * fr_strerror_marker(char const **subject, size_t *offset)
Get the last library error marker.
Definition strerror.c:598
void _fr_strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
Log to thread local error buffer.
Definition strerror.c:245
Holds data used by the logging stack.
Definition strerror.c:51
Definition strerror.c:35