The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
cf_util.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program 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
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: c765dfac3d74f64f5b9d1679119d9c63ef7a07c9 $
19 * @file cf_util.c
20 * @brief Functions for building and managing the structure of internal format config items.
21 *
22 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: c765dfac3d74f64f5b9d1679119d9c63ef7a07c9 $")
25
26#include <string.h>
27
28#include <freeradius-devel/server/cf_file.h>
29#include <freeradius-devel/server/cf_priv.h>
30#include <freeradius-devel/server/log.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/util/atexit.h>
33
34static inline int8_t cf_ident2_cmp(void const *a, void const *b);
35static int8_t _cf_ident1_cmp(void const *a, void const *b);
36static int8_t _cf_ident2_cmp(void const *a, void const *b);
37
38/** Return the next child that's of the specified type
39 *
40 * @param[in] parent to return children from.
41 * @param[in] current child to start searching from.
42 * @param[in] type to search for.
43 * @return
44 * - The next #CONF_ITEM that's a child of ci matching type.
45 * - NULL if no #CONF_ITEM matches that criteria.
46 */
48{
50 if (ci->type == type) return ci;
51 }
52
53 return NULL;
54}
55
56/** Return the previous child that's of the specified type
57 *
58 * @param[in] parent to return children from.
59 * @param[in] current child to start searching from.
60 * @param[in] type to search for.
61 * @return
62 * - The next #CONF_ITEM that's a child of ci matching type.
63 * - NULL if no #CONF_ITEM matches that criteria.
64 */
65static inline CC_HINT(always_inline)
67{
69 if (ci->type == type) return ci;
70 }
71
72 return NULL;
73}
74
75#define IS_WILDCARD(_ident) (_ident == CF_IDENT_ANY)
76
77/** Return the next child that's of the specified type with the specified identifiers
78 *
79 * @param[in] parent The section we're searching in.
80 * @param[in] type of #CONF_ITEM we're searching for.
81 * @param[in] ident1 The first identifier.
82 * @param[in] ident2 The second identifier. Special value CF_IDENT_ANY
83 * can be used to match any ident2 value.
84 * @return
85 * - The first matching item.
86 * - NULL if no items matched.
87 */
88static CONF_ITEM *cf_find(CONF_ITEM const *parent, CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
89{
90 CONF_SECTION cs_find;
91 CONF_PAIR cp_find;
92 CONF_DATA cd_find;
93 CONF_ITEM *find;
94
95 if (!parent) return NULL;
96 if (cf_item_has_no_children(parent)) return NULL;
97
98 if (!ident1) return cf_next(parent, NULL, type);
99
100 switch (type) {
102 memset(&cs_find, 0, sizeof(cs_find));
103 cs_find.item.type = CONF_ITEM_SECTION;
104 cs_find.name1 = ident1;
105 if (!IS_WILDCARD(ident2)) cs_find.name2 = ident2;
106
107 find = (CONF_ITEM *)&cs_find;
108 break;
109
110 case CONF_ITEM_PAIR:
111 fr_assert((ident2 == NULL) || IS_WILDCARD(ident2));
112
113 memset(&cp_find, 0, sizeof(cp_find));
114 cp_find.item.type = CONF_ITEM_PAIR;
115 cp_find.attr = ident1;
116
117 find = (CONF_ITEM *)&cp_find;
118 break;
119
120 case CONF_ITEM_DATA:
121 memset(&cd_find, 0, sizeof(cd_find));
122 cd_find.item.type = CONF_ITEM_DATA;
123 cd_find.type = ident1;
124 if (!IS_WILDCARD(ident2)) cd_find.name = ident2;
125
126 find = (CONF_ITEM *)&cd_find;
127 break;
128
129 default:
130 fr_assert_fail(NULL);
131 return NULL;
132 }
133
134 /*
135 * No ident1, iterate over the child list
136 */
137 if (IS_WILDCARD(ident1)) {
139 if (find->type != ci->type) continue;
140
141 if (cf_ident2_cmp(find, ci) == 0) return ci;
142 }
143
144 return NULL;
145 }
146
147 /*
148 * No ident2, use the ident1 tree. The tree itself may be
149 * NULL when the parent has only had non-indexed children
150 * added (e.g. CONF_COMMENT items don't populate the rbtree).
151 */
152 if (IS_WILDCARD(ident2)) {
153 if (!parent->ident1) return NULL;
154 return fr_rb_find(parent->ident1, find);
155 }
156
157 /*
158 * Only sections have an ident2 tree.
159 */
160 if (parent->type != CONF_ITEM_SECTION) return NULL;
161
162 /*
163 * Both ident1 and ident2 use the ident2 tree. As above,
164 * the tree may be NULL when only non-indexed children exist.
165 */
166 if (!parent->ident2) return NULL;
167 return fr_rb_find(parent->ident2, find);
168}
169
170/** Return the next child that's of the specified type with the specified identifiers
171 *
172 * @param[in] parent The section we're searching in.
173 * @param[in] prev item we found, or NULL to start from the beginning.
174 * @param[in] type of #CONF_ITEM we're searching for.
175 * @param[in] ident1 The first identifier.
176 * @param[in] ident2 The second identifier. Special value CF_IDENT_ANY
177 * can be used to match any ident2 value.
178 * @return
179 * - The first matching item.
180 * - NULL if no items matched.
181 */
182static CONF_ITEM *cf_find_next(CONF_ITEM const *parent, CONF_ITEM const *prev,
183 CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
184{
185 CONF_SECTION cs_find;
186 CONF_PAIR cp_find;
187 CONF_DATA cd_find;
188 CONF_ITEM *find;
189
190 if (!parent) return NULL;
191
192 if (!prev) {
193 if (!ident1) return cf_next(parent, NULL, type);
194 return cf_find(parent, type, ident1, ident2);
195 }
196 if (!ident1) return cf_next(parent, prev, type);
197
198 switch (type) {
200 memset(&cs_find, 0, sizeof(cs_find));
201 cs_find.item.type = CONF_ITEM_SECTION;
202 cs_find.name1 = ident1;
203 if (!IS_WILDCARD(ident2)) cs_find.name2 = ident2;
204
205 find = (CONF_ITEM *)&cs_find;
206 break;
207
208 case CONF_ITEM_PAIR:
209 fr_assert((ident2 == NULL) || IS_WILDCARD(ident2));
210
211 memset(&cp_find, 0, sizeof(cp_find));
212 cp_find.item.type = CONF_ITEM_PAIR;
213 cp_find.attr = ident1;
214
215 find = (CONF_ITEM *)&cp_find;
216 break;
217
218 case CONF_ITEM_DATA:
219 memset(&cd_find, 0, sizeof(cd_find));
220 cd_find.item.type = CONF_ITEM_DATA;
221 cd_find.type = ident1;
222 if (!IS_WILDCARD(ident2)) cd_find.name = ident2;
223
224 find = (CONF_ITEM *)&cd_find;
225 break;
226
227 default:
228 fr_assert_fail(NULL);
229 return NULL;
230 }
231
232 if (IS_WILDCARD(ident1)) {
233 cf_item_foreach_next(parent, ci, prev) {
234 if (find->type != ci->type) continue;
235
236 if (cf_ident2_cmp(find, ci) == 0) return ci;
237 }
238
239 return NULL;
240 }
241
242 if (IS_WILDCARD(ident2)) {
243 cf_item_foreach_next(parent, ci, prev) {
244 if (_cf_ident1_cmp(ci, find) == 0) return ci;
245
246 }
247
248 return NULL;
249 }
250
251 cf_item_foreach_next(parent, ci, prev) {
252 if (_cf_ident2_cmp(ci, find) == 0) return ci;
253 }
254
255 return NULL;
256}
257
258/** Compare the first identifier of a child
259 *
260 * For CONF_ITEM_PAIR this is 'attr'.
261 * For CONF_ITEM_SECTION this is 'name1'.
262 * For CONF_ITEM_DATA this is 'type'.
263 *
264 * @param[in] one First CONF_ITEM to compare.
265 * @param[in] two Second CONF_ITEM to compare.
266 * @return CMP(one, two)
267 */
268static inline int8_t _cf_ident1_cmp(void const *one, void const *two)
269{
270 int ret;
271
273
274 {
275 CONF_ITEM const *a = one;
276 CONF_ITEM const *b = two;
277
278 CMP_RETURN(a, b, type);
279 type = a->type;
280 }
281
282 switch (type) {
283 case CONF_ITEM_PAIR:
284 {
285 CONF_PAIR const *a = one;
286 CONF_PAIR const *b = two;
287
288 ret = strcmp(a->attr, b->attr);
289 return CMP(ret, 0);
290 }
291
293 {
294 CONF_SECTION const *a = one;
295 CONF_SECTION const *b = two;
296
297 ret = strcmp(a->name1, b->name1);
298 return CMP(ret, 0);
299 }
300
301 case CONF_ITEM_DATA:
302 {
303 CONF_DATA const *a = one;
304 CONF_DATA const *b = two;
305
306 ret = strcmp(a->type, b->type);
307 return CMP(ret, 0);
308 }
309
310 default:
311 fr_assert_fail(NULL);
312 return 0;
313 }
314}
315
316/** Compare only the second identifier of a child
317 *
318 * For CONF_ITEM_SECTION this is 'name2'.
319 * For CONF_ITEM_DATA this is 'name'.
320 *
321 * @param[in] one First CONF_ITEM to compare.
322 * @param[in] two Second CONF_ITEM to compare.
323 * @return CMP(one,two)
324 */
325static inline int8_t cf_ident2_cmp(void const *one, void const *two)
326{
327 CONF_ITEM const *ci = one;
328 int ret;
329
330 switch (ci->type) {
331 case CONF_ITEM_PAIR:
332 return 0;
333
335 {
336 CONF_SECTION const *a = one;
337 CONF_SECTION const *b = two;
338
339 if (!b->name2 && a->name2) return +1;
340 if (b->name2 && !a->name2) return -1;
341 if (!b->name2 && !a->name2) return 0;
342
343 ret = strcmp(a->name2, b->name2);
344 return CMP(ret, 0);
345 }
346
347 case CONF_ITEM_DATA:
348 {
349 CONF_DATA const *a = one;
350 CONF_DATA const *b = two;
351
352 if (!b->name && a->name) return +1;
353 if (b->name && !a->name) return -1;
354 if (!b->name && !a->name) return 0;
355
356 ret = strcmp(a->name, b->name);
357 return CMP(ret, 0);
358 }
359
360 default:
361 fr_assert_fail(NULL);
362 return 0;
363 }
364}
365
366/** Compare the first and second identifiers of a child
367 *
368 * For CONF_ITEM_SECTION this is 'name2'.
369 * For CONF_ITEM_DATA this is 'name'.
370 *
371 * @param[in] a First CONF_ITEM to compare.
372 * @param[in] b Second CONF_ITEM to compare.
373 * @return CMP(a, b)
374 */
375static int8_t _cf_ident2_cmp(void const *a, void const *b)
376{
377 int ret;
378
379 ret = _cf_ident1_cmp(a, b);
380 if (ret != 0) return ret;
381
382 return cf_ident2_cmp(a, b);
383}
384
385/** Add a child
386 *
387 * @param[in] parent to add child to.
388 * @param[in] child to add.
389 */
391{
392 fr_assert(parent != child);
393
394 if (!parent || !child) return;
395
396 /*
397 * New child, add child trees.
398 */
399 if (!parent->ident1) parent->ident1 = fr_rb_inline_alloc(parent, CONF_ITEM, ident1_node,
400 _cf_ident1_cmp, NULL);
401 fr_rb_insert(parent->ident1, child);
402 fr_dlist_insert_tail(&parent->children, child); /* Append to the list of children */
403
404 if (parent->type != CONF_ITEM_SECTION) return; /* Only sections can have ident2 trees */
405
406 if (!parent->ident2) parent->ident2 = fr_rb_inline_alloc(parent, CONF_ITEM, ident2_node,
407 _cf_ident2_cmp, NULL);
408 fr_rb_insert(parent->ident2, child); /* NULL ident2 is still a value */
409}
410
411/** Insert a child after a given one
412 *
413 * @param[in] parent to add child to.
414 * @param[in] prev previous
415 * @param[in] child to add.
416 */
418{
419 fr_assert(parent != child);
420 fr_assert(prev != child);
421
422 /*
423 * Must be given something. Can't insert at HEAD.
424 */
425 if (!parent || !child) return;
426
427 if (!prev) {
428 cf_item_add(parent, child);
429 return;
430 }
431
432 /*
433 * If there's a prev, then the ident trees must be there.
434 */
435 fr_assert(parent->ident1 != NULL);
436
437 fr_rb_insert(parent->ident1, child);
438 fr_dlist_insert_after(&parent->children, prev, child); /* insert in the list of children */
439
440 if (parent->type != CONF_ITEM_SECTION) return; /* only sections can have ident2 trees */
441
442 fr_assert(parent->ident2 != NULL);
443 fr_rb_insert(parent->ident2, child); /* NULL ident2 is still a value */
444}
445
446
447/** Remove item from parent and fixup trees
448 *
449 * @param[in] parent to remove child from.
450 * @param[in] child to remove.
451 * @return
452 * - The previous item (makes iteration easier)
453 * - NULL if the item wasn't set.
454 */
456{
457 CONF_ITEM *found = NULL;
458 CONF_ITEM *prev;
459 bool in_ident1, in_ident2;
460
461 if (!parent || cf_item_has_no_children(parent)) return NULL;
462 if (parent != child->parent) return NULL;
463
465 if (ci == child) {
466 found = ci;
467 break;
468 }
469 }
470
471 if (!found) return NULL;
472
473 /*
474 * Fixup the linked list
475 */
476 prev = fr_dlist_remove(&parent->children, child);
477
478 in_ident1 = (fr_rb_remove_by_inline_node(parent->ident1, &child->ident1_node) != NULL);
479
480 /*
481 * Only sections can have ident2 trees.
482 */
483 if (parent->type != CONF_ITEM_SECTION) {
484 in_ident2 = false;
485 } else {
486 in_ident2 = (fr_rb_remove_by_inline_node(parent->ident2, &child->ident2_node) != NULL);
487 }
488
489 /*
490 * Look for twins. They weren't in the tree initially,
491 * because "child" was there.
492 */
494 if (!in_ident1 && !in_ident2) break;
495
496 if (in_ident1 && (_cf_ident1_cmp(ci, child) == 0)) {
497 fr_rb_insert(parent->ident1, ci);
498 in_ident1 = false;
499 }
500
501 if (in_ident2 && (_cf_ident2_cmp(ci, child) == 0)) {
502 fr_rb_insert(parent->ident2, ci);
503 in_ident2 = false;
504 }
505 }
506
507 return prev;
508}
509
510/** Return the next child of the CONF_ITEM
511 *
512 * @param[in] parent to return children from.
513 * @param[in] curr child to start searching from.
514 * @return
515 * - The next #CONF_ITEM that's a child of cs.
516 * - NULL if no more #CONF_ITEM.
517 */
519{
520 if (!parent) return NULL;
521
522 return fr_dlist_next(&parent->children, curr);
523}
524
525/** Return the next child of cs
526 *
527 * @param[in] ci to return children from.
528 * @param[in] curr child to start searching from.
529 * @return
530 * - The next #CONF_ITEM that's a child of cs.
531 * - NULL if no more #CONF_ITEM.
532 */
534{
535 if (!ci) return NULL;
536
537 return fr_dlist_prev(&ci->children, curr);
538}
539
540/** Initialize a CONF_ITEM, so we don't have repeated code
541 *
542 * @param[in] ci the CONF_ITEM to initialize
543 * @param[in] type the type to set
544 * @param[in] parent the parent node hosting this one
545 * @param[in] filename which caused this node to be created
546 * @param[in] lineno where in the filename
547 */
548static void cf_item_init(CONF_ITEM *ci, CONF_ITEM_TYPE type, CONF_ITEM *parent, char const *filename, int lineno)
549{
550 ci->type = type;
551 ci->parent = parent;
552
553 fr_dlist_init(&ci->children, CONF_ITEM, entry);
554
555 if (filename) cf_filename_set(ci, filename);
556 if (lineno) cf_lineno_set(ci, lineno);
557}
558
559/** Return the top level #CONF_SECTION holding all other #CONF_ITEM
560 *
561 * @param[in] ci to traverse up from.
562 * @return
563 * - NULL if ci was NULL.
564 * - The top level #CONF_SECTION
565 */
567{
568 CONF_ITEM const *ci_p;
569
570 if (!ci) return NULL;
571
572 for (ci_p = ci; ci_p->parent; ci_p = ci_p->parent);
573
574 return cf_item_to_section(ci_p);
575}
576
577/** Return the parent of a #CONF_ITEM
578 *
579 * @param[in] ci to return the parent of.
580 * @return
581 * - NULL if ci was NULL or it has no parents.
582 * - The parent of ci.
583 */
585{
586 if (!ci) return NULL;
587
588 return ci->parent;
589}
590
591/** Return the lineno the #CONF_ITEM was parsed at
592 *
593 * @param[in] ci to return the location of.
594 * @return
595 * - -1 if the #CONF_ITEM was created programmatically.
596 * - >= 0 where in the config file the line was parsed from.
597 */
598int _cf_lineno(CONF_ITEM const *ci)
599{
600 if (!ci) return -1;
601
602 return ci->lineno;
603}
604
605/** Return the filename the #CONF_ITEM was parsed in
606 *
607 * @param[in] ci to return the location of.
608 * @return
609 * - NULL if the #CONF_ITEM was created programmatically.
610 * - The path of the config file the #CONF_ITEM was located in.
611 */
612char const *_cf_filename(CONF_ITEM const *ci)
613{
614 if (!ci) return NULL;
615
616 return ci->filename;
617}
618
619/** Determine if #CONF_ITEM is a #CONF_SECTION
620 *
621 * @param[in] ci to check.
622 * @return
623 * - true if ci is a #CONF_SECTION.
624 * - false if ci is another specialisation.
625 */
627{
628 if (!ci) return false;
629
630 return ci->type == CONF_ITEM_SECTION;
631}
632
633/** Determine if #CONF_ITEM is a #CONF_PAIR
634 *
635 * @param[in] ci to check.
636 * @return
637 * - true if ci is a #CONF_PAIR.
638 * - false if ci is another specialisation.
639 */
641{
642 if (!ci) return false;
643
644 return ci->type == CONF_ITEM_PAIR;
645}
646
647/** Determine if #CONF_ITEM is #CONF_DATA
648 *
649 * @param[in] ci to check.
650 * @return
651 * - true if ci is #CONF_DATA.
652 * - false if ci is another specialisation.
653 */
655{
656 if (!ci) return false;
657
658 return ci->type == CONF_ITEM_DATA;
659}
660
661/** Cast a #CONF_ITEM to a #CONF_PAIR
662 *
663 * @note Will assert if ci does not contain #CONF_PAIR.
664 *
665 * @param[in] ci to cast.
666 * @return
667 * - #CONF_PAIR.
668 * - NULL if ci was NULL.
669 *
670 * @hidecallergraph
671 */
673{
674 if (ci == NULL) return NULL;
675
677
678 return UNCONST(CONF_PAIR *, ci);
679}
680
681/** Cast a #CONF_ITEM to a #CONF_SECTION
682 *
683 * @note Will assert if ci does not contain #CONF_SECTION.
684 *
685 * @param[in] ci to cast.
686 * @return
687 * - #CONF_SECTION.
688 * - NULL if ci was NULL.
689 *
690 * @hidecallergraph
691 */
693{
694 if (ci == NULL) return NULL;
695
697
698 return UNCONST(CONF_SECTION *, ci);
699}
700
701/** Cast #CONF_ITEM to #CONF_DATA performing a type check
702 *
703 * @note Will assert if ci does not contain #CONF_DATA.
704 *
705 * @param[in] ci to cast.
706 * @return
707 * - #CONF_DATA.
708 * - NULL if ci was NULL.
709 *
710 * @hidecallergraph
711 */
713{
714 if (ci == NULL) return NULL;
715
717
718 return UNCONST(CONF_DATA *, ci);
719}
720
721/** Cast a #CONF_PAIR to a #CONF_ITEM
722 *
723 * @param[in] cp to cast.
724 * @return
725 * - The common #CONF_ITEM header.
726 * - NULL if cp was NULL.
727 *
728 * @hidecallergraph
729 */
731{
732 if (cp == NULL) return NULL;
733
734 return UNCONST(CONF_ITEM *, cp);
735}
736
737/** Cast a #CONF_SECTION to a #CONF_ITEM
738 *
739 * @param[in] cs to cast.
740 * @return
741 * - The common #CONF_ITEM header.
742 * - NULL if cs was NULL.
743 *
744 * @hidecallergraph
745 */
747{
748 if (cs == NULL) return NULL;
749
750 return UNCONST(CONF_ITEM *, cs);
751}
752
753/** Cast #CONF_DATA to a #CONF_ITEM
754 *
755 * @param[in] cd to cast.
756 * @return
757 * - The common #CONF_ITEM header.
758 * - NULL if cd was NULL.
759 *
760 * @hidecallergraph
761 */
763{
764 if (cd == NULL) return NULL;
765
766 return UNCONST(CONF_ITEM *, cd);
767}
768
769/** Determine if #CONF_ITEM is a #CONF_COMMENT.
770 */
772{
773 if (!ci) return false;
774 return ci->type == CONF_ITEM_COMMENT;
775}
776
777/** Cast a #CONF_ITEM to a #CONF_COMMENT (asserts on type mismatch).
778 */
780{
781 if (ci == NULL) return NULL;
783 return UNCONST(CONF_COMMENT *, ci);
784}
785
786/** Cast a #CONF_COMMENT back to a #CONF_ITEM.
787 */
789{
790 if (c == NULL) return NULL;
791 return UNCONST(CONF_ITEM *, c);
792}
793
794char const *cf_comment_text(CONF_COMMENT const *c)
795{
796 if (c == NULL) return NULL;
797 return c->text;
798}
799
800/*
801 * Off by default - the runtime server parser drops comments as it
802 * always has. Utilities call cf_preserve_comments_set() before
803 * cf_file_read() when they want the round-trip.
804 */
805static bool cf_preserve_comments = false;
806
807void cf_preserve_comments_set(bool preserve)
808{
809 cf_preserve_comments = preserve;
810}
811
812/*
813 * Private getter declared in cf_priv.h for cf_file.c's parser hook.
814 * Keeps cf_preserve_comments truly private to cf_util.c; the public
815 * API is the setter.
816 */
818{
820}
821
822/*
823 * On by default - the runtime parser always wants `${foo}` resolved
824 * to the value of `foo`. Tools like radjson2conf, which build a
825 * tree from JSON and write it back out, flip this off so values
826 * containing `${...}` round-trip verbatim instead of being resolved
827 * against an incomplete fragment tree. $INCLUDE is a separate code
828 * path and is unaffected.
829 */
830static bool cf_expand_vars = true;
831
832void cf_expand_variables_set(bool expand)
833{
834 cf_expand_vars = expand;
835}
836
838{
839 return cf_expand_vars;
840}
841
843{
844 CONF_COMMENT *c;
845
846 if (!parent) return NULL;
847
848 c = talloc_zero(parent, CONF_COMMENT);
849 if (!c) return NULL;
850
852 cf_section_to_item(parent), NULL, 0);
853
854 c->text = text ? talloc_strdup(c, text) : NULL;
855
856 /*
857 * Append to the parent's ordered children list, but do NOT
858 * insert into ident1 / ident2 trees - comments aren't
859 * name-keyed and shouldn't show up in cf_pair_find / cf_section_find.
860 */
861 fr_dlist_insert_tail(&parent->item.children, &c->item);
862 return c;
863}
864
865/** Free a section and associated trees
866 *
867 * @param[in] cs to free.
868 * @return 0
869 */
871{
872 if (cs->item.ident1) TALLOC_FREE(cs->item.ident1);
873 if (cs->item.ident2) TALLOC_FREE(cs->item.ident2);
874
875 return 0;
876}
877
878/** Allocate a #CONF_SECTION
879 *
880 * @param[in] ctx to allocate
881 * @param[in] parent #CONF_SECTION to hang this #CONF_SECTION off of.
882 * If parent is not NULL, the new section will be added as a child.
883 * @param[in] name1 Primary name.
884 * @param[in] name2 Secondary name.
885 * @param[in] filename Caller file name for debugging. May be overridden later.
886 * @param[in] lineno Caller line number for debugging. May be overridden later.
887 * @return
888 * - NULL on error.
889 * - A new #CONF_SECTION parented by parent.
890 */
892 char const *name1, char const *name2,
893 char const *filename, int lineno)
894{
895 CONF_SECTION *cs;
896 char buffer[1024];
897
898 if (!name1) return NULL;
899
900 if (name2 && parent) {
901 char const *p;
902
903 p = strchr(name2, '$');
904 if (p && (p[1] != '{')) p = NULL;
905
906 if (p) {
907 name2 = cf_expand_variables(parent->item.filename,
908 parent->item.lineno,
909 parent,
910 buffer, sizeof(buffer), name2, -1, NULL, false);
911
912 if (!name2) {
913 ERROR("Failed expanding section name");
914 return NULL;
915 }
916 }
917 }
918
919 cs = talloc_zero(ctx, CONF_SECTION);
920 if (!cs) return NULL;
921
923
924 MEM(cs->name1 = talloc_strdup(cs, name1));
925 if (name2) {
926 MEM(cs->name2 = talloc_strdup(cs, name2));
928 }
929 talloc_set_destructor(cs, _cf_section_free);
930
931 if (parent) {
932 CONF_DATA const *cd;
933 conf_parser_t *rule;
934
935 /*
936 * Look up the parents parsing rules for itself.
937 * If there are rules, then one of them might be
938 * parsing rules for this new child. If that
939 * happens, we push the child parsing rules to
940 * this new child.
941 */
943 if (cd) {
944 rule = cf_data_value(cd);
945
946 if ((rule->flags & CONF_FLAG_SUBSECTION) &&
947 rule->on_read && rule->subcs) {
948 conf_parser_t const *rule_p;
949
950 for (rule_p = rule->subcs; rule_p->name1; rule_p++) {
951 if ((rule_p->flags & CONF_FLAG_SUBSECTION) &&
952 rule_p->on_read &&
953 (strcmp(rule_p->name1, name1) == 0)) {
954 if (_cf_section_rule_push(cs, rule_p,
955 cd->item.filename, cd->item.lineno) < 0) {
956 error:
957 talloc_free(cs);
958 return NULL;
959 }
960
961 if (rule_p->on_read(ctx, NULL, NULL,
962 cf_section_to_item(cs), rule_p) < 0) goto error;
963 goto done;
964 }
965 }
966 }
967 }
968
969 /*
970 * Or, the parent may already have parse rules
971 * for this new child. In which case we push the
972 * child rules for this section, and then do the
973 * on_read callback.
974 */
976 if (cd) {
977 rule = cf_data_value(cd);
978 if ((rule->flags & CONF_FLAG_SUBSECTION) &&
979 rule->on_read) {
980 if (cf_section_rules_push(cs, rule->subcs) < 0) goto error;
981 if (rule->on_read(ctx, NULL, NULL, cf_section_to_item(cs), rule) < 0) goto error;
982 }
983 }
984
985 done:
986 cs->depth = parent->depth + 1;
987 cf_item_add(parent, &(cs->item));
988 }
989
990 return cs;
991}
992
993/** Set the filename of a #CONF_ITEM
994 *
995 * @param[in] ci to set filename on.
996 * @param[in] filename to set.
997 */
998void _cf_filename_set(CONF_ITEM *ci, char const *filename)
999{
1001
1002 ci->filename = talloc_strdup(ci, filename);
1003}
1004
1005/** Set the line number of a #CONF_ITEM
1006 *
1007 * @param[in] ci to set the lineno for.
1008 * @param[in] lineno to set.
1009 */
1010void _cf_lineno_set(CONF_ITEM *ci, int lineno)
1011{
1012 ci->lineno = lineno;
1013}
1014
1015/** Duplicate a configuration section
1016 *
1017 * @note recursively duplicates any child sections.
1018 * @note does not duplicate any data associated with a section, or its child sections.
1019 *
1020 * @param[in] ctx to allocate memory in.
1021 * @param[in] parent section (may be NULL).
1022 * @param[in] cs to duplicate.
1023 * @param[in] name1 of new section.
1024 * @param[in] name2 of new section.
1025 * @param[in] copy_meta Copy additional meta data for a section
1026 * (like template, base, depth, parsed state,
1027 * and variables).
1028 * @return
1029 * - A duplicate of the existing section.
1030 * - NULL on error.
1031 */
1033 char const *name1, char const *name2, bool copy_meta)
1034{
1035 CONF_SECTION *out, *dst;
1036 CONF_SECTION const *src;
1037 CONF_ITEM const *ci;
1038
1039 /*
1040 * Create the new output section.
1041 */
1042 out = cf_section_alloc(ctx, parent, name1, name2);
1043
1044 if (copy_meta) {
1045 out->template = cs->template;
1046 out->base = cs->base;
1047 out->depth = cs->depth;
1048 }
1049
1052
1053 /*
1054 * Start copying children of the input.
1055 */
1056 src = cs;
1057 ci = NULL;
1058 dst = out;
1059
1060 /*
1061 * Do this iteratively, because it's nicer than using the C stack.
1062 */
1063 while (true) {
1064 CONF_SECTION *src_child, *dst_child;
1065 CONF_PAIR *cp;
1066
1067 /*
1068 * Go to the next child. If there is none, then try to go back up to the parent.
1069 */
1070 ci = fr_dlist_next(&src->item.children, ci);
1071 if (!ci) {
1072 /*
1073 * We're back at the top, and we have no more children. We can stop looping.
1074 */
1075 if (src == cs) break;
1076
1077 /*
1078 * The current child is what we were just copying. The parent is now the childs
1079 * parent.
1080 */
1081 ci = &src->item;
1082 src = cf_item_to_section(src->item.parent);
1083 dst = cf_item_to_section(dst->item.parent);
1084 continue;
1085 }
1086
1087 fr_assert(ci != cf_section_to_item(cs));
1089
1090 switch (ci->type) {
1091 case CONF_ITEM_SECTION:
1092 src_child = cf_item_to_section(ci);
1093 dst_child = cf_section_alloc(dst, dst, src_child->name1, src_child->name2);
1094 if (!dst_child) {
1095 oom:
1097 return NULL;
1098 }
1099
1100 if (copy_meta) {
1101 dst_child->template = src_child->template;
1102 dst_child->base = src_child->base;
1103 dst_child->depth = src_child->depth;
1104 }
1105
1106 dst_child->item.filename = src_child->item.filename;
1107 dst_child->item.lineno = src_child->item.lineno;
1108
1109 /*
1110 * Descend into the child so its children get copied too.
1111 */
1112 src = src_child;
1113 dst = dst_child;
1114 ci = NULL;
1115 continue;
1116
1117 case CONF_ITEM_PAIR:
1118 cp = cf_pair_dup(dst, cf_item_to_pair(ci), copy_meta);
1119 if (!cp) goto oom;
1120 break;
1121
1122 case CONF_ITEM_DATA: /* Skip data */
1123 break;
1124
1125 case CONF_ITEM_COMMENT:
1126 /*
1127 * Preserve comment lines when duplicating a section -
1128 * it costs almost nothing and round-tripping utilities
1129 * stay correct.
1130 */
1131 {
1132 CONF_COMMENT const *src_co = cf_item_to_comment(ci);
1133 CONF_COMMENT *dst_co = cf_comment_alloc(dst, src_co->text);
1134
1135 if (!dst_co) goto oom;
1136
1137 cf_filename_set(dst_co, src_co->item.filename);
1138 cf_lineno_set(dst_co, src_co->item.lineno);
1139 }
1140 break;
1141
1142 case CONF_ITEM_INVALID:
1143 fr_assert(0);
1144 }
1145 }
1146
1147 return out;
1148}
1149
1150/** Return the first child in a CONF_SECTION
1151 *
1152 * @param[in] cs to return children from.
1153 * @return
1154 * - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
1155 * - NULL if no #CONF_ITEM matches that criteria.
1156 */
1161
1162/** Return the next child that's a #CONF_SECTION
1163 *
1164 * @param[in] cs to return children from.
1165 * @param[in] curr child to start searching from.
1166 * @return
1167 * - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
1168 * - NULL if no #CONF_ITEM matches that criteria.
1169 */
1174
1175/** Return the previous child that's a #CONF_SECTION
1176 *
1177 * @param[in] cs to return children from.
1178 * @param[in] curr child to start searching from.
1179 * @return
1180 * - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
1181 * - NULL if no #CONF_ITEM matches that criteria.
1182 */
1187
1188/** Find a CONF_SECTION with name1 and optionally name2.
1189 *
1190 * @param[in] cs The section we're searching in.
1191 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1192 * can be used to match any name1 value.
1193 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1194 * can be used to match any name2 value.
1195 * @return
1196 * - The first matching subsection.
1197 * - NULL if no subsections match.
1198 *
1199 * @hidecallergraph
1200 */
1202 char const *name1, char const *name2)
1203{
1205}
1206
1207/** Return the next matching section
1208 *
1209 * @param[in] cs The section we're searching in.
1210 * @param[in] prev section we found. May be NULL in which case
1211 * we just return the next section after prev.
1212 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1213 * can be used to match any name1 value.
1214 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1215 * can be used to match any name2 value.
1216 * @return
1217 * - The next CONF_SECTION.
1218 * - NULL if there are no more CONF_SECTIONs
1219 *
1220 * @hidecallergraph
1221 */
1223 char const *name1, char const *name2)
1224{
1226 CONF_ITEM_SECTION, name1, name2));
1227}
1228
1229/** Find an ancestor of the passed CONF_ITEM which has a child matching a specific name1 and optionally name2.
1230 *
1231 * @note Despite the name, this function also searches in ci for a matching item.
1232 *
1233 * Will walk up the configuration tree, searching in each parent until a matching section is found or
1234 * we hit the root.
1235 *
1236 * @param[in] ci The conf item we're searching back from.
1237 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1238 * can be used to match any name1 value.
1239 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1240 * can be used to match any name2 value.
1241 * @return
1242 * - The first matching subsection.
1243 * - NULL if no subsections match.
1244 */
1246 char const *name1, char const *name2)
1247{
1248 do {
1249 CONF_ITEM *found;
1250
1251 found = cf_find(ci, CONF_ITEM_SECTION, name1, name2);
1252 if (found) return cf_item_to_section(found);
1253 } while ((ci = cf_parent(ci)));
1254
1255 return NULL;
1256}
1257
1258/** Find a parent CONF_SECTION with name1 and optionally name2.
1259 *
1260 * @param[in] ci The section we're searching in.
1261 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1262 * can be used to match any name1 value.
1263 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1264 * can be used to match any name2 value.
1265 * @return
1266 * - The first matching subsection.
1267 * - NULL if no subsections match.
1268 */
1270 char const *name1, char const *name2)
1271{
1272 while ((ci = cf_parent(ci))) {
1273 CONF_SECTION *found;
1274
1275 if (!cf_item_is_section(ci)) continue; /* Could be data hanging off a pair*/
1276
1277 found = cf_item_to_section(ci);
1278
1279 if (cf_section_name_cmp(found, name1, name2) == 0) return found;
1280 }
1281
1282 return NULL;
1283}
1284
1285/** Find a pair in a #CONF_SECTION
1286 *
1287 * @param[in] cs the #CONF_SECTION to search in.
1288 * @param[in] attr to search for.
1289 * @return
1290 * - NULL if no pair can be found.
1291 * - The value of the pair found.
1292 */
1293char const *cf_section_value_find(CONF_SECTION const *cs, char const *attr)
1294{
1295 CONF_PAIR *cp;
1296
1297 cp = cf_pair_find(cs, attr);
1298
1299 return (cp ? cp->value : NULL);
1300}
1301
1302/** Check if a given section matches the specified name1/name2 identifiers
1303 *
1304 * @param[in] cs to check.
1305 * @param[in] name1 identifier. May be CF_IDENT_ANY for wildcard matches.
1306 * @param[in] name2 identifier. May be CF_IDENT_ANY for wildcard matches.
1307 * @return
1308 * - >1 if cs is greater than the identifiers.
1309 * - 0 if cs matches the identifiers.
1310 * - <0 if cs is less than the identifiers.
1311 */
1312int8_t cf_section_name_cmp(CONF_SECTION const *cs, char const *name1, char const *name2)
1313{
1314 int8_t ret;
1315
1316 if (name1 != CF_IDENT_ANY) {
1317 ret = CMP(strcmp(cf_section_name1(cs), name1), 0);
1318 if (ret != 0) return ret;
1319 }
1320
1321 if (name2 != CF_IDENT_ANY) {
1322 char const *cs_name2 = cf_section_name2(cs);
1323
1324 if (!cs_name2) {
1325 if (!name2) return 0;
1326 return 1;
1327 }
1328 if (!name2) return -1;
1329
1330 return CMP(strcmp(cs_name2, name2), 0);
1331 }
1332
1333 return 0;
1334}
1335
1336/** Return the first identifier of a #CONF_SECTION
1337 *
1338 * @param[in] cs to return identifiers for.
1339 * @return
1340 * - The first identifier.
1341 * - NULL if cs was NULL or no name1 set.
1342 *
1343 * @hidecallergraph
1344 */
1345char const *cf_section_name1(CONF_SECTION const *cs)
1346{
1347 return (cs ? cs->name1 : NULL);
1348}
1349
1350/** Return the second identifier of a #CONF_SECTION
1351 *
1352 * @param[in] cs to return identifiers for.
1353 * @return
1354 * - The second identifier.
1355 * - NULL if cs was NULL or no name2 set.
1356 *
1357 * @hidecallergraph
1358 */
1359char const *cf_section_name2(CONF_SECTION const *cs)
1360{
1361 return (cs ? cs->name2 : NULL);
1362}
1363
1364/** Return name2 if set, else name1
1365 *
1366 * @param[in] cs to return identifiers for.
1367 * @return name1 or name2 identifier.
1368 *
1369 * @hidecallergraph
1370 */
1371char const *cf_section_name(CONF_SECTION const *cs)
1372{
1373 char const *name;
1374
1375 name = cf_section_name2(cs);
1376 if (name) return name;
1377
1378 return cf_section_name1(cs);
1379}
1380
1381/** Return variadic argument at the specified index
1382 *
1383 * @param[in] cs containing the arguments.
1384 * @param[in] argc Argument index. Note name1 and name2 are not counted in this index.
1385 * @return the argument value or NULL.
1386 */
1387char const *cf_section_argv(CONF_SECTION const *cs, int argc)
1388{
1389 if (!cs || !cs->argv || (argc < 0) || (argc >= cs->argc)) return NULL;
1390
1391 return cs->argv[argc];
1392}
1393
1394/** Return the quoting of the name2 identifier
1395 *
1396 * @param[in] cs containing name2.
1397 * @return
1398 * - #T_BARE_WORD.
1399 * - #T_SINGLE_QUOTED_STRING.
1400 * - #T_BACK_QUOTED_STRING.
1401 * - #T_DOUBLE_QUOTED_STRING.
1402 * - #T_INVALID if cs was NULL.
1403 */
1405{
1406 if (!cs) return T_INVALID;
1407
1408 return cs->name2_quote;
1409}
1410
1411/** Return the quoting for one of the variadic arguments
1412 *
1413 * @param[in] cs containing the arguments.
1414 * @param[in] argc Argument index. Note name1 and name2 are not counted in this index.
1415 * @return
1416 * - #T_BARE_WORD.
1417 * - #T_SINGLE_QUOTED_STRING.
1418 * - #T_BACK_QUOTED_STRING.
1419 * - #T_DOUBLE_QUOTED_STRING.
1420 * - #T_INVALID if cs was NULL or the index was invalid.
1421 */
1423{
1424 if (!cs || !cs->argv_quote || (argc < 0) || (argc >= cs->argc)) return T_INVALID;
1425
1426 return cs->argv_quote[argc];
1427}
1428
1429/** Allocate a #CONF_PAIR
1430 *
1431 * @param[in] parent #CONF_SECTION to hang this #CONF_PAIR off of.
1432 * @param[in] attr name.
1433 * @param[in] value of #CONF_PAIR.
1434 * @param[in] op #T_OP_EQ, #T_OP_SET etc.
1435 * @param[in] lhs_quote #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
1436 * @param[in] rhs_quote #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
1437 * @return
1438 * - NULL on error.
1439 * - A new #CONF_SECTION parented by parent.
1440 */
1441CONF_PAIR *cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
1442 fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
1443{
1444 CONF_PAIR *cp;
1445
1447 if (!attr) return NULL;
1448
1449 cp = talloc_zero(parent, CONF_PAIR);
1450 if (!cp) return NULL;
1451
1453
1454 cp->lhs_quote = lhs_quote;
1455 cp->rhs_quote = rhs_quote;
1456 cp->op = op;
1457
1458 cp->attr = talloc_strdup(cp, attr);
1459 if (!cp->attr) {
1460 error:
1461 talloc_free(cp);
1462 return NULL;
1463 }
1464
1465 if (value) {
1466 cp->value = talloc_strdup(cp, value);
1467 if (!cp->value) goto error;
1468 }
1469
1470 cf_item_add(parent, &(cp->item));
1471 return cp;
1472}
1473
1474/** Duplicate a #CONF_PAIR
1475 *
1476 * @param parent to allocate new pair in.
1477 * @param cp to duplicate.
1478 * @param copy_meta Copy additional meta data for a pair
1479 * @return
1480 * - NULL on error.
1481 * - A duplicate of the input pair.
1482 */
1484{
1485 CONF_PAIR *new;
1486
1488 fr_assert(cp);
1489
1490 new = cf_pair_alloc(parent, cp->attr, cf_pair_value(cp), cp->op, cp->lhs_quote, cp->rhs_quote);
1491 if (!new) return NULL;
1492
1493 if (copy_meta) {
1494 new->item.parsed = cp->item.parsed;
1495 new->item.referenced = cp->item.referenced;
1496 }
1497 cf_lineno_set(new, cp->item.lineno);
1498 cf_filename_set(new, cp->item.filename);
1499
1500 return new;
1501}
1502
1503/** Replace pair value in a given section with the given value.
1504 *
1505 * @note A new pair with the same metadata as the #CONF_PAIR will be added
1506 * even if the #CONF_PAIR can't be found inside the #CONF_SECTION.
1507 *
1508 * @param[in] cs to replace pair in.
1509 * @param[in] cp to replace.
1510 * @param[in] value New value to assign to cp.
1511 * @return
1512 * - 0 on success.
1513 * - -1 on failure.
1514 */
1516{
1517 if (!cs || !cp || !value) return -1;
1518
1520
1521 MEM(cp->value = talloc_strdup(cp, value));
1522
1523 return 0;
1524}
1525
1526
1527/** Mark an item as parsed
1528 *
1529 * @param[in] ci to mark as parsed.
1530 */
1532{
1533 ci->parsed = true;
1534}
1535
1536/** Return whether an item has already been parsed
1537 *
1538 * @param[in] ci to check.
1539 * @return
1540 * - true if item has been parsed.
1541 * - false if the pair hasn't been parsed.
1542 */
1544{
1545 return ci->parsed;
1546}
1547
1548/** Return the first child that's a #CONF_PAIR
1549 *
1550 * @param[in] cs to return children from.
1551 * @return
1552 * - The first #CONF_ITEM that's a child of cs and a CONF_PAIR.
1553 * - NULL if no #CONF_ITEM matches that criteria.
1554 */
1559
1560/** Return the next child that's a #CONF_PAIR
1561 *
1562 * @param[in] cs to return children from.
1563 * @param[in] curr child to start searching from.
1564 * @return
1565 * - The next #CONF_ITEM that's a child of cs and a CONF_PAIR.
1566 * - NULL if no #CONF_ITEM matches that criteria.
1567 */
1572
1573/** Return the previous child that's a #CONF_PAIR
1574 *
1575 * @param[in] cs to return children from.
1576 * @param[in] curr child to start searching from.
1577 * @return
1578 * - The previous #CONF_ITEM that's a child of cs and a CONF_PAIR.
1579 * - NULL if no #CONF_ITEM matches that criteria.
1580 */
1585
1586/** Search for a #CONF_PAIR with a specific name
1587 *
1588 * @param[in] cs to search in.
1589 * @param[in] attr to find.
1590 * @return
1591 * - The next matching #CONF_PAIR.
1592 * - NULL if none matched.
1593 */
1594CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *attr)
1595{
1596 return cf_item_to_pair(cf_find(cf_section_to_item(cs), CONF_ITEM_PAIR, attr, NULL));
1597}
1598
1599/** Find a pair with a name matching attr, after specified pair
1600 *
1601 * @param[in] cs to search in.
1602 * @param[in] prev Pair to search from (may be NULL).
1603 * @param[in] attr to find (may be NULL in which case any attribute matches).
1604 * @return
1605 * - The next matching #CONF_PAIR
1606 * - NULL if none matched.
1607 */
1608CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
1609{
1611}
1612
1613/** Find a pair with a name matching attr in the specified section or one of its parents
1614 *
1615 * @param[in] cs to search in. Will start in the current section
1616 * and work upwards.
1617 * @param[in] attr to find.
1618 * @return
1619 * - A matching #CONF_PAIR.
1620 * - NULL if none matched.
1621 */
1622CONF_PAIR *cf_pair_find_in_parent(CONF_SECTION const *cs, char const *attr)
1623{
1624 CONF_ITEM const *parent = cf_section_to_item(cs);
1625
1626 do {
1627 CONF_ITEM *found;
1628
1629 found = cf_find(parent, CONF_ITEM_PAIR, attr, NULL);
1630 if (found) return cf_item_to_pair(found);
1631 } while ((parent = cf_parent(parent)));
1632
1633 return NULL;
1634}
1635
1636/** Callback to determine the number of pairs in a section
1637 *
1638 * @param[out] count Where we store the number of pairs found.
1639 * @param[in] cs we're currently searching in.
1640 */
1641static void _pair_count(int *count, CONF_SECTION const *cs)
1642{
1643 CONF_ITEM const *ci = NULL;
1644
1645 while ((ci = cf_item_next(cs, ci))) {
1646 if (cf_item_is_section(ci)) {
1648 continue;
1649 }
1650
1651 (*count)++;
1652 }
1653}
1654
1655/** Count the number of conf pairs beneath a section
1656 *
1657 * @param[in] cs to search for items in.
1658 * @return The number of pairs nested within section.
1659 */
1661{
1662 int count = 0;
1663
1664 _pair_count(&count, cs);
1665
1666 return count;
1667}
1668
1669/** Count the number of times an attribute occurs in a parent section
1670 *
1671 * @param[in] cs to search for items in.
1672 * @param[in] attr to search for.
1673 * @return The number of pairs of that attribute type.
1674 */
1675unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
1676{
1677 size_t i;
1678 CONF_PAIR *cp = NULL;
1679
1680 for (i = 0; (cp = cf_pair_find_next(cs, cp, attr)); i++);
1681
1682 return i;
1683}
1684
1685/** Concatenate the values of any pairs with name attr
1686 *
1687 * @param[out] out where to write the concatenated values.
1688 * @param[in] cs to search in.
1689 * @param[in] attr to search for.
1690 * @param[in] sep to use to separate values
1691 * @return
1692 * - Length of the data written to out on success.
1693 * - < 0 on failure. Number of additional bytes required in buffer.
1694 */
1695fr_slen_t cf_pair_values_concat(fr_sbuff_t *out, CONF_SECTION const *cs, char const *attr, char const *sep)
1696{
1697 fr_sbuff_t our_out = FR_SBUFF(out);
1698 CONF_PAIR *cp;
1699 fr_slen_t slen = 0;
1700 fr_sbuff_escape_rules_t e_rules = {
1701 .name = __FUNCTION__,
1702 .chr = '\\'
1703 };
1704
1705 if (sep) e_rules.subs[(uint8_t)*sep] = *sep;
1706
1707 for (cp = cf_pair_find(cs, attr); cp;) {
1708 char const *value = cf_pair_value(cp);
1709
1710 cp = cf_pair_find_next(cs, cp, attr);
1711
1712 if (!value) continue;
1713
1714 slen = fr_sbuff_in_escape(&our_out, value, strlen(value), &e_rules);
1715 if (slen < 0) return slen;
1716
1717 if (cp && sep) {
1718 slen = fr_sbuff_in_strcpy(&our_out, sep);
1719 if (slen < 0) return slen;
1720 }
1721 }
1722
1723 FR_SBUFF_SET_RETURN(out, &our_out);
1724}
1725
1726/** Return the attr of a #CONF_PAIR
1727 *
1728 * Return the LHS value of a pair (the attribute).
1729 *
1730 * @param[in] pair to return the attribute for.
1731 * @return
1732 * - NULL if the pair was NULL.
1733 * - The attribute name of the pair.
1734 *
1735 * @hidecallergraph
1736 */
1737char const *cf_pair_attr(CONF_PAIR const *pair)
1738{
1739 return (pair ? pair->attr : NULL);
1740}
1741
1742/** Return the value of a #CONF_PAIR
1743 *
1744 * Return the RHS value of a pair (the value).
1745 *
1746 * @param[in] pair to return the value of.
1747 * @return
1748 * - NULL if pair was NULL or the pair has no value.
1749 * - The string value of the pair.
1750 *
1751 * @hidecallergraph
1752 */
1753char const *cf_pair_value(CONF_PAIR const *pair)
1754{
1755 return (pair ? pair->value : NULL);
1756}
1757
1758/** Return the operator of a pair
1759 *
1760 * @param[in] pair to return the operator of.
1761 * @return
1762 * - T_INVALID if pair was NULL.
1763 * - T_OP_* (one of the operator constants).
1764 *
1765 * @hidecallergraph
1766 */
1768{
1769 return (pair ? pair->op : T_INVALID);
1770}
1771
1772/** Return the value (lhs) quoting of a pair
1773 *
1774 * @param pair to extract value type from.
1775 * @return
1776 * - #T_BARE_WORD.
1777 * - #T_SINGLE_QUOTED_STRING.
1778 * - #T_BACK_QUOTED_STRING.
1779 * - #T_DOUBLE_QUOTED_STRING.
1780 * - #T_INVALID if the pair is NULL.
1781 */
1783{
1784 return (pair ? pair->lhs_quote : T_INVALID);
1785}
1786
1787/** Return the value (rhs) quoting of a pair
1788 *
1789 * @param pair to extract value type from.
1790 * @return
1791 * - #T_BARE_WORD.
1792 * - #T_SINGLE_QUOTED_STRING.
1793 * - #T_BACK_QUOTED_STRING.
1794 * - #T_DOUBLE_QUOTED_STRING.
1795 * - #T_INVALID if the pair is NULL.
1796 */
1798{
1799 return (pair ? pair->rhs_quote : T_INVALID);
1800}
1801
1802/** Free user data associated with #CONF_DATA
1803 *
1804 * @param[in] cd being freed.
1805 * @return 0
1806 */
1807static int _cd_free(CONF_DATA *cd)
1808{
1809 return talloc_free(UNCONST(void *, cd->data));
1810}
1811
1812/** Allocate a new user data container
1813 *
1814 * @param[in] parent #CONF_PAIR, or #CONF_SECTION to hang CONF_DATA off of.
1815 * @param[in] data being added.
1816 * @param[in] type of data being added.
1817 * @param[in] name String identifier of the user data.
1818 * @param[in] do_free function, called when the parent #CONF_SECTION is being freed.
1819 * @return
1820 * - CONF_DATA on success.
1821 * - NULL on error.
1822 */
1823static CONF_DATA *cf_data_alloc(CONF_ITEM *parent, void const *data, char const *type, char const *name, bool do_free)
1824{
1825 CONF_DATA *cd;
1826
1827 cd = talloc_zero(parent, CONF_DATA);
1828 if (!cd) return NULL;
1829
1831
1832 /*
1833 * strdup so if the data is freed, we can
1834 * still remove it from the section without
1835 * explosions.
1836 */
1837 if (data) {
1838 cd->type = talloc_strdup(cd, type);
1839 cd->data = data;
1840 }
1841 if (name) cd->name = talloc_strdup(cd, name);
1842
1843 if (do_free) talloc_set_destructor(cd, _cd_free);
1844
1845 cf_item_add(parent, cd);
1846 return cd;
1847}
1848
1849/** Find user data in a config section
1850 *
1851 * @param[in] ci The section to search for data in.
1852 * @param[in] type of user data. Used for name spacing and walking over a specific
1853 * type of user data.
1854 * @param[in] name String identifier of the user data. Special value CF_IDENT_ANY
1855 * may be used to match on type only.
1856 * @return
1857 * - The user data.
1858 * - NULL if no user data exists.
1859 */
1860CONF_DATA const *_cf_data_find(CONF_ITEM const *ci, char const *type, char const *name)
1861{
1863}
1864
1865/** Return the next item of user data
1866 *
1867 * @param[in] ci The section to search for data in.
1868 * @param[in] prev section we found. May be NULL in which case
1869 * we just return the next section after prev.
1870 * @param[in] type of user data. Used for name spacing and walking over a specific
1871 * type of user data.
1872 * @param[in] name String identifier of the user data. Special value CF_IDENT_ANY
1873 * can be used to match any name2 value.
1874 * @return
1875 * - The next matching #CONF_DATA.
1876 * - NULL if there is no more matching #CONF_DATA.
1877 */
1878CONF_DATA const *_cf_data_find_next(CONF_ITEM const *ci, CONF_ITEM const *prev, char const *type, char const *name)
1879{
1881}
1882
1883/** Find matching data in the specified section or one of its parents
1884 *
1885 * @param[in] ci The section to search for data in.
1886 * @param[in] type of user data. Used for name spacing and walking over a specific
1887 * type of user data.
1888 * @param[in] name String identifier of the user data. Special value CF_IDENT_ANY
1889 * may be used to match on type only.
1890 * @return
1891 * - The next matching #CONF_DATA.
1892 * - NULL if there is no more matching #CONF_DATA.
1893 */
1894CONF_DATA *_cf_data_find_in_parent(CONF_ITEM const *ci, char const *type, char const *name)
1895{
1896 CONF_ITEM const *parent = ci;
1897
1898 do {
1899 CONF_ITEM *found;
1900
1902 if (found) return cf_item_to_data(found);
1903 } while ((parent = cf_parent(parent)));
1904
1905 return NULL;
1906}
1907
1908/** Return the user assigned value of #CONF_DATA
1909 *
1910 * @param[in] cd to return value of.
1911 * @return the user data stored within the #CONF_DATA.
1912 */
1913void *cf_data_value(CONF_DATA const *cd)
1914{
1915 void *to_return;
1916
1917 if (!cd) return NULL;
1918
1919 memcpy(&to_return, &cd->data, sizeof(to_return));
1920
1921 return to_return;
1922}
1923
1924/** Add talloced user data to a config section
1925 *
1926 * @param[in] ci to add data to.
1927 * @param[in] data to add.
1928 * @param[in] name String identifier of the user data.
1929 * @param[in] do_free Function to free user data when the CONF_SECTION is freed.
1930 * @param[in] filename Source file the #CONF_DATA was added in.
1931 * @param[in] lineno the #CONF_DATA was added at.
1932 * @return
1933 * - #CONF_DATA - opaque handle to the stored data - on success.
1934 * - NULL error.
1935 */
1936CONF_DATA const *_cf_data_add(CONF_ITEM *ci, void const *data, char const *name, bool do_free,
1937 char const *filename, int lineno)
1938{
1939 CONF_DATA *cd;
1940 CONF_DATA const *found;
1941 char const *type = NULL;
1942
1943 if (!ci) return NULL;
1944
1945 if (data) type = talloc_get_name(data);
1946
1947 /*
1948 * Already exists. Can't add it.
1949 */
1950 found = _cf_data_find(ci, type, name);
1951 if (found) {
1952 return NULL;
1953 }
1954
1955 cd = cf_data_alloc(ci, data, type, name, do_free);
1956 if (!cd) {
1957 cf_log_err(ci, "Failed allocating data");
1958 return NULL;
1959 }
1960 cd->is_talloced = true;
1961 cf_filename_set(cd, filename);
1962 cf_lineno_set(cd, lineno);
1963
1964 return cd;
1965}
1966
1967/** Add non-talloced user data to a config section
1968 *
1969 * @param[in] ci to add data to.
1970 * @param[in] data to add.
1971 * @param[in] type identifier of the user data.
1972 * @param[in] name String identifier of the user data.
1973 * @param[in] filename Source file the #CONF_DATA was added in.
1974 * @param[in] lineno the #CONF_DATA was added at.
1975 * - #CONF_DATA - opaque handle to the stored data - on success.
1976 * - NULL error.
1977 */
1978CONF_DATA const *_cf_data_add_static(CONF_ITEM *ci, void const *data, char const *type, char const *name,
1979 char const *filename, int lineno)
1980{
1981 CONF_DATA *cd;
1982 CONF_DATA const *found;
1983
1984 /*
1985 * Already exists. Can't add it.
1986 */
1987 found = _cf_data_find(ci, type, name);
1988 if (found) {
1989 /*
1990 * Suppress these, as it's OK for the conf_parser_t in main_config.c
1991 */
1992 if (strcmp(type, "conf_parser_t") == 0) return NULL;
1993
1994 cf_log_err(ci, "Data of type %s with name \"%s\" already exists. Existing data added %s[%i]", type,
1995 name, found->item.filename, found->item.lineno);
1996 return NULL;
1997 }
1998
1999 cd = cf_data_alloc(ci, data, type, name, false);
2000 if (!cd) {
2001 cf_log_err(ci, "Failed allocating data");
2002 return NULL;
2003 }
2004 cd->is_talloced = false;
2005 cf_filename_set(cd, filename);
2006 cf_lineno_set(cd, lineno);
2007
2008 return cd;
2009}
2010
2011/** Remove data from a configuration section
2012 *
2013 * @note If cd was not found it will not be freed, and it is the caller's responsibility
2014 * to free it explicitly, or free the section it belongs to.
2015 *
2016 * @param[in] parent to remove data from.
2017 * @param[in] cd opaque handle of the stored data.
2018 * @return
2019 * - The value stored within the data (if cd is valid and was found and removed).
2020 * - NULL if not found.
2021 */
2023{
2024 void *data;
2025
2026 if (!cd) return NULL;
2027
2028 (void)cf_item_remove(parent, cd);
2029
2030 talloc_set_destructor(cd, NULL); /* Disarm the destructor */
2031 memcpy(&data, &cd->data, sizeof(data));
2033
2034 return data;
2035}
2036
2037/** Walk over a specific type of CONF_DATA
2038 *
2039 * @param[in] ci containing the CONF_DATA to walk over.
2040 * @param[in] type of CONF_DATA to walk over.
2041 * @param[in] cb to call when we find CONF_DATA of the specified type.
2042 * @param[in] ctx to pass to cb.
2043 * @return
2044 * - 0 on success.
2045 * - -1 on failure.
2046 */
2047int _cf_data_walk(CONF_ITEM *ci, char const *type, cf_walker_t cb, void *ctx)
2048{
2049 CONF_DATA *cd;
2050 CONF_ITEM *item;
2051 fr_rb_tree_t *tree;
2053 int ret = 0;
2054
2055 if (!ci->ident2) return 0;
2056
2057 tree = ci->ident2;
2058
2059 for (item = fr_rb_iter_init_inorder(tree, &iter);
2060 item;
2061 item = fr_rb_iter_next_inorder(tree, &iter)) {
2062 /*
2063 * We're walking ident2, not all of the items will be data
2064 */
2065 if (item->type != CONF_ITEM_DATA) continue;
2066
2067 cd = (void *) item;
2068 if ((cd->type != type) && (strcmp(cd->type, type) != 0)) continue;
2069
2070 ret = cb(UNCONST(void *, cd->data), ctx);
2071 if (ret) {
2072 break;
2073 }
2074 }
2075
2076 return ret;
2077}
2078
2079static inline CC_HINT(nonnull) void truncate_filename(char const **e, char const **p, int *len, char const *filename)
2080{
2081 size_t flen;
2082 char const *q;
2083
2084 #define FILENAME_TRUNCATE 60
2085
2086 *p = filename;
2087 *e = "";
2088
2089 flen = talloc_strlen(filename);
2090 if (flen <= FILENAME_TRUNCATE) {
2091 *len = (int)flen;
2092 return;
2093 }
2094
2095 *p += flen - FILENAME_TRUNCATE;
2096 *len = FILENAME_TRUNCATE;
2097
2098 q = strchr(*p, FR_DIR_SEP);
2099 if (q) {
2100 q++;
2101 *len -= (q - *p);
2102 *p += (q - *p);
2103 }
2104
2105 *e = "...";
2106}
2107
2108/** Check to see if the CONF_PAIR value is present in the specified table
2109 *
2110 * If it's not present, return an error and produce a helpful log message
2111 *
2112 * @param[out] out The result of parsing the pair value.
2113 * @param[in] table to look for string values in.
2114 * @param[in] table_len Length of the table.
2115 * @param[in] cp to parse.
2116 * @return
2117 * - 0 on success.
2118 * - -1 on failure.
2119 */
2120int cf_pair_in_table(int32_t *out, fr_table_num_sorted_t const *table, size_t table_len, CONF_PAIR *cp)
2121{
2122 char *list = NULL;
2123 int32_t res;
2124 size_t i;
2125
2127 if (res != FR_TABLE_NOT_FOUND) {
2128 *out = res;
2129 return 0;
2130 }
2131
2132 for (i = 0; i < table_len; i++) MEM(list = talloc_asprintf_append_buffer(list, "'%s', ", table[i].name.str));
2133
2134 if (!list) {
2135 cf_log_err(cp, "Internal error parsing %s: Table was empty", cf_pair_attr(cp));
2136 return -1;
2137 }
2138
2139 /*
2140 * Trim the final ", "
2141 */
2142 MEM(list = talloc_bstr_realloc(NULL, list, talloc_array_length(list) - 2));
2143
2144 cf_log_err(cp, "Invalid value \"%s\". Expected one of %s", cf_pair_value(cp), list);
2145
2146 talloc_free(list);
2147
2148 return -1;
2149}
2150
2151/** Log an error message relating to a #CONF_ITEM
2152 *
2153 * @param[in] type of log message.
2154 * @param[in] ci #CONF_ITEM to print file/lineno for.
2155 * @param[in] file src file the log message was generated in.
2156 * @param[in] line number the log message was generated on.
2157 * @param[in] fmt of the message.
2158 * @param[in] ap Message args.
2159 */
2160void _cf_vlog(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, va_list ap)
2161{
2162 va_list aq;
2163
2164 if ((type == L_DBG) && !DEBUG_ENABLED) return;
2165
2166 if (!ci || !ci->filename || !*ci->filename || (*ci->filename == '<') ||
2167 (((type == L_DBG) || (type == L_INFO)) && !DEBUG_ENABLED4)) {
2168 va_copy(aq, ap);
2170 va_end(aq);
2171 return;
2172 }
2173
2174 {
2175 char const *e, *p;
2176 int len;
2177 char *msg;
2178
2179 truncate_filename(&e, &p, &len, ci->filename);
2180
2181 va_copy(aq, ap);
2182 msg = fr_vasprintf(NULL, fmt, aq);
2183 va_end(aq);
2184
2185 fr_log(LOG_DST, type, file, line, "%s%.*s[%d]: %s", e, len, p, ci->lineno, msg);
2187 }
2188}
2189
2190/** Log an error message relating to a #CONF_ITEM
2191 *
2192 * @param[in] type of log message.
2193 * @param[in] file src file the log message was generated in.
2194 * @param[in] line number the log message was generated on.
2195 * @param[in] ci #CONF_ITEM to print file/lineno for.
2196 * @param[in] fmt of the message.
2197 * @param[in] ... Message args.
2198 */
2199void _cf_log(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, ...)
2200{
2201 va_list ap;
2202
2203 if ((type == L_DBG) && !DEBUG_ENABLED) return;
2204
2205 va_start(ap, fmt);
2206 _cf_vlog(type, ci, file, line, fmt, ap);
2207 va_end(ap);
2208}
2209
2210/** Log an error message relating to a #CONF_ITEM
2211 *
2212 * Drains the fr_strerror() stack emitting one or more error messages.
2213 *
2214 * @param[in] type of log message.
2215 * @param[in] file src file the log message was generated in.
2216 * @param[in] line number the log message was generated on.
2217 * @param[in] ci #CONF_ITEM to print file/lineno for.
2218 * @param[in] f_rules Additional optional formatting controls.
2219 * @param[in] fmt of the message.
2220 * @param[in] ap Message args.
2221 */
2222void _cf_vlog_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line,
2223 fr_log_perror_format_t const *f_rules, char const *fmt, va_list ap)
2224{
2225 va_list aq;
2226
2227 if ((type == L_DBG) && !DEBUG_ENABLED) return;
2228
2229 if (!ci || !ci->filename) {
2230 va_copy(aq, ap);
2231 fr_vlog_perror(LOG_DST, type, file, line, f_rules, fmt, aq);
2232 va_end(aq);
2233 return;
2234 }
2235
2236 {
2237 char const *e, *p;
2238 int len;
2239 char *prefix;
2240 TALLOC_CTX *thread_log_pool;
2241 TALLOC_CTX *pool;
2242 fr_log_perror_format_t our_f_rules;
2243
2244 if (f_rules) {
2245 our_f_rules = *f_rules;
2246 } else {
2247 our_f_rules = (fr_log_perror_format_t){};
2248 }
2249
2250 /*
2251 * Get some scratch space from the logging code
2252 */
2253 thread_log_pool = fr_log_pool_init();
2254 pool = talloc_new(thread_log_pool);
2255
2256 truncate_filename(&e, &p, &len, ci->filename);
2257
2258 /*
2259 * Create the file location string
2260 */
2261 prefix = fr_asprintf(pool, "%s%.*s[%d]: ", e, len, p, ci->lineno);
2262
2263 /*
2264 * Prepend it to an existing first prefix
2265 */
2266 if (f_rules && f_rules->first_prefix) {
2267 char *first;
2268
2269 first = talloc_bstrdup(pool, prefix);
2270 MEM(talloc_strndup_append_buffer(first, f_rules->first_prefix, SIZE_MAX));
2271
2272 our_f_rules.first_prefix = first;
2273 } else {
2274 our_f_rules.first_prefix = prefix;
2275 }
2276
2277 /*
2278 * Prepend it to an existing subsq prefix
2279 */
2280 if (f_rules && f_rules->subsq_prefix) {
2281 char *subsq;
2282
2283 subsq = talloc_bstrdup(pool, prefix);
2284 MEM(talloc_strndup_append_buffer(subsq, f_rules->subsq_prefix, SIZE_MAX));
2285
2286 our_f_rules.subsq_prefix = subsq;
2287 } else {
2288 our_f_rules.subsq_prefix = prefix;
2289 }
2290
2291 va_copy(aq, ap);
2292 fr_vlog_perror(LOG_DST, type, file, line, &our_f_rules, fmt, aq);
2293 va_end(aq);
2294
2295 talloc_free(pool);
2296 }
2297}
2298
2299/** Log an error message relating to a #CONF_ITEM
2300 *
2301 * Drains the fr_strerror() stack emitting one or more error messages.
2302 *
2303 * @param[in] type of log message.
2304 * @param[in] file src file the log message was generated in.
2305 * @param[in] line number the log message was generated on.
2306 * @param[in] ci #CONF_ITEM to print file/lineno for.
2307 * @param[in] f_rules Additional optional formatting controls.
2308 * @param[in] fmt of the message.
2309 * @param[in] ... Message args.
2310 */
2311void _cf_log_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line,
2312 fr_log_perror_format_t const *f_rules, char const *fmt, ...)
2313{
2314 va_list ap;
2315
2316 if ((type == L_DBG) && !DEBUG_ENABLED) return;
2317
2318 va_start(ap, fmt);
2319 _cf_vlog_perr(type, ci, file, line, f_rules, fmt, ap);
2320 va_end(ap);
2321}
2322
2323/** Log a debug message relating to a #CONF_ITEM
2324 *
2325 * Always emits a filename/lineno prefix if available
2326 *
2327 * @param[in] type of log message.
2328 * @param[in] file src file the log message was generated in.
2329 * @param[in] line number the log message was generated on.
2330 * @param[in] ci #CONF_ITEM to print file/lineno for.
2331 * @param[in] fmt of the message.
2332 * @param[in] ... Message args.
2333 */
2334void _cf_log_with_filename(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, ...)
2335{
2336 va_list ap;
2337
2338 if ((type == L_DBG) && !DEBUG_ENABLED) return;
2339
2340 if (!ci || !ci->filename) {
2341 va_start(ap, fmt);
2342 fr_vlog(LOG_DST, type, file, line, fmt, ap);
2343 va_end(ap);
2344 return;
2345 }
2346
2347 {
2348 char const *e, *p;
2349 int len;
2350 char *msg;
2351
2352 truncate_filename(&e, &p, &len, ci->filename);
2353
2354 va_start(ap, fmt);
2355 msg = fr_vasprintf(NULL, fmt, ap);
2356 va_end(ap);
2357
2358 fr_log(LOG_DST, type, file, line, "%s%.*s[%d]: %s", e, len, p, ci->lineno, msg);
2360 }
2361}
2362
2363/** Log an error message in the context of a child pair of the specified parent
2364 *
2365 * @param[in] parent containing the pair.
2366 * @param[in] child name to use as a logging context.
2367 * @param[in] type of log message.
2368 * @param[in] file src file the log message was generated in.
2369 * @param[in] line number the log message was generated on.
2370 * @param[in] fmt of the message.
2371 * @param[in] ... Message args.
2372 */
2374 char const *file, int line, char const *fmt, ...)
2375{
2376 va_list ap;
2377 CONF_PAIR const *cp;
2378
2379 cp = cf_pair_find(parent, child);
2380 if (cp) {
2381 va_start(ap, fmt);
2382 _cf_vlog(type, CF_TO_ITEM(cp), file, line, fmt, ap);
2383 va_end(ap);
2384 return;
2385 }
2386
2387 va_start(ap, fmt);
2389 va_end(ap);
2390}
2391
2392
2393/** Log an error message in the context of a child pair of the specified parent
2394 *
2395 * @param[in] parent containing the pair.
2396 * @param[in] child name to use as a logging context.
2397 * @param[in] type of log message.
2398 * @param[in] file src file the log message was generated in.
2399 * @param[in] line number the log message was generated on.
2400 * @param[in] f_rules Line prefixes.
2401 * @param[in] fmt of the message.
2402 * @param[in] ... Message args.
2403 */
2405 char const *file, int line, fr_log_perror_format_t const *f_rules,
2406 char const *fmt, ...)
2407{
2408 va_list ap;
2409 CONF_PAIR const *cp;
2410
2411 cp = cf_pair_find(parent, child);
2412 if (cp) {
2413 va_start(ap, fmt);
2414 _cf_vlog_perr(type, CF_TO_ITEM(cp), file, line, f_rules, fmt, ap);
2415 va_end(ap);
2416 return;
2417 }
2418
2419 va_start(ap, fmt);
2420 _cf_vlog_perr(type, CF_TO_ITEM(parent), file, line, f_rules, fmt, ap);
2421 va_end(ap);
2422}
2423
2424/** Print out debugging information about a CONFIG_ITEM
2425 *
2426 * @param[in] ci being debugged.
2427 */
2429{
2430 /*
2431 * Print summary of the item
2432 */
2433 switch (ci->type) {
2434 case CONF_ITEM_SECTION:
2435 {
2436 CONF_SECTION const *cs = cf_item_to_section(ci);
2437 int i;
2438
2439 DEBUG("SECTION - %p", cs);
2440 DEBUG(" name1 : %s", cs->name1);
2441 DEBUG(" name2 : %s", cs->name2 ? cs->name2 : "<none>");
2442 DEBUG(" name2_quote : %s", fr_table_str_by_value(fr_token_quotes_table, cs->name2_quote, "<INVALID>"));
2443 DEBUG(" argc : %d", cs->argc);
2444
2445 for (i = 0; i < cs->argc; i++) {
2446 char const *quote = fr_table_str_by_value(fr_token_quotes_table, cs->argv_quote[i], "<INVALID>");
2447 DEBUG(" argv[%i] : %s%s%s", i, quote, cs->argv[i], quote);
2448 }
2449 }
2450 break;
2451
2452 case CONF_ITEM_PAIR:
2453 {
2454 CONF_PAIR const *cp = cf_item_to_pair(ci);
2455
2456 DEBUG("PAIR - %p", cp);
2457 DEBUG(" attr : %s", cp->attr);
2458 DEBUG(" value : %s", cp->value);
2459 DEBUG(" operator : %s", fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"));
2460 DEBUG(" lhs_quote : %s", fr_table_str_by_value(fr_token_quotes_table, cp->lhs_quote, "<INVALID>"));
2461 DEBUG(" rhs_quote : %s", fr_table_str_by_value(fr_token_quotes_table, cp->rhs_quote, "<INVALID>"));
2462 DEBUG(" pass2 : %s", cp->pass2 ? "yes" : "no");
2463 DEBUG(" parsed : %s", cp->item.parsed ? "yes" : "no");
2464 }
2465 break;
2466
2467 case CONF_ITEM_DATA:
2468 {
2469 CONF_DATA const *cd = cf_item_to_data(ci);
2470
2471 DEBUG("DATA - %p", cd);
2472 DEBUG(" type : %s", cd->type);
2473 DEBUG(" name : %s", cd->name);
2474 DEBUG(" data : %p", cd->data);
2475 }
2476 break;
2477
2478 default:
2479 DEBUG("INVALID - %p", ci);
2480 return;
2481 }
2482
2483 DEBUG(" filename : %s", ci->filename);
2484 DEBUG(" line : %i", ci->lineno);
2485 if (ci->parent) DEBUG(" next : %p", fr_dlist_next(&ci->parent->children, ci));
2486 DEBUG(" parent : %p", ci->parent);
2487 DEBUG(" children : %s", cf_item_has_no_children(ci) ? "no" : "yes");
2488 DEBUG(" ident1 tree : %p (%u entries)", ci->ident1, ci->ident1 ? fr_rb_num_elements(ci->ident1) : 0);
2489 DEBUG(" ident2 tree : %p (%u entries)", ci->ident2, ci->ident2 ? fr_rb_num_elements(ci->ident2) : 0);
2490
2491 if (cf_item_has_no_children(ci)) return;
2492
2493 /*
2494 * Print summary of the item's children
2495 */
2496 DEBUG("CHILDREN");
2497
2498 cf_item_foreach(ci, child) {
2499 char const *in_ident1, *in_ident2;
2500
2501 in_ident1 = fr_rb_find(ci->ident1, child) == child? "in ident1 " : "";
2502
2503 if (ci->type != CONF_ITEM_SECTION) {
2504 in_ident2 = NULL;
2505 } else {
2506 in_ident2 = fr_rb_find(ci->ident2, child) == child? "in ident2 " : "";
2507 }
2508
2509 switch (child->type) {
2510 case CONF_ITEM_SECTION:
2511 {
2512 CONF_SECTION const *cs = cf_item_to_section(child);
2513
2514 DEBUG(" SECTION %p (%s %s) %s%s", child, cs->name1, cs->name2 ? cs->name2 : "<none>",
2515 in_ident1, in_ident2);
2516 }
2517 break;
2518
2519 case CONF_ITEM_PAIR:
2520 {
2521 CONF_PAIR const *cp = cf_item_to_pair(child);
2522 char const *lhs_quote = fr_table_str_by_value(fr_token_quotes_table, cp->lhs_quote, "<INVALID>");
2523 char const *rhs_quote = fr_table_str_by_value(fr_token_quotes_table, cp->rhs_quote, "<INVALID>");
2524
2525 DEBUG(" PAIR %p (%s%s%s %s %s%s%s) %s%s", child,
2526 lhs_quote, cp->attr, lhs_quote,
2527 fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"),
2528 rhs_quote, cp->value, rhs_quote,
2529 in_ident1, in_ident2);
2530 }
2531 break;
2532
2533 case CONF_ITEM_DATA:
2534 {
2535 CONF_DATA const *cd = cf_item_to_data(child);
2536
2537 DEBUG(" DATA %p (%s *)%s = %p %s%s", child,
2538 cd->type, cd->name ? cd->name : "", cd->data,
2539 in_ident1, in_ident2);
2540 break;
2541 }
2542
2543 default:
2544 DEBUG(" INVALID - %p", child);
2545 break;
2546 }
2547 }
2548}
2549
2550/** Ease of use from debugger
2551 */
2553{
2554 cf_item_debug(cp);
2555}
2556
2557/** Ease of use from debugger
2558 */
2560{
2561 cf_item_debug(cs);
2562}
2563
2564/*
2565 * Used when we don't need the children any more, as with
2566 *
2567 * if (0) { ... }
2568 */
2570{
2571 CONF_ITEM *child;
2572
2573 while ((child = cf_item_next(ci, NULL)) != NULL) {
2574 _cf_item_remove(ci, child);
2575 }
2576}
2577
2578void _cf_canonicalize_error(CONF_ITEM *ci, ssize_t slen, char const *msg, char const *str)
2579{
2580 char *spaces, *text;
2581
2582 fr_canonicalize_error(ci, &spaces, &text, slen, str);
2583
2584 cf_log_err(ci, "%s", msg);
2585 cf_log_err(ci, "%s", text);
2586 cf_log_perr(ci, "%s^", spaces);
2587
2589 talloc_free(text);
2590}
2591
2592/*
2593 * Create or find a CONF_PAIR, including parents.
2594 *
2595 * This is only used by the command-line argument '-S foo.bar=baz'
2596 */
2597int cf_pair_replace_or_add(CONF_SECTION *cs, char const *ref, char const *value)
2598{
2599 char *name2;
2600 CONF_PAIR *cp;
2601 char buffer[256];
2602
2603 while (*ref) {
2604 char *p;
2605 CONF_SECTION *subcs;
2606
2607 p = strchr(ref, '.');
2608 if (!p) break;
2609
2610 p++;
2611 if (*p == '[') {
2612 size_t len;
2613
2614 name2 = p + 1;
2615 p = strchr(name2, ']'); /* doesn't support nesting, too bad */
2616 if (!p) {
2617 fr_strerror_printf("Missing ']' after %s", name2);
2618 return -1;
2619 }
2620
2621 len = (size_t) (p - name2);
2622 if (len >= sizeof(buffer)) {
2623 fr_strerror_printf("Reference in '[...]' is too long after %s", name2);
2624 return -1;
2625 }
2626 memcpy(buffer, name2, len);
2627 buffer[len] = '\0';
2628 name2 = buffer;
2629
2630 } else {
2631 name2 = NULL;
2632 }
2633
2634 subcs = cf_section_find(cs, ref, name2);
2635 if (!subcs) {
2636 subcs = cf_section_alloc(cs, cs, ref, name2);
2637 if (!subcs) return -1;
2638 }
2639
2640 cs = subcs;
2641 ref = p;
2642 }
2643
2644 cp = cf_pair_find(cs, ref);
2645 if (cp) return cf_pair_replace(cs, cp, value);
2646
2648 if (!cp) return -1;
2649
2650 return 0;
2651}
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 UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:512
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:122
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
char const * cf_expand_variables(char const *cf, int lineno, CONF_SECTION *outer_cs, char *output, size_t outsize, char const *input, ssize_t inlen, bool *soft_fail, bool soft_fail_env)
Definition cf_file.c:297
int _cf_section_rule_push(CONF_SECTION *cs, conf_parser_t const *rule, char const *filename, int lineno)
Add a single rule to a CONF_SECTION.
Definition cf_parse.c:1587
conf_parser_flags_t flags
Flags which control parsing behaviour.
Definition cf_parse.h:612
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:701
char const * name1
Name of the CONF_ITEM to parse.
Definition cf_parse.h:607
cf_parse_t on_read
Function to call as the item is being read, just after it has been allocated and initialized.
Definition cf_parse.h:626
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:423
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:606
fr_rb_node_t ident2_node
Entry in the ident2 tree.
Definition cf_priv.h:56
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:107
CONF_ITEM * parent
Parent.
Definition cf_priv.h:61
fr_token_t name2_quote
The type of quoting around name2.
Definition cf_priv.h:112
void * base
Definition cf_priv.h:118
char const * name2
Second name token. Given foo bar {} would be bar.
Definition cf_priv.h:110
int argc
number of additional arguments
Definition cf_priv.h:114
char const * attr
Attribute name.
Definition cf_priv.h:80
char const * name
Additional qualification of type.
Definition cf_priv.h:160
#define cf_item_foreach_prev(_ci, _iter, _prev)
Iterate over the contents of a list in reverse order.
Definition cf_priv.h:191
bool referenced
Was this item referenced in the config?
Definition cf_priv.h:69
fr_rb_tree_t * ident2
Tree to store the second identifier (name2 || name).
Definition cf_priv.h:64
fr_token_t rhs_quote
Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition cf_priv.h:85
bool parsed
Was this item used during parsing?
Definition cf_priv.h:68
int depth
Definition cf_priv.h:119
char const * value
Attribute value.
Definition cf_priv.h:81
char const * name1
First name token. Given foo bar {} would be foo.
Definition cf_priv.h:109
void const * data
User data.
Definition cf_priv.h:162
static bool cf_item_has_no_children(CONF_ITEM const *ci)
Check if the CONF_ITEM has no children.
Definition cf_priv.h:201
fr_dlist_head_t children
The head of the ordered list of children.
Definition cf_priv.h:59
fr_token_t * argv_quote
Definition cf_priv.h:116
fr_token_t op
Operator e.g. =, :=.
Definition cf_priv.h:83
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:78
bool pass2
do expansion in pass2.
Definition cf_priv.h:87
char const * filename
The file the config item was parsed from.
Definition cf_priv.h:71
fr_rb_tree_t * ident1
Tree to store the first identifier (name1 || type || attr).
Definition cf_priv.h:63
bool is_talloced
If true we can do extra checks.
Definition cf_priv.h:163
CONF_SECTION * template
Definition cf_priv.h:124
fr_rb_node_t ident1_node
Entry in the ident1 tree.
Definition cf_priv.h:55
char const * text
Comment text, with the leading # and any surrounding whitespace stripped.
Definition cf_priv.h:149
#define cf_item_foreach_next(_ci, _iter, _prev)
Iterate over the contents of a list.
Definition cf_priv.h:181
@ CONF_ITEM_INVALID
Definition cf_priv.h:40
@ CONF_ITEM_PAIR
Definition cf_priv.h:41
@ CONF_ITEM_DATA
Definition cf_priv.h:43
@ CONF_ITEM_SECTION
Definition cf_priv.h:42
@ CONF_ITEM_COMMENT
A # ... line preserved verbatim from the input - only created when the parser is asked to keep commen...
Definition cf_priv.h:44
enum conf_type CONF_ITEM_TYPE
char const ** argv
additional arguments
Definition cf_priv.h:115
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:147
char const * type
C type of data being stored.
Definition cf_priv.h:159
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:157
fr_token_t lhs_quote
Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition cf_priv.h:84
int lineno
The line number the config item began on.
Definition cf_priv.h:70
CONF_ITEM_TYPE type
Whether the config item is a config_pair, conf_section or cf_data.
Definition cf_priv.h:66
A # ... comment line preserved verbatim from the input.
Definition cf_priv.h:146
Internal data that is associated with a configuration section.
Definition cf_priv.h:156
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:640
static void cf_item_init(CONF_ITEM *ci, CONF_ITEM_TYPE type, CONF_ITEM *parent, char const *filename, int lineno)
Initialize a CONF_ITEM, so we don't have repeated code.
Definition cf_util.c:548
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1782
void * _cf_data_remove(CONF_ITEM *parent, CONF_DATA const *cd)
Remove data from a configuration section.
Definition cf_util.c:2022
CONF_SECTION * _cf_section_find_parent(CONF_ITEM const *ci, char const *name1, char const *name2)
Find a parent CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1269
int _cf_data_walk(CONF_ITEM *ci, char const *type, cf_walker_t cb, void *ctx)
Walk over a specific type of CONF_DATA.
Definition cf_util.c:2047
unsigned int cf_pair_count_descendents(CONF_SECTION const *cs)
Count the number of conf pairs beneath a section.
Definition cf_util.c:1660
void _cf_item_mark_parsed(CONF_ITEM *ci)
Mark an item as parsed.
Definition cf_util.c:1531
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition cf_util.c:1608
void cf_section_debug(CONF_SECTION *cs)
Ease of use from debugger.
Definition cf_util.c:2559
CONF_DATA * _cf_data_find_in_parent(CONF_ITEM const *ci, char const *type, char const *name)
Find matching data in the specified section or one of its parents.
Definition cf_util.c:1894
static bool cf_preserve_comments
Definition cf_util.c:805
CONF_ITEM * cf_data_to_item(CONF_DATA const *cd)
Cast CONF_DATA to a CONF_ITEM.
Definition cf_util.c:762
CONF_ITEM * _cf_item_remove(CONF_ITEM *parent, CONF_ITEM *child)
Remove item from parent and fixup trees.
Definition cf_util.c:455
CONF_DATA const * _cf_data_find(CONF_ITEM const *ci, char const *type, char const *name)
Find user data in a config section.
Definition cf_util.c:1860
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
Return the quoting for one of the variadic arguments.
Definition cf_util.c:1422
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
Count the number of times an attribute occurs in a parent section.
Definition cf_util.c:1675
int cf_pair_in_table(int32_t *out, fr_table_num_sorted_t const *table, size_t table_len, CONF_PAIR *cp)
Check to see if the CONF_PAIR value is present in the specified table.
Definition cf_util.c:2120
int cf_pair_replace_or_add(CONF_SECTION *cs, char const *ref, char const *value)
Definition cf_util.c:2597
CONF_PAIR * cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp, bool copy_meta)
Duplicate a CONF_PAIR.
Definition cf_util.c:1483
void _cf_item_insert_after(CONF_ITEM *parent, CONF_ITEM *prev, CONF_ITEM *child)
Insert a child after a given one.
Definition cf_util.c:417
static int8_t _cf_ident1_cmp(void const *a, void const *b)
Compare the first identifier of a child.
Definition cf_util.c:268
#define FILENAME_TRUNCATE
static CONF_DATA * cf_data_alloc(CONF_ITEM *parent, void const *data, char const *type, char const *name, bool do_free)
Allocate a new user data container.
Definition cf_util.c:1823
fr_slen_t cf_pair_values_concat(fr_sbuff_t *out, CONF_SECTION const *cs, char const *attr, char const *sep)
Concatenate the values of any pairs with name attr.
Definition cf_util.c:1695
void cf_item_free_children(CONF_ITEM *ci)
Definition cf_util.c:2569
CONF_ITEM * cf_comment_to_item(CONF_COMMENT const *c)
Cast a CONF_COMMENT back to a CONF_ITEM.
Definition cf_util.c:788
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1359
int8_t cf_section_name_cmp(CONF_SECTION const *cs, char const *name1, char const *name2)
Check if a given section matches the specified name1/name2 identifiers.
Definition cf_util.c:1312
void _cf_log(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt,...)
Log an error message relating to a CONF_ITEM.
Definition cf_util.c:2199
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1913
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:746
static int8_t _cf_ident2_cmp(void const *a, void const *b)
Compare the first and second identifiers of a child.
Definition cf_util.c:375
static int8_t cf_ident2_cmp(void const *a, void const *b)
Compare only the second identifier of a child.
Definition cf_util.c:325
CONF_ITEM * _cf_parent(CONF_ITEM const *ci)
Return the parent of a CONF_ITEM.
Definition cf_util.c:584
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1441
void _cf_vlog_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, fr_log_perror_format_t const *f_rules, char const *fmt, va_list ap)
Log an error message relating to a CONF_ITEM.
Definition cf_util.c:2222
CONF_SECTION * cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the next child that's a CONF_SECTION.
Definition cf_util.c:1170
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1345
CONF_SECTION * _cf_section_alloc(TALLOC_CTX *ctx, CONF_SECTION *parent, char const *name1, char const *name2, char const *filename, int lineno)
Allocate a CONF_SECTION.
Definition cf_util.c:891
CONF_ITEM * _cf_item_next(CONF_ITEM const *parent, CONF_ITEM const *curr)
Return the next child of the CONF_ITEM.
Definition cf_util.c:518
static void _pair_count(int *count, CONF_SECTION const *cs)
Callback to determine the number of pairs in a section.
Definition cf_util.c:1641
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1201
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:692
CONF_ITEM * _cf_item_prev(CONF_ITEM const *ci, CONF_ITEM const *curr)
Return the next child of cs.
Definition cf_util.c:533
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1594
CONF_DATA * cf_item_to_data(CONF_ITEM const *ci)
Cast CONF_ITEM to CONF_DATA performing a type check.
Definition cf_util.c:712
void _cf_filename_set(CONF_ITEM *ci, char const *filename)
Set the filename of a CONF_ITEM.
Definition cf_util.c:998
char const * cf_section_value_find(CONF_SECTION const *cs, char const *attr)
Find a pair in a CONF_SECTION.
Definition cf_util.c:1293
bool cf_item_is_comment(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_COMMENT.
Definition cf_util.c:771
CONF_SECTION * _cf_root(CONF_ITEM const *ci)
Return the top level CONF_SECTION holding all other CONF_ITEM.
Definition cf_util.c:566
CONF_COMMENT * cf_comment_alloc(CONF_SECTION *parent, char const *text)
Allocate a new comment item attached to parent.
Definition cf_util.c:842
void _cf_lineno_set(CONF_ITEM *ci, int lineno)
Set the line number of a CONF_ITEM.
Definition cf_util.c:1010
void cf_preserve_comments_set(bool preserve)
Control whether the CF parser preserves # ... comments.
Definition cf_util.c:807
void _cf_log_by_child(fr_log_type_t type, CONF_SECTION const *parent, char const *child, char const *file, int line, char const *fmt,...)
Log an error message in the context of a child pair of the specified parent.
Definition cf_util.c:2373
void _cf_log_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, fr_log_perror_format_t const *f_rules, char const *fmt,...)
Log an error message relating to a CONF_ITEM.
Definition cf_util.c:2311
CONF_DATA const * _cf_data_add_static(CONF_ITEM *ci, void const *data, char const *type, char const *name, char const *filename, int lineno)
Add non-talloced user data to a config section.
Definition cf_util.c:1978
static int _cd_free(CONF_DATA *cd)
Free user data associated with CONF_DATA.
Definition cf_util.c:1807
void _cf_vlog(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, va_list ap)
Log an error message relating to a CONF_ITEM.
Definition cf_util.c:2160
void _cf_log_perr_by_child(fr_log_type_t type, CONF_SECTION const *parent, char const *child, char const *file, int line, fr_log_perror_format_t const *f_rules, char const *fmt,...)
Log an error message in the context of a child pair of the specified parent.
Definition cf_util.c:2404
CONF_COMMENT * cf_item_to_comment(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_COMMENT (asserts on type mismatch).
Definition cf_util.c:779
static CONF_ITEM * cf_next(CONF_ITEM const *parent, CONF_ITEM const *current, CONF_ITEM_TYPE type)
Return the next child that's of the specified type.
Definition cf_util.c:47
bool _cf_expand_variables(void)
Definition cf_util.c:837
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
Definition cf_util.c:1371
char const * _cf_filename(CONF_ITEM const *ci)
Return the filename the CONF_ITEM was parsed in.
Definition cf_util.c:612
bool _cf_preserve_comments(void)
Definition cf_util.c:817
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:654
bool _cf_item_is_parsed(CONF_ITEM *ci)
Return whether an item has already been parsed.
Definition cf_util.c:1543
void _cf_item_debug(CONF_ITEM const *ci)
Print out debugging information about a CONFIG_ITEM.
Definition cf_util.c:2428
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1767
#define IS_WILDCARD(_ident)
Definition cf_util.c:75
static CONF_ITEM * cf_prev(CONF_ITEM const *parent, CONF_ITEM const *current, CONF_ITEM_TYPE type)
Return the previous child that's of the specified type.
Definition cf_util.c:66
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1797
void _cf_log_with_filename(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt,...)
Log a debug message relating to a CONF_ITEM.
Definition cf_util.c:2334
CONF_PAIR * cf_pair_first(CONF_SECTION const *cs)
Return the first child that's a CONF_PAIR.
Definition cf_util.c:1555
static CONF_ITEM * cf_find(CONF_ITEM const *parent, CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
Return the next child that's of the specified type with the specified identifiers.
Definition cf_util.c:88
static void truncate_filename(char const **e, char const **p, int *len, char const *filename)
Definition cf_util.c:2079
CONF_PAIR * cf_pair_next(CONF_SECTION const *cs, CONF_PAIR const *curr)
Return the next child that's a CONF_PAIR.
Definition cf_util.c:1568
void _cf_canonicalize_error(CONF_ITEM *ci, ssize_t slen, char const *msg, char const *str)
Definition cf_util.c:2578
CONF_SECTION * _cf_section_find_in_parent(CONF_ITEM const *ci, char const *name1, char const *name2)
Find an ancestor of the passed CONF_ITEM which has a child matching a specific name1 and optionally n...
Definition cf_util.c:1245
CONF_DATA const * _cf_data_find_next(CONF_ITEM const *ci, CONF_ITEM const *prev, char const *type, char const *name)
Return the next item of user data.
Definition cf_util.c:1878
static CONF_ITEM * cf_find_next(CONF_ITEM const *parent, CONF_ITEM const *prev, CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
Return the next child that's of the specified type with the specified identifiers.
Definition cf_util.c:182
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:626
static bool cf_expand_vars
Definition cf_util.c:830
char const * cf_comment_text(CONF_COMMENT const *c)
Definition cf_util.c:794
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
Definition cf_util.c:1032
CONF_PAIR * cf_pair_find_in_parent(CONF_SECTION const *cs, char const *attr)
Find a pair with a name matching attr in the specified section or one of its parents.
Definition cf_util.c:1622
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
Definition cf_util.c:1387
CONF_PAIR * cf_pair_prev(CONF_SECTION const *cs, CONF_PAIR const *curr)
Return the previous child that's a CONF_PAIR.
Definition cf_util.c:1581
void cf_expand_variables_set(bool expand)
Opt out of ${var} expansion when reading config (default: enabled).
Definition cf_util.c:832
int _cf_lineno(CONF_ITEM const *ci)
Return the lineno the CONF_ITEM was parsed at.
Definition cf_util.c:598
static int _cf_section_free(CONF_SECTION *cs)
Free a section and associated trees.
Definition cf_util.c:870
CONF_SECTION * cf_section_first(CONF_SECTION const *cs)
Return the first child in a CONF_SECTION.
Definition cf_util.c:1157
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:672
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition cf_util.c:1222
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1404
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1753
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair value in a given section with the given value.
Definition cf_util.c:1515
void _cf_item_add(CONF_ITEM *parent, CONF_ITEM *child)
Add a child.
Definition cf_util.c:390
void cf_pair_debug(CONF_PAIR *cp)
Ease of use from debugger.
Definition cf_util.c:2552
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:730
CONF_SECTION * cf_section_prev(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the previous child that's a CONF_SECTION.
Definition cf_util.c:1183
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1737
CONF_DATA const * _cf_data_add(CONF_ITEM *ci, void const *data, char const *name, bool do_free, char const *filename, int lineno)
Add talloced user data to a config section.
Definition cf_util.c:1936
#define cf_item_add(_parent, _child)
Definition cf_util.h:85
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:345
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:300
#define cf_lineno_set(_ci, _lineno)
Definition cf_util.h:186
#define cf_parent(_cf)
Definition cf_util.h:118
#define cf_item_remove(_parent, _child)
Definition cf_util.h:91
#define cf_item_next(_parent, _curr)
Definition cf_util.h:94
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:352
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:201
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
Definition cf_util.h:65
#define cf_item_foreach(_parent, _iter)
Iterate over every child item of a CONF_SECTION (or any CONF_ITEM that has children).
Definition cf_util.h:109
#define cf_filename_set(_ci, _filename)
Definition cf_util.h:183
#define cf_item_debug(_cf)
Definition cf_util.h:417
int(* cf_walker_t)(void *data, void *ctx)
Definition cf_util.h:78
#define CF_IDENT_ANY
Definition cf_util.h:80
static fr_atomic_queue_t ** aq
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:208
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
Test enumeration values.
Definition dict_test.h:92
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:242
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
Definition dlist.h:570
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
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:537
static int fr_dlist_insert_after(fr_dlist_head_t *list_head, void *pos, void *ptr)
Insert an item after an item already in the list.
Definition dlist.h:396
talloc_free(hp)
#define LOG_DST
Definition network.c:29
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition log.h:260
#define DEBUG_ENABLED
True if global debug level 1 messages are enabled.
Definition log.h:257
TALLOC_CTX * fr_log_pool_init(void)
talloc ctx to use when composing log messages
Definition log.c:345
void fr_vlog_perror(fr_log_t const *log, fr_log_type_t type, char const *file, int line, fr_log_perror_format_t const *f_rules, char const *fmt, va_list ap)
Drain any outstanding messages from the fr_strerror buffers.
Definition log.c:647
void fr_vlog(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt, va_list ap)
Send a server log message to its destination.
Definition log.c:380
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition log.c:105
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:616
char const * first_prefix
Prefix for the first line printed.
Definition log.h:122
char const * subsq_prefix
Prefix for subsequent lines.
Definition log.h:123
fr_log_type_t
Definition log.h:51
@ L_INFO
Informational message.
Definition log.h:52
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:56
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:121
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
unsigned long int size_t
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
Definition print.c:860
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:883
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
static const char * spaces
Definition radict.c:177
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_remove_by_inline_node(fr_rb_tree_t *tree, fr_rb_node_t *node)
Remove an entry from the tree, using the node structure, without freeing the data.
Definition rb.c:722
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:269
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
The main red black tree structure.
Definition rb.h:71
static char const * name
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1469
ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff.
Definition sbuff.c:1634
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF(_sbuff_or_marker)
return count
Definition module.c:155
fr_aka_sim_id_type_t type
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
char * talloc_bstrdup(TALLOC_CTX *ctx, char const *in)
Binary safe strdup function.
Definition talloc.c:590
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
Definition talloc.c:682
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:288
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:236
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:33
fr_table_num_sorted_t const fr_token_quotes_table[]
Definition token.c:68
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:266
const bool fr_binary_op[T_TOKEN_LAST]
Definition token.c:284
enum fr_token fr_token_t
@ T_INVALID
Definition token.h:37
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
#define FR_TABLE_NOT_FOUND
Macro to use as dflt.
Definition token.h:135
static fr_slen_t parent
Definition pair.h:858
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_slen_t data
Definition value.h:1340
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030