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: 41de68eef84dc63e3c36659c6d19c68057eeff80 $")
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 /*
209 * Address pathological case where we could leak memory
210 * if only a combination of fr_strerror and
211 * fr_strerror_printf_push are used.
212 */
213 if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
214
215 entry = talloc(pool_alt(buffer), fr_log_entry_t);
216 if (unlikely(!entry)) {
217 oom:
218 fr_perror("Failed allocating memory for libradius error buffer");
219 return NULL;
220 }
221
222 va_copy(ap_p, ap);
223 entry->msg = fr_vasprintf(entry, fmt, ap_p);
224 va_end(ap_p);
225 if (unlikely(!entry->msg)) goto oom;
226 entry->subject = NULL;
227 entry->offset = 0;
228 entry->file = file;
229 entry->line = line;
230
231 return entry;
232}
233
234/** Log to thread local error buffer
235 *
236 * @param[in] file the error occurred in.
237 * @param[in] line the error occurred on.
238 * @param[in] fmt printf style format string.
239 * If NULL clears any existing messages.
240 * @param[in] ap Arguments for the format string.
241 *
242 * @hidecallergraph
243 */
244void _fr_strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
245{
246 va_list our_ap;
247
248 va_copy(our_ap, ap);
249 strerror_vprintf(file, line, fmt, our_ap);
250 va_end(our_ap);
251}
252
253/** Add a message to an existing stack of messages at the tail
254 *
255 * @param[in] file the error occurred in.
256 * @param[in] line the error occurred on.
257 * @param[in] fmt printf style format string.
258 * @param[in] ap Arguments for the format string.
259 *
260 * @hidecallergraph
261 */
262void _fr_strerror_vprintf_push(char const *file, int line, char const *fmt, va_list ap)
263{
264 va_list our_ap;
266 fr_log_entry_t *entry;
267
269 if (unlikely(buffer == NULL)) return;
270
271 va_copy(our_ap, ap);
272 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
273 va_end(our_ap);
274
275 if (unlikely(!entry)) return;
276
277 fr_dlist_insert_tail(&buffer->entries, entry);
278}
279
280/** Add a message to an existing stack of messages at the head
281 *
282 * @param[in] file the error occurred in.
283 * @param[in] line the error occurred on.
284 * @param[in] fmt printf style format string.
285 * @param[in] ap Arguments for the format string.
286 *
287 * @hidecallergraph
288 */
289void _fr_strerror_vprintf_push_head(char const *file, int line, char const *fmt, va_list ap)
290{
291 va_list our_ap;
293 fr_log_entry_t *entry;
294
296 if (unlikely(buffer == NULL)) return;
297
298 va_copy(our_ap, ap);
299 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
300 va_end(our_ap);
301
302 if (unlikely(!entry)) return;
303
304 fr_dlist_insert_head(&buffer->entries, entry);
305}
306
307/** Add an error marker to an existing stack of messages
308 *
309 * @param[in] file the error occurred in.
310 * @param[in] line the error occurred on.
311 * @param[in] subject to mark up.
312 * @param[in] offset Positive offset to show where the error
313 * should be positioned.
314 * @param[in] fmt Error string.
315 * @param[in] ap Arguments for the error string.
316 *
317 * @hidecallergraph
318 */
320 char const *subject, size_t offset, char const *fmt, va_list ap)
321{
322 va_list our_ap;
323 fr_log_entry_t *entry;
324
325 va_copy(our_ap, ap);
326 entry = strerror_vprintf(file, line, fmt, our_ap);
327 va_end(our_ap);
328
329 if (unlikely(!entry)) return;
330
331 entry->subject = talloc_strdup(entry, subject);
332 entry->offset = offset;
333}
334
335/** Add an error marker to an existing stack of messages at the tail
336 *
337 * @param[in] file the error occurred in.
338 * @param[in] line the error occurred on.
339 * @param[in] subject to mark up.
340 * @param[in] offset Positive offset to show where the error
341 * should be positioned.
342 * @param[in] fmt Error string.
343 * @param[in] ap Arguments for the error string.
344 *
345 * @hidecallergraph
346 */
348 char const *subject, size_t offset, char const *fmt, va_list ap)
349{
350 va_list our_ap;
351 fr_log_entry_t *entry;
353
355 if (unlikely(buffer == NULL)) return;
356
357 va_copy(our_ap, ap);
358 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
359 va_end(our_ap);
360
361 if (unlikely(!entry)) return;
362
363 entry->subject = talloc_strdup(entry, subject);
364 entry->offset = offset;
365
366 fr_dlist_insert_tail(&buffer->entries, entry);
367}
368
369/** Add an error marker to an existing stack of messages at the head
370 *
371 * @param[in] file the error occurred in.
372 * @param[in] line the error occurred on.
373 * @param[in] subject to mark up.
374 * @param[in] offset Positive offset to show where the error
375 * should be positioned.
376 * @param[in] fmt Error string.
377 * @param[in] ap Arguments for the error string.
378 *
379 * @hidecallergraph
380 */
382 char const *subject, size_t offset, char const *fmt, va_list ap)
383{
384 va_list our_ap;
385 fr_log_entry_t *entry;
387
389 if (unlikely(buffer == NULL)) return;
390
391 va_copy(our_ap, ap);
392 entry = strerror_vprintf_push(file, line, buffer, fmt, our_ap);
393 va_end(our_ap);
394
395 if (unlikely(!entry)) return;
396
397 entry->subject = talloc_strdup(entry, subject);
398 entry->offset = offset;
399
400 fr_dlist_insert_head(&buffer->entries, entry);
401}
402
403/** Create an entry in the thread local logging stack using a const string, clearing all other entries
404 *
405 * @hidecallergraph
406 */
407static inline CC_HINT(always_inline) fr_log_entry_t *strerror_const(char const *file, int line, char const *msg)
408{
409 fr_log_entry_t *entry;
411
413 if (unlikely(buffer == NULL)) return NULL;
414
415 entry = talloc(pool_alt(buffer), fr_log_entry_t);
416 if (unlikely(!entry)) {
417 fr_perror("Failed allocating memory for libradius error buffer");
418 return NULL;
419 }
420 /*
421 * For some reason this is significantly
422 * more efficient than a compound literal
423 * even though in the majority of cases
424 * compound literals and individual field
425 * assignments result in the same byte
426 * code.
427 */
428 entry->file = file;
429 entry->line = line;
430 entry->msg = msg;
431 entry->subject = NULL;
432 entry->offset = 0;
433
435 fr_dlist_clear(&buffer->entries);
436 fr_dlist_insert_tail(&buffer->entries, entry);
437
438 return entry;
439}
440
441/** Log to thread local error buffer
442 *
443 * @param[in] file the error occurred in.
444 * @param[in] line the error occurred on.
445 * @param[in] msg To add to error stack. Must have a
446 * lifetime equal to that of the program.
447 * @hidecallergraph
448 */
449void _fr_strerror_const(char const *file, int line, char const *msg)
450{
451 (void)strerror_const(file, line, msg);
452}
453
454/** Add a message to an existing stack of messages
455 *
456 * @param[in] file the error occurred in.
457 * @param[in] line the error occurred on.
458 * @param[in] buffer to add the message to.
459 * @param[in] msg To add to error stack. Must have a
460 * lifetime equal to that of the program.
461 *
462 * @hidecallergraph
463 */
464static inline CC_HINT(always_inline) fr_log_entry_t *strerror_const_push(char const *file, int line,
465 fr_log_buffer_t *buffer, char const *msg)
466{
467 fr_log_entry_t *entry;
468
469 /*
470 * Address pathological case where we could leak memory
471 * if only a combination of fr_strerror and
472 * fr_strerror_printf_push are used.
473 */
474 if (!fr_dlist_num_elements(&buffer->entries)) talloc_free_children(buffer->pool);
475
476 entry = talloc(pool_alt(buffer), fr_log_entry_t);
477 if (unlikely(!entry)) {
478 fr_perror("Failed allocating memory for libradius error buffer");
479 return NULL;
480 }
481 /*
482 * For some reason this is significantly
483 * more efficient than a compound literal
484 * even though in the majority of cases
485 * compound literals and individual field
486 * assignments result in the same byte
487 * code.
488 */
489 entry->msg = msg;
490 entry->subject = NULL;
491 entry->offset = 0;
492 entry->file = file;
493 entry->line = line;
494
495 return entry;
496}
497
498/** Add a message to an existing stack of messages at the tail
499 *
500 * @param[in] file the error occurred in.
501 * @param[in] line the error occurred on.
502 * @param[in] msg To add to error stack. Must have a
503 * lifetime equal to that of the program.
504 *
505 * @hidecallergraph
506 */
507void _fr_strerror_const_push(char const *file, int line, char const *msg)
508{
510 fr_log_entry_t *entry;
511
513 if (unlikely(buffer == NULL)) return;
514
516 if (unlikely(!entry)) return;
517
518 fr_dlist_insert_tail(&buffer->entries, entry);
519}
520
521/** Add a message to an existing stack of messages at the head
522 *
523 * @param[in] file the error occurred in.
524 * @param[in] line the error occurred on.
525 * @param[in] msg To add to error stack. Must have a
526 * lifetime equal to that of the program.
527 *
528 * @hidecallergraph
529 */
530void _fr_strerror_const_push_head(char const *file, int line, char const *msg)
531{
533 fr_log_entry_t *entry;
534
536 if (unlikely(buffer == NULL)) return;
537
539 if (unlikely(!entry)) return;
540
541 fr_dlist_insert_head(&buffer->entries, entry);
542}
543
544/** Get the last library error
545 *
546 * Will only return the last library error once, after which it will return a zero length string.
547 * If there are additional messages on the log stack they will be discarded.
548 *
549 * @return library error or zero length string.
550 *
551 * @hidecallergraph
552 */
553char const *fr_strerror(void)
554{
556 fr_log_entry_t *entry;
557
559 if (unlikely(buffer == NULL)) return "";
560
561 entry = fr_dlist_tail(&buffer->entries);
562 if (!entry) return "";
563
564 /*
565 * Memory gets freed on next call to
566 * fr_strerror_printf or fr_strerror_printf_push.
567 */
568 fr_dlist_clear(&buffer->entries);
569
570 return entry->msg;
571}
572
573/** Clears all pending messages from the talloc pools
574 *
575 */
577{
579
580 if (unlikely(buffer == NULL)) return;
581
582 fr_dlist_clear(&buffer->entries);
583 talloc_free_children(buffer->pool_a);
584 talloc_free_children(buffer->pool_b);
585}
586
587/** Get the last library error marker
588 *
589 * @param[out] subject The subject string the error relates to.
590 * @param[out] offset Where to place the marker.
591 * @return
592 * - NULL if there are no pending errors.
593 * - The error message if there was an error.
594 *
595 * @hidecallergraph
596 */
597char const *fr_strerror_marker(char const **subject, size_t *offset)
598{
600 fr_log_entry_t *entry;
601
603 if (unlikely(buffer == NULL)) return "";
604
605 entry = fr_dlist_head(&buffer->entries);
606 if (!entry) return "";
607
608 /*
609 * Memory gets freed on next call to
610 * fr_strerror_printf or fr_strerror_printf_push.
611 */
612 fr_dlist_clear(&buffer->entries);
613
614 *subject = entry->subject;
615 *offset = entry->offset;
616
617 return entry->msg;
618}
619
620/** Get the last library error
621 *
622 * @return library error or zero length string.
623 *
624 * @hidecallergraph
625 */
626char const *fr_strerror_peek(void)
627{
629 fr_log_entry_t *entry;
630
632 if (unlikely(buffer == NULL)) return "";
633
634 entry = fr_dlist_tail(&buffer->entries);
635 if (!entry) return "";
636
637 return entry->msg;
638}
639
640/** Get the last library error marker
641 *
642 * @param[out] subject The subject string the error relates to.
643 * @param[out] offset Where to place the marker.
644 * @return
645 * - NULL if there are no pending errors.
646 * - The error message if there was an error.
647 *
648 * @hidecallergraph
649 */
650char const *fr_strerror_marker_peek(char const **subject, size_t *offset)
651{
653 fr_log_entry_t *entry;
654
656 if (unlikely(buffer == NULL)) return "";
657
658 entry = fr_dlist_head(&buffer->entries);
659 if (!entry) return "";
660
661 *subject = entry->subject;
662 *offset = entry->offset;
663
664 return entry->msg;
665}
666
667/** Pop the last library error
668 *
669 * Return the first message added to the error stack using #fr_strerror_printf
670 * or #fr_strerror_printf_push.
671 *
672 * @note Unlink fr_strerror() will return NULL if no messages are pending.
673 *
674 * @return
675 * - A library error.
676 * - NULL if no errors are pending.
677 *
678 * @hidecallergraph
679 */
680char const *fr_strerror_pop(void)
681{
683 fr_log_entry_t *entry;
684
686 if (unlikely(buffer == NULL)) return NULL;
687
688 entry = fr_dlist_head(&buffer->entries);
689 if (!entry) return NULL;
690
691 fr_dlist_remove(&buffer->entries, entry);
692
693 return entry->msg;
694}
695
696/** Pop the last library error with marker information
697 *
698 * Return the first message added to the error stack using #fr_strerror_printf
699 * or #fr_strerror_printf_push.
700 *
701 * @return
702 * - A library error.
703 * - NULL if no errors are pending.
704 *
705 * @hidecallergraph
706 */
707char const *fr_strerror_marker_pop(char const **subject, size_t *offset)
708{
710 fr_log_entry_t *entry;
711
713 if (unlikely(buffer == NULL)) return NULL;
714
715 entry = fr_dlist_head(&buffer->entries);
716 if (!entry) return NULL;
717
718 fr_dlist_remove(&buffer->entries, entry);
719
720 *subject = entry->subject;
721 *offset = entry->offset;
722
723 return entry->msg;
724}
725
726/** Print the current error to stderr with a prefix
727 *
728 * Used by utility functions lacking their own logging infrastructure
729 *
730 * @hidecallergraph
731 */
732void fr_perror(char const *fmt, ...)
733{
734 char const *error;
735 char const *subject;
736 size_t offset;
737 char *prefix = NULL;
738 va_list ap;
739
740 error = fr_strerror_marker_pop(&subject, &offset);
741 if (fmt) {
742 va_start(ap, fmt);
743 prefix = talloc_vasprintf(NULL, fmt, ap);
744 va_end(ap);
745
746 if (error) {
747 fprintf(stderr, "%s: %s\n", prefix, error);
748 } else {
749 fprintf(stderr, "%s\n", prefix);
750 talloc_free(prefix);
751 return;
752 }
753 talloc_free(prefix);
754 } else {
755 if (!error) return;
756 fprintf(stderr, "%s\n", error);
757 }
758
759 while ((error = fr_strerror_marker_pop(&subject, &offset))) {
760 if (error && (error[0] != '\0')) {
761 fprintf(stderr, "%s\n", error);
762 }
763 }
764
765}
766
767/** Print the stack of string buffers to a thread local buffer
768 *
769 * Used by utility functions lacking their own logging infrastructure
770 *
771 * @hidecallergraph
772 *
773 * @param[in] line_sep to insert between the log lines.
774 * @param[in] fmt to prefix all log messages with.
775 * @return
776 * - A thread local string buffer containing the concatenated messages.
777 */
778char const *fr_perror_to_str(char const *line_sep, char const *fmt, ...)
779{
780 char const *error;
781 char const *subject;
782 size_t offset;
783 char *prefix;
784 va_list ap;
785 fr_sbuff_t *agg;
786
787 FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 256, SIZE_MAX);
788
789 va_start(ap, fmt);
790 prefix = talloc_vasprintf(NULL, fmt, ap);
791 if (unlikely(!prefix)) return NULL;
792 va_end(ap);
793
794 error = fr_strerror_marker_pop(&subject, &offset);
795 if (error) {
796 if (fr_sbuff_in_sprintf(agg, "%s: %s%s", prefix, error, line_sep) < 0) return NULL;
797 } else {
798 if (fr_sbuff_in_sprintf(agg, "%s%s", prefix, error, line_sep) < 0) return NULL;
799 talloc_free(prefix);
800 return NULL;
801 }
802
803 while ((error = fr_strerror_marker_pop(&subject, &offset))) {
804 if (error && (error[0] != '\0')) {
805 if (fr_sbuff_in_sprintf(agg, "%s: %s%s", prefix, error, line_sep) < 0) return NULL;
806 }
807 }
808 talloc_free(prefix);
809
810 return fr_sbuff_start(agg);
811}
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:485
#define unlikely(_x)
Definition build.h:383
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:1597
#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:347
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:507
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:553
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:732
char const * fr_strerror_peek(void)
Get the last library error.
Definition strerror.c:626
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
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:707
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:530
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:262
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:319
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:464
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:289
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:407
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:449
#define FR_STRERROR_BUFSIZE
Definition strerror.c:31
char const * fr_strerror_pop(void)
Pop the last library error.
Definition strerror.c:680
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:381
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:778
char const * fr_strerror_marker_peek(char const **subject, size_t *offset)
Get the last library error marker.
Definition strerror.c:650
char const * fr_strerror_marker(char const **subject, size_t *offset)
Get the last library error marker.
Definition strerror.c:597
void _fr_strerror_vprintf(char const *file, int line, char const *fmt, va_list ap)
Log to thread local error buffer.
Definition strerror.c:244
Holds data used by the logging stack.
Definition strerror.c:50
Definition strerror.c:34