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