The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
24 RCSID("$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 
34 typedef struct fr_log_entry_s fr_log_entry_t;
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  */
51 typedef 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 
59 static _Thread_local fr_log_buffer_t *fr_strerror_buffer;
60 static _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  */
69 static 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 
112  fr_dlist_talloc_init(&buffer->entries, fr_log_entry_t, list);
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  */
125 static 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 
134 static 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  */
149 static 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  */
245 void _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  */
263 void _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  */
290 void _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  */
320 void _fr_strerror_marker_vprintf(char const *file, int line,
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  */
408 static 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  */
450 void _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  */
465 static 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  */
508 void _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 
516  entry = strerror_const_push(file, line, buffer, msg);
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  */
531 void _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 
539  entry = strerror_const_push(file, line, buffer, msg);
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  */
554 char 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  */
598 char 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  */
627 char 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  */
651 char 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  */
681 char 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  */
708 char 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  */
733 void 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  */
779 char 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:574
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:444
#define unlikely(_x)
Definition: build.h:378
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 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 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
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition: dlist.h:638
#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:853
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
#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
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
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition: strerror.c:733
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
char const * fr_strerror_marker(char const **subject, size_t *offset)
Get the last library error marker.
Definition: strerror.c:598
TALLOC_CTX * pool
Current pool in use.
Definition: strerror.c:54
char const * fr_strerror_peek(void)
Get the last library error.
Definition: strerror.c:627
static fr_log_buffer_t * fr_strerror_init(void)
Initialise thread local storage.
Definition: strerror.c:88
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 TALLOC_CTX * pool_alt(fr_log_buffer_t *buffer)
Definition: strerror.c:125
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
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
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
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
static int _fr_logging_free(void *arg)
Definition: strerror.c:69
char const * fr_strerror_pop(void)
Pop the last library error.
Definition: strerror.c:681
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
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 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
static _Thread_local fr_log_buffer_t * fr_strerror_buffer
Definition: strerror.c:59
fr_dlist_head_t entries
Definition: strerror.c:56
void _fr_strerror_const(char const *file, int line, char const *msg)
Log to thread local error buffer.
Definition: strerror.c:450
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
#define FR_STRERROR_BUFSIZE
Definition: strerror.c:32
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_strerror_marker_peek(char const **subject, size_t *offset)
Get the last library error marker.
Definition: strerror.c:651
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