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